Subversion Repositories tendra.SVN

Rev

Rev 2 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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