Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – tendra.SVN – Blame – /branches/tendra5-amd64/src/utilities/make_tdf/lex.c – Rev 6

Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
6 7u83 2
 * Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
6 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
6 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
6 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
6 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
6 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
#include "config.h"
62
#include "tdf.h"
63
#include "cmd_ops.h"
64
#include "spec_ops.h"
65
#include "error.h"
66
#include "input.h"
67
#include "lex.h"
68
#include "syntax.h"
69
#include "xalloc.h"
70
 
71
 
72
/*
73
    INPUT FILE
74
 
75
    This is the file from which the lexical routine read their input.
76
*/
77
 
6 7u83 78
static FILE *lex_input;
2 7u83 79
 
80
 
81
/*
82
    PENDING BUFFER
83
 
84
    Pending characters are dealt with by means of this buffer.  pending
85
    is set to the start of the buffer to indicate that there are no
86
    characters pending, otherwise the pending characters are stored in
87
    the buffer.  The buffer may need increasing in size if the look-ahead
88
    required by the lexical analyser increases.
89
*/
90
 
6 7u83 91
static int pending_buff[12] = { '?' };
92
static int *pending = pending_buff;
2 7u83 93
 
94
 
95
/*
96
    MAPPINGS AND DECLARATIONS FOR AUTOMATICALLY GENERATED SECTION
97
 
98
    These macros give the mappings between the actions used in the
99
    automatically generated lexical analyser and the routines defined
100
    in this file.
101
*/
102
 
6 7u83 103
static int read_char(void);
104
static int read_comment(void);
105
static int read_identifier(int);
106
static int read_number(int);
2 7u83 107
 
6 7u83 108
#define get_comment(A)		read_comment()
109
#define get_identifier(A)	read_identifier((A))
110
#define get_number(A)		read_number((A))
111
#define unknown_token(A)	lex_unknown
112
#define unread_char(A)		*(++pending) = (A)
2 7u83 113
 
114
 
115
/*
116
    AUTOMATICALLY GENERATED SECTION
117
 
118
    The main body of the lexical analyser is automatically generated.
119
*/
120
 
121
#include "lexer.h"
122
 
123
 
124
/*
125
    GET THE NEXT CHARACTER
126
 
127
    This routine reads the next character, either from the pending buffer
128
    or from the input file.
129
*/
130
 
6 7u83 131
static int
132
read_char(void)
2 7u83 133
{
6 7u83 134
    int c;
135
    if (pending != pending_buff) {
136
	c = *(pending--);
2 7u83 137
    } else {
6 7u83 138
	c = fgetc(lex_input);
139
	if (c == '\n') crt_line_no++;
140
	if (c == EOF) return(LEX_EOF);
141
	c &= 0xff;
2 7u83 142
    }
6 7u83 143
    return(c);
2 7u83 144
}
145
 
146
 
147
/*
148
    TOKEN BUFFER
149
 
150
    This buffer is used by read_token to hold the values of identifiers.
151
    Similarly token_value is used to hold the values of numbers.
152
*/
153
 
6 7u83 154
char token_buff[2000];
155
static char *token_end = token_buff + sizeof(token_buff);
156
char *first_comment = NULL;
157
unsigned token_value = 0;
2 7u83 158
 
159
 
160
/*
161
    READ AN IDENTIFIER
162
 
163
    This routine reads an identifier beginning with a, returning the
164
    corresponding lexical token.  Keywords are dealt with locally.
165
*/
166
 
6 7u83 167
static int
168
read_identifier(int a)
2 7u83 169
{
6 7u83 170
    int c = a, cl;
171
    char *t = token_buff;
2 7u83 172
    do {
6 7u83 173
	*(t++) = (char)c;
174
	if (t == token_end) error(ERROR_FATAL, "Buffer overflow");
175
	c = read_char();
176
	cl = lookup_char(c);
177
    } while (is_alphanum(cl));
178
    *t = 0;
179
    unread_char(c);
2 7u83 180
 
181
    /* Deal with keywords */
6 7u83 182
    t = token_buff;
183
#define MAKE_KEYWORD(A, B)\
184
    if (streq(t,(A))) return(B);
2 7u83 185
#include "keyword.h"
6 7u83 186
    return(lex_name);
2 7u83 187
}
188
 
189
 
190
/*
191
    READ A NUMBER
192
 
193
    This routine reads a number.  It is entered after the initial digit,
194
    a, has been read.  The number's value is stored in token_value.
195
*/
196
 
6 7u83 197
static int
198
read_number(int a)
2 7u83 199
{
6 7u83 200
    int c = a, cl;
201
    unsigned n = 0;
2 7u83 202
    do {
6 7u83 203
	unsigned m = 10 * n + (unsigned)(c - '0');
204
	if (m < n) error(ERROR_SERIOUS, "Number overflow");
205
	n = m;
206
	c = read_char();
207
	cl = lookup_char(c);
208
    } while (is_digit(cl));
209
    unread_char(c);
210
    token_value = n;
211
    return(lex_number);
2 7u83 212
}
213
 
214
 
215
/*
216
    READ A COMMENT
217
 
218
    This routine reads a shell style comment.  It is entered after the
219
    initial hash character has been read.
220
*/
221
 
6 7u83 222
static int
223
read_comment(void)
2 7u83 224
{
6 7u83 225
    int c;
226
    char *t = token_buff;
2 7u83 227
    do {
6 7u83 228
	*(t++) = ' ';
229
	if (t == token_end) t = token_buff;
230
	*(t++) = '*';
231
	if (t == token_end) t = token_buff;
2 7u83 232
	do {
6 7u83 233
	    c = read_char();
234
	    if (c == LEX_EOF) {
235
		error(ERROR_SERIOUS, "End of file in comment");
236
		return(lex_eof);
2 7u83 237
	    }
6 7u83 238
	    *(t++) = (char)c;
239
	    if (t == token_end) t = token_buff;
240
	} while (c != '\n');
241
	c = read_char();
242
    } while (c == '#');
243
    unread_char(c);
244
    *t = 0;
245
    if (first_comment == 0) first_comment = xstrcpy(token_buff);
246
    return(read_token());
2 7u83 247
}
248
 
249
 
250
/*
251
    GET A COMMAND FROM A STRING
252
 
253
    This routine returns the address of the first non-white space character
254
    from the string ps.  It returns the null pointer if the end of the line
255
    is reached.
256
*/
257
 
6 7u83 258
static char *
259
get_command(char **ps)
2 7u83 260
{
6 7u83 261
    char *t = *ps;
262
    char *s = t;
263
    if (s) {
264
	char c;
265
	while (c = *s,(c == ' ' || c == '\t' || c == '\r')) {
266
	    *s = 0;
267
	    s++;
2 7u83 268
	}
6 7u83 269
	if (c == '#' || c == '\n' || c == 0) {
270
	    *s = 0;
271
	    *ps = NULL;
272
	    return(NULL);
2 7u83 273
	}
6 7u83 274
	t = s;
275
	while (c = *s, !(c == ' ' || c == '\t' || c == '\r' ||
276
			   c == '\n' || c == 0)) {
277
	    s++;
2 7u83 278
	}
6 7u83 279
	*ps = s;
2 7u83 280
    }
6 7u83 281
    return(t);
2 7u83 282
}
283
 
284
 
285
/*
286
    READ A TEMPLATE FILE
287
 
288
    This routine reads a template file from the current input file.
289
*/
290
 
6 7u83 291
COMMAND
292
read_template(COMMAND p)
2 7u83 293
{
6 7u83 294
    int go = 1;
295
    char buff[1000];
296
    FILE *f = lex_input;
297
    int ln1 = crt_line_no;
298
    LIST(COMMAND)q = NULL_list(COMMAND);
2 7u83 299
    do {
6 7u83 300
	COMMAND r = NULL_cmd;
301
	int ln2 = crt_line_no;
302
	char *s = fgets(buff, 1000, f);
303
	if (s == NULL) {
2 7u83 304
	    /* End of file */
6 7u83 305
	    if (IS_cmd_cond(p)) {
306
		error(ERROR_SERIOUS, "End of '@if' expected");
307
	    } else if (IS_cmd_loop(p)) {
308
		error(ERROR_SERIOUS, "End of '@loop' expected");
2 7u83 309
	    }
6 7u83 310
	    break;
2 7u83 311
	}
6 7u83 312
	s = xstrcpy(s);
313
	if (s[0] == '@') {
2 7u83 314
	    /* Complex command */
6 7u83 315
	    int complex = 1;
316
	    char *s1, *s2, *s3;
317
	    s++;
318
	    s1 = get_command(&s);
319
	    if (s1 == NULL) s1 = "<empty>";
320
	    s2 = get_command(&s);
321
	    s3 = get_command(&s);
322
	    if (streq(s1, "if")) {
323
		if (s2 == NULL) {
324
		    error(ERROR_SERIOUS, "Incomplete '@%s' command", s1);
325
		    s2 = "true";
2 7u83 326
		}
6 7u83 327
		MAKE_cmd_cond(ln2, s2, NULL_cmd, NULL_cmd, r);
328
	    } else if (streq(s1, "else")) {
329
		if (IS_cmd_cond(p)) {
330
		    COMMAND v = DEREF_cmd(cmd_cond_true_code(p));
331
		    if (!IS_NULL_cmd(v)) {
332
			error(ERROR_SERIOUS, "Duplicate '@%s' command", s1);
2 7u83 333
		    }
6 7u83 334
		    q = REVERSE_list(q);
335
		    MAKE_cmd_compound(ln1, q, v);
336
		    COPY_cmd(cmd_cond_true_code(p), v);
337
		    q = NULL_list(COMMAND);
338
		    ln1 = ln2;
2 7u83 339
		} else {
6 7u83 340
		    error(ERROR_SERIOUS, "Misplaced '@%s' command", s1);
2 7u83 341
		}
6 7u83 342
		s3 = s2;
343
	    } else if (streq(s1, "endif")) {
344
		if (IS_cmd_cond(p)) {
345
		    go = 0;
2 7u83 346
		} else {
6 7u83 347
		    error(ERROR_SERIOUS, "Misplaced '@%s' command", s1);
2 7u83 348
		}
6 7u83 349
		s3 = s2;
350
	    } else if (streq(s1, "loop")) {
351
		if (s2 == NULL) {
352
		    error(ERROR_SERIOUS, "Incomplete '@%s' command", s1);
353
		    s2 = "false";
2 7u83 354
		}
6 7u83 355
		MAKE_cmd_loop(ln2, s2, NULL_cmd, r);
356
	    } else if (streq(s1, "end")) {
357
		if (IS_cmd_loop(p)) {
358
		    go = 0;
2 7u83 359
		} else {
6 7u83 360
		    error(ERROR_SERIOUS, "Misplaced '@%s' command", s1);
2 7u83 361
		}
6 7u83 362
		s3 = s2;
363
	    } else if (streq(s1, "use")) {
364
		if (s2 == NULL) {
365
		    error(ERROR_SERIOUS, "Incomplete '@%s' command", s1);
366
		    s2 = "all";
2 7u83 367
		}
6 7u83 368
		MAKE_cmd_use(ln2, s2, s3, r);
369
		if (s3) s3 = get_command(&s);
370
		complex = 0;
371
	    } else if (streq(s1, "special")) {
372
		if (s2 == NULL) {
373
		    error(ERROR_SERIOUS, "Incomplete '@%s' command", s1);
374
		    s2 = "<none>";
2 7u83 375
		}
6 7u83 376
		MAKE_cmd_special(ln2, s2, s3, r);
377
		if (s3) s3 = get_command(&s);
378
		complex = 0;
379
	    } else if (streq(s1, "comment")) {
380
		s3 = NULL;
2 7u83 381
	    } else {
6 7u83 382
		error(ERROR_SERIOUS, "Unknown command, '@%s'", s1);
383
		s3 = NULL;
2 7u83 384
	    }
6 7u83 385
	    if (s3) {
386
		error(ERROR_SERIOUS, "End of '@%s' expected", s1);
2 7u83 387
	    }
6 7u83 388
	    crt_line_no = ln2 + 1;
389
	    if (!IS_NULL_cmd(r)) {
2 7u83 390
		/* Read body of command */
6 7u83 391
		if (complex) {
392
		    COMMAND u = read_template(r);
393
		    if (IS_cmd_cond(r)) {
394
			COMMAND v = DEREF_cmd(cmd_cond_true_code(r));
395
			if (IS_NULL_cmd(v)) {
396
			    COPY_cmd(cmd_cond_true_code(r), u);
2 7u83 397
			} else {
6 7u83 398
			    COPY_cmd(cmd_cond_false_code(r), u);
2 7u83 399
			}
6 7u83 400
		    } else if (IS_cmd_loop(r)) {
401
			COPY_cmd(cmd_loop_body(r), u);
2 7u83 402
		    }
403
		}
6 7u83 404
		CONS_cmd(r, q, q);
2 7u83 405
	    }
406
	} else {
407
	    /* Simple command */
6 7u83 408
	    MAKE_cmd_simple(ln2, s, r);
409
	    CONS_cmd(r, q, q);
410
	    crt_line_no = ln2 + 1;
2 7u83 411
	}
6 7u83 412
    } while (go);
413
    q = REVERSE_list(q);
414
    MAKE_cmd_compound(ln1, q, p);
415
    return(p);
2 7u83 416
}
417
 
418
 
419
/*
420
    CURRENT TOKEN
421
 
422
    These variables are used by the parser to hold the current and former
423
    lexical tokens.
424
*/
425
 
6 7u83 426
int crt_lex_token;
427
int saved_lex_token;
2 7u83 428
 
429
 
430
/*
431
    OPEN AN INPUT FILE
432
 
433
    This routine opens the input file nm.  It returns true if the file is
434
    opened successfully.
435
*/
436
 
6 7u83 437
int
438
open_file(char *nm)
2 7u83 439
{
6 7u83 440
    crt_line_no = 1;
441
    if (nm == NULL || streq(nm, "-")) {
442
	crt_file_name = "stdin";
443
	lex_input = stdin;
2 7u83 444
    } else {
6 7u83 445
	crt_file_name = nm;
446
	lex_input = fopen(nm, "r");
447
	if (lex_input == NULL) {
448
	    error(ERROR_SERIOUS, "Can't open input file, '%s'", nm);
449
	    return(0);
2 7u83 450
	}
451
    }
6 7u83 452
    return(1);
2 7u83 453
}
454
 
455
 
456
/*
457
    CLOSE THE INPUT FILE
458
 
459
    This routine closes the current input file.
460
*/
461
 
6 7u83 462
void
463
close_file(void)
2 7u83 464
{
6 7u83 465
    FILE *f = lex_input;
466
    if (f != stdin) fclose_v(f);
467
    return;
2 7u83 468
}