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 42... Line 72...
42
    CREATE A KEYWORD
72
    CREATE A KEYWORD
43
 
73
 
44
    This routine creates a keyword nm with lexical token value t.
74
    This routine creates a keyword nm with lexical token value t.
45
*/
75
*/
46
 
76
 
47
static void make_keyword
77
static void
48
    PROTO_N ( ( nm, t ) )
-
 
49
    PROTO_T ( char *nm X int t )
78
make_keyword(char *nm, int t)
50
{
79
{
51
    object *p = make_object ( nm, OBJ_KEYWORD ) ;
80
    object *p = make_object(nm, OBJ_KEYWORD);
52
    p->u.u_num = t ;
81
    p->u.u_num = t;
53
    IGNORE add_hash ( keywords, p, no_version ) ;
82
    IGNORE add_hash(keywords, p, no_version);
54
    return ;
83
    return;
55
}
84
}
56
 
85
 
57
 
86
 
58
/*
87
/*
59
    INITIALISE KEYWORDS
88
    INITIALISE KEYWORDS
60
 
89
 
61
    This routine initialises the hash table of keywords.
90
    This routine initialises the hash table of keywords.
62
*/
91
*/
63
 
92
 
64
void init_keywords
93
void
65
    PROTO_Z ()
94
init_keywords(void)
66
{
95
{
67
#define MAKE_KEYWORD( NAME, LEX )\
96
#define MAKE_KEYWORD(NAME, LEX)\
68
    make_keyword ( NAME, LEX )
97
    make_keyword(NAME, LEX)
69
#include "keyword.h"
98
#include "keyword.h"
70
    return ;
99
    return;
71
}
100
}
72
 
101
 
73
 
102
 
74
/*
103
/*
75
    CURRENT LEXICAL TOKEN
104
    CURRENT LEXICAL TOKEN
76
 
105
 
77
    These variables are used to store the value of the current lexical
106
    These variables are used to store the value of the current lexical
78
    token.
107
    token.
79
*/
108
*/
80
 
109
 
81
int crt_lex_token = lex_unknown ;
110
int crt_lex_token = lex_unknown;
82
int saved_lex_token = lex_unknown ;
111
int saved_lex_token = lex_unknown;
83
char *token_value = null ;
112
char *token_value = null;
84
 
113
 
85
 
114
 
86
/*
115
/*
87
    INPUT FILE
116
    INPUT FILE
88
 
117
 
89
    These variable input_file gives the file from which the input is read.
118
    These variable input_file gives the file from which the input is read.
90
    The input_pending variable is used to unread one character.
119
    The input_pending variable is used to unread one character.
91
*/
120
*/
92
 
121
 
93
FILE *input_file ;
122
FILE *input_file;
94
int input_pending = LEX_EOF ;
123
int input_pending = LEX_EOF;
95
 
124
 
96
 
125
 
97
/*
126
/*
98
    READ A CHARACTER FROM THE INPUT FILE
127
    READ A CHARACTER FROM THE INPUT FILE
99
 
128
 
100
    This routine reads the next character from the input file.
129
    This routine reads the next character from the input file.
101
*/
130
*/
102
 
131
 
103
static int read_char
132
static int
104
    PROTO_Z ()
133
read_char(void)
105
{
134
{
106
    int c = input_pending ;
135
    int c = input_pending;
107
    if ( c == LEX_EOF ) {
136
    if (c == LEX_EOF) {
108
	c = fgetc ( input_file ) ;
137
	c = fgetc(input_file);
109
	if ( c == '\n' ) line_no++ ;
138
	if (c == '\n')line_no++;
110
	if ( c == EOF ) return ( LEX_EOF ) ;
139
	if (c == EOF) return(LEX_EOF);
111
	c &= 0xff ;
140
	c &= 0xff;
112
    } else {
141
    } else {
113
	input_pending = LEX_EOF ;
142
	input_pending = LEX_EOF;
114
    }
143
    }
115
    return ( c ) ;
144
    return(c);
116
}
145
}
117
 
146
 
118
 
147
 
119
/*
148
/*
120
    MAPPINGS OF LEXICAL ANALYSER ROUTINES
149
    MAPPINGS OF LEXICAL ANALYSER ROUTINES
121
 
150
 
122
    These macros give the mappings from the lexical analyser to the
151
    These macros give the mappings from the lexical analyser to the
123
    routines defined in this module.
152
    routines defined in this module.
124
*/
153
*/
125
 
154
 
126
static int read_identifier PROTO_S ( ( int, int, int ) ) ;
155
static int read_identifier(int, int, int);
127
static int read_number PROTO_S ( ( int, int ) ) ;
156
static int read_number(int, int);
128
static int read_string PROTO_S ( ( int ) ) ;
157
static int read_string(int);
129
static int read_insert PROTO_S ( ( int ) ) ;
158
static int read_insert(int);
130
static int read_c_comment PROTO_S ( ( int ) ) ;
159
static int read_c_comment(int);
131
static int read_comment PROTO_S ( ( int ) ) ;
160
static int read_comment(int);
132
 
161
 
133
#define unread_char( A )	input_pending = ( A )
162
#define unread_char(A)	input_pending = (A)
134
#define get_global( A )		read_identifier ( 0, ( A ), 0 )
163
#define get_global(A)		read_identifier(0,(A), 0)
135
#define get_local( A, B )	read_identifier ( ( A ), ( B ), 0 )
164
#define get_local(A, B)	read_identifier((A), (B), 0)
136
#define get_command( A, B )	read_identifier ( ( A ), ( B ), 0 )
165
#define get_command(A, B)	read_identifier((A), (B), 0)
137
#define get_variable( A, B )	read_identifier ( ( A ), ( B ), 0 )
166
#define get_variable(A, B)	read_identifier((A), (B), 0)
138
#define get_number( A )		read_number ( ( A ), 0 )
167
#define get_number(A)		read_number((A), 0)
139
#define get_string( A )		read_string ( 0 )
168
#define get_string(A)		read_string(0)
140
#define get_comment( A )	read_comment ( 0 )
169
#define get_comment(A)	read_comment(0)
141
#define get_c_comment( A, B )	read_c_comment ( 0 )
170
#define get_c_comment(A, B)	read_c_comment(0)
142
#define get_text( A, B )	read_insert ( 0 )
171
#define get_text(A, B)	read_insert(0)
143
#define unknown_token( A )	lex_unknown
172
#define unknown_token(A)	lex_unknown
144
 
173
 
145
 
174
 
146
/*
175
/*
147
    INCLUDE THE LEXICAL ANALYSER
176
    INCLUDE THE LEXICAL ANALYSER
148
 
177
 
Line 161... Line 190...
161
    entered after the first character, b, has been read.  a gives the
190
    entered after the first character, b, has been read.  a gives the
162
    identifier prefix, '+' for commands, '$' for variables, '~' for
191
    identifier prefix, '+' for commands, '$' for variables, '~' for
163
    local identifiers, and 0 for normal identifiers.
192
    local identifiers, and 0 for normal identifiers.
164
*/
193
*/
165
 
194
 
166
static int read_identifier
195
static int
167
    PROTO_N ( ( a, b, pp ) )
-
 
168
    PROTO_T ( int a X int b X int pp )
196
read_identifier(int a, int b, int pp)
169
{
197
{
170
    int c ;
198
    int c;
171
    object *p ;
199
    object *p;
172
    int i = 0 ;
200
    int i = 0;
173
    char *s = buffer ;
201
    char *s = buffer;
174
    if ( a ) s [ i++ ] = ( char ) a ;
202
    if (a)s [ i++ ] = (char)a;
175
    s [ i++ ] = ( char ) b ;
203
    s [ i++ ] = (char)b;
176
    for ( ; ; ) {
204
    for (; ;) {
177
	c = read_char () ;
205
	c = read_char();
178
	if ( !is_alphanum ( lookup_char ( c ) ) ) break ;
206
	if (!is_alphanum(lookup_char(c)))break;
179
	s [i] = ( char ) c ;
207
	s [i] = (char)c;
180
	if ( ++i >= buffsize ) {
208
	if (++i >= buffsize) {
181
	    error ( ERR_SERIOUS, "Identifier too long" ) ;
209
	    error(ERR_SERIOUS, "Identifier too long");
182
	    i = 1 ;
210
	    i = 1;
183
	}
211
	}
184
    }
212
    }
185
    unread_char ( c ) ;
213
    unread_char(c);
186
    s [i] = 0 ;
214
    s [i] = 0;
187
    p = search_hash ( keywords, s, no_version ) ;
215
    p = search_hash(keywords, s, no_version);
188
    if ( p ) return ( p->u.u_num ) ;
216
    if (p) return(p->u.u_num);
189
    token_value = s ;
217
    token_value = s;
190
    if ( a == 0 ) {
218
    if (a == 0) {
191
	if ( !pp ) token_value = string_copy ( s ) ;
219
	if (!pp)token_value = string_copy(s);
192
	return ( lex_name ) ;
220
	return(lex_name);
193
    }
221
    }
194
    if ( a == '$' ) {
222
    if (a == '$') {
195
	if ( !pp ) token_value = string_copy ( s ) ;
223
	if (!pp)token_value = string_copy(s);
196
	return ( lex_variable ) ;
224
	return(lex_variable);
197
    }
225
    }
198
    if ( a == '+' ) {
226
    if (a == '+') {
199
	/* Commands */
227
	/* Commands */
200
	if ( !pp ) token_value = string_copy ( s ) ;
228
	if (!pp)token_value = string_copy(s);
201
	error ( ERR_SERIOUS, "Unknown command, '%s'", s ) ;
229
	error(ERR_SERIOUS, "Unknown command, '%s'", s);
202
	return ( lex_name ) ;
230
	return(lex_name);
203
    }
231
    }
204
    token_value = string_concat ( HIDDEN_NAME, s + 1 ) ;
232
    token_value = string_concat(HIDDEN_NAME, s + 1);
205
    return ( lex_name ) ;
233
    return(lex_name);
206
}
234
}
207
 
235
 
208
 
236
 
209
/*
237
/*
210
    READ A NUMBER
238
    READ A NUMBER
211
 
239
 
212
    This routine reads a number from the input file.  It is entered after
240
    This routine reads a number from the input file.  It is entered after
213
    the initial character, a, has been read.
241
    the initial character, a, has been read.
214
*/
242
*/
215
 
243
 
216
static int read_number
244
static int
217
    PROTO_N ( ( a, pp ) )
-
 
218
    PROTO_T ( int a X int pp )
245
read_number(int a, int pp)
219
{
246
{
220
    int c ;
247
    int c;
221
    int i = 0 ;
248
    int i = 0;
222
    char *s = buffer ;
249
    char *s = buffer;
223
    s [ i++ ] = ( char ) a ;
250
    s [ i++ ] = (char)a;
224
    for ( ; ; ) {
251
    for (; ;) {
225
	c = read_char () ;
252
	c = read_char();
226
	if ( !is_digit ( lookup_char ( c ) ) ) break ;
253
	if (!is_digit(lookup_char(c)))break;
227
	s [i] = ( char ) c ;
254
	s [i] = (char)c;
228
	if ( ++i >= buffsize ) {
255
	if (++i >= buffsize) {
229
	    error ( ERR_SERIOUS, "Number too long" ) ;
256
	    error(ERR_SERIOUS, "Number too long");
230
	    i = 0 ;
257
	    i = 0;
231
	}
258
	}
232
    }
259
    }
233
    unread_char ( c ) ;
260
    unread_char(c);
234
    s [i] = 0 ;
261
    s [i] = 0;
235
    if ( pp ) {
262
    if (pp) {
236
	token_value = s ;
263
	token_value = s;
237
    } else {
264
    } else {
238
	token_value = string_copy ( s ) ;
265
	token_value = string_copy(s);
239
    }
266
    }
240
    return ( lex_number ) ;
267
    return(lex_number);
241
}
268
}
242
 
269
 
243
 
270
 
244
/*
271
/*
245
    READ A STRING
272
    READ A STRING
246
 
273
 
247
    This routine reads a string from the input file.  It is entered after
274
    This routine reads a string from the input file.  It is entered after
248
    the initial quote has been read.
275
    the initial quote has been read.
249
*/
276
*/
250
 
277
 
251
static int read_string
278
static int
252
    PROTO_N ( ( pp ) )
-
 
253
    PROTO_T ( int pp )
279
read_string(int pp)
254
{
280
{
255
    int c ;
281
    int c;
256
    int i = 0 ;
282
    int i = 0;
257
    char *s = buffer ;
283
    char *s = buffer;
258
    for ( ; ; ) {
284
    for (; ;) {
259
	c = read_char () ;
285
	c = read_char();
260
	if ( c == '"' ) {
286
	if (c == '"') {
261
	    /* End of string */
287
	    /* End of string */
262
	    break ;
288
	    break;
263
	} else if ( c == '\\' ) {
289
	} else if (c == '\\') {
264
	    /* Deal with escaped characters */
290
	    /* Deal with escaped characters */
265
	    c = read_char () ;
291
	    c = read_char();
266
	    if ( c == '\n' || c == LEX_EOF ) goto new_line ;
292
	    if (c == '\n' || c == LEX_EOF)goto new_line;
267
	    if ( pp ) {
293
	    if (pp) {
268
		/* Preserve escapes when preprocessing */
294
		/* Preserve escapes when preprocessing */
269
		s [i] = '\\' ;
295
		s [i] = '\\';
270
		i++ ;
296
		i++;
271
	    } else {
297
	    } else {
272
		/* Examine escape sequence */
298
		/* Examine escape sequence */
273
		switch ( c ) {
299
		switch (c) {
274
		    case 'n' : c = '\n' ; break ;
300
		    case 'n': c = '\n'; break;
275
		    case 'r' : c = '\r' ; break ;
301
		    case 'r': c = '\r'; break;
276
		    case 't' : c = '\t' ; break ;
302
		    case 't': c = '\t'; break;
277
		}
303
		}
278
	    }
304
	    }
279
	} else if ( c == '\n' || c == LEX_EOF ) {
305
	} else if (c == '\n' || c == LEX_EOF) {
280
	    /* Deal with new lines */
306
	    /* Deal with new lines */
281
	    new_line : {
307
	    new_line : {
282
		error ( ERR_SERIOUS, "New line in string" ) ;
308
		error(ERR_SERIOUS, "New line in string");
283
		s [i] = 0 ;
309
		s [i] = 0;
284
		return ( lex_string ) ;
310
		return(lex_string);
285
	    }
311
	    }
286
	}
312
	}
287
	s [i] = ( char ) c ;
313
	s [i] = (char)c;
288
	if ( ++i >= buffsize ) {
314
	if (++i >= buffsize) {
289
	    error ( ERR_SERIOUS, "String too long" ) ;
315
	    error(ERR_SERIOUS, "String too long");
290
	    i = 0 ;
316
	    i = 0;
291
	}
317
	}
292
    }
318
    }
293
    s [i] = 0 ;
319
    s [i] = 0;
294
    if ( pp ) {
320
    if (pp) {
295
	token_value = s ;
321
	token_value = s;
296
    } else {
322
    } else {
297
	token_value = string_copy ( s ) ;
323
	token_value = string_copy(s);
298
    }
324
    }
299
    return ( lex_string ) ;
325
    return(lex_string);
300
}
326
}
301
 
327
 
302
 
328
 
303
/*
329
/*
304
    READ A SECTION OF QUOTED TEXT
330
    READ A SECTION OF QUOTED TEXT
Line 308... Line 334...
308
    have already been read.  Firstly any further percents are read, then
334
    have already been read.  Firstly any further percents are read, then
309
    the text is read until an equal number of percents are encountered.
335
    the text is read until an equal number of percents are encountered.
310
    Any leading or trailing whitespace is ignored if pp is false.
336
    Any leading or trailing whitespace is ignored if pp is false.
311
*/
337
*/
312
 
338
 
313
static int read_insert
339
static int
314
    PROTO_N ( ( pp ) )
-
 
315
    PROTO_T ( int pp )
340
read_insert(int pp)
316
{
341
{
317
    int c ;
342
    int c;
318
    int i = 0 ;
343
    int i = 0;
319
    int p = 0 ;
344
    int p = 0;
320
    int percents = 2 ;
345
    int percents = 2;
321
    char *s = buffer ;
346
    char *s = buffer;
322
    while ( c = read_char (), c == '%' ) percents++ ;
347
    while (c = read_char(), c == '%')percents++;
323
    unread_char ( c ) ;
348
    unread_char(c);
324
    if ( pp ) {
349
    if (pp) {
325
	/* Preserve percents when preprocessing */
350
	/* Preserve percents when preprocessing */
326
	if ( percents < buffsize ) {
351
	if (percents < buffsize) {
327
	    for ( i = 0 ; i < percents ; i++ ) s [i] = '%' ;
352
	    for (i = 0; i < percents; i++)s [i] = '%';
328
	} else {
353
	} else {
329
	    error ( ERR_SERIOUS, "Insert too long" ) ;
354
	    error(ERR_SERIOUS, "Insert too long");
330
	}
355
	}
331
    }
356
    }
332
    do {
357
    do {
333
	c = read_char () ;
358
	c = read_char();
334
	if ( c == '%' ) {
359
	if (c == '%') {
335
	    p++ ;
360
	    p++;
336
	} else {
361
	} else {
337
	    if ( c == LEX_EOF ) {
362
	    if (c == LEX_EOF) {
338
		error ( ERR_SERIOUS, "End of file in quoted text" ) ;
363
		error(ERR_SERIOUS, "End of file in quoted text");
339
		return ( lex_eof ) ;
364
		return(lex_eof);
340
	    }
365
	    }
341
	    p = 0 ;
366
	    p = 0;
342
	}
367
	}
343
	s [i] = ( char ) c ;
368
	s [i] = (char)c;
344
	if ( ++i >= buffsize ) {
369
	if (++i >= buffsize) {
345
	    error ( ERR_SERIOUS, "Insert too long" ) ;
370
	    error(ERR_SERIOUS, "Insert too long");
346
	    i = 0 ;
371
	    i = 0;
347
	}
372
	}
348
    } while ( p != percents ) ;
373
    } while (p != percents);
349
    if ( pp ) {
374
    if (pp) {
350
	/* Preserve percents when preprocessing */
375
	/* Preserve percents when preprocessing */
351
	s [i] = 0 ;
376
	s [i] = 0;
352
	token_value = s ;
377
	token_value = s;
353
    } else {
378
    } else {
354
	/* Strip out initial and final white space */
379
	/* Strip out initial and final white space */
355
	if ( i >= p ) i -= p ;
380
	if (i >= p)i -= p;
356
	s [i] = 0 ;
381
	s [i] = 0;
357
	while ( --i >= 0 ) {
382
	while (--i >= 0) {
358
	    int a = ( int ) s [i] ;
383
	    int a = (int)s [i];
359
	    int t = lookup_char ( a & 0xff ) ;
384
	    int t = lookup_char(a & 0xff);
360
	    if ( !is_white ( t ) ) break ;
385
	    if (!is_white(t))break;
361
	    s [i] = 0 ;
386
	    s [i] = 0;
362
	}
387
	}
363
	i = 0 ;
388
	i = 0;
364
	for ( ; ; ) {
389
	for (; ;) {
365
	    int a = ( int ) s [i] ;
390
	    int a = (int)s [i];
366
	    int t = lookup_char ( a & 0xff ) ;
391
	    int t = lookup_char(a & 0xff);
367
	    if ( !is_white ( t ) ) break ;
392
	    if (!is_white(t))break;
368
	    i++ ;
393
	    i++;
369
	}
394
	}
370
	token_value = string_copy ( s + i ) ;
395
	token_value = string_copy(s + i);
371
    }
396
    }
372
    return ( percents % 2 ? lex_build_Hinsert : lex_insert ) ;
397
    return(percents % 2 ? lex_build_Hinsert : lex_insert);
373
}
398
}
374
 
399
 
375
 
400
 
376
/*
401
/*
377
    READ A C COMMENT
402
    READ A C COMMENT
Line 379... Line 404...
379
    This routine reads a C-style comment into the buffer.  The routine is
404
    This routine reads a C-style comment into the buffer.  The routine is
380
    entered just after the initial / * has been read, and continues until
405
    entered just after the initial / * has been read, and continues until
381
    the corresponding * /.
406
    the corresponding * /.
382
*/
407
*/
383
 
408
 
384
static int read_c_comment
409
static int
385
    PROTO_N ( ( pp ) )
-
 
386
    PROTO_T ( int pp )
410
read_c_comment(int pp)
387
{
411
{
388
    int c ;
412
    int c;
389
    int i = 2 ;
413
    int i = 2;
390
    int p = 0 ;
414
    int p = 0;
391
    char *s = buffer ;
415
    char *s = buffer;
392
    s [0] = '/' ;
416
    s [0] = '/';
393
    s [1] = '*' ;
417
    s [1] = '*';
394
    do {
418
    do {
395
	c = read_char () ;
419
	c = read_char();
396
	if ( c == '*' && p == 0 ) {
420
	if (c == '*' && p == 0) {
397
	    p = 1 ;
421
	    p = 1;
398
	} else if ( c == '/' && p == 1 ) {
422
	} else if (c == '/' && p == 1) {
399
	    p = 2 ;
423
	    p = 2;
400
	} else {
424
	} else {
401
	    p = 0 ;
425
	    p = 0;
402
	}
426
	}
403
	if ( c == LEX_EOF ) {
427
	if (c == LEX_EOF) {
404
	    error ( ERR_SERIOUS, "End of file in comment" ) ;
428
	    error(ERR_SERIOUS, "End of file in comment");
405
	    return ( lex_eof ) ;
429
	    return(lex_eof);
406
	}
430
	}
407
	s [i] = ( char ) c ;
431
	s [i] = (char)c;
408
	if ( ++i >= buffsize ) {
432
	if (++i >= buffsize) {
409
	    error ( ERR_SERIOUS, "Comment too long" ) ;
433
	    error(ERR_SERIOUS, "Comment too long");
410
	    i = 2 ;
434
	    i = 2;
411
	}
435
	}
412
    } while ( p != 2 ) ;
436
    } while (p != 2);
413
    s [i] = 0 ;
437
    s [i] = 0;
414
    if ( pp ) {
438
    if (pp) {
415
	token_value = s ;
439
	token_value = s;
416
    } else {
440
    } else {
417
	token_value = string_copy ( s ) ;
441
	token_value = string_copy(s);
418
    }
442
    }
419
    return ( lex_comment ) ;
443
    return(lex_comment);
420
}
444
}
421
 
445
 
422
 
446
 
423
/*
447
/*
424
    READ A TSPEC COMMENT
448
    READ A TSPEC COMMENT
Line 426... Line 450...
426
    This routine steps over a tspec comment.  It is entered after the
450
    This routine steps over a tspec comment.  It is entered after the
427
    initial '#' has been read and skips to the end of the line.  If pp
451
    initial '#' has been read and skips to the end of the line.  If pp
428
    is false then the next token is returned.
452
    is false then the next token is returned.
429
*/
453
*/
430
 
454
 
431
static int read_comment
455
static int
432
    PROTO_N ( ( pp ) )
-
 
433
    PROTO_T ( int pp )
456
read_comment(int pp)
434
{
457
{
435
    int c ;
458
    int c;
436
    while ( c = read_char (), c != '\n' ) {
459
    while (c = read_char(), c != '\n') {
437
	if ( c == LEX_EOF ) {
460
	if (c == LEX_EOF) {
438
	    error ( ERR_SERIOUS, "End of file in comment" ) ;
461
	    error(ERR_SERIOUS, "End of file in comment");
439
	    return ( lex_eof ) ;
462
	    return(lex_eof);
440
	}
463
	}
441
    }
464
    }
442
    if ( pp ) return ( lex_unknown ) ;
465
    if (pp) return(lex_unknown);
443
    return ( read_token () ) ;
466
    return(read_token());
444
}
467
}
445
 
468
 
446
 
469
 
447
/*
470
/*
448
    READ A PREPROCESSING TOKEN
471
    READ A PREPROCESSING TOKEN
Line 450... Line 473...
450
    This routine is a stripped down version of read_token which is used
473
    This routine is a stripped down version of read_token which is used
451
    in preprocessing.  Initial white space is skipped if w is true.
474
    in preprocessing.  Initial white space is skipped if w is true.
452
    The token read is always stored in the buffer.
475
    The token read is always stored in the buffer.
453
*/
476
*/
454
 
477
 
455
static int read_pptoken
478
static int
456
    PROTO_N ( ( w ) )
-
 
457
    PROTO_T ( int w )
479
read_pptoken(int w)
458
{
480
{
459
    int c ;
481
    int c;
460
    int t = lex_unknown ;
482
    int t = lex_unknown;
461
    do {
483
    do {
462
	c = read_char () ;
484
	c = read_char();
463
    } while ( w && is_white ( lookup_char ( c ) ) ) ;
485
    } while (w && is_white(lookup_char(c)));
464
    switch ( c ) {
486
    switch (c) {
465
	case '"' : {
487
	case '"': {
466
	    return ( read_string ( 1 ) ) ;
488
	    return(read_string(1));
467
	}
489
	}
468
	case '#' : {
490
	case '#': {
469
	    IGNORE read_comment ( 1 ) ;
491
	    IGNORE read_comment(1);
470
	    if ( w ) return ( read_pptoken ( w ) ) ;
492
	    if (w) return(read_pptoken(w));
471
	    c = '\n' ;
493
	    c = '\n';
472
	    break ;
494
	    break;
473
	}
495
	}
474
	case '%' : {
496
	case '%': {
475
	    int a = read_char () ;
497
	    int a = read_char();
476
	    if ( a == '%' ) return ( read_insert ( 1 ) ) ;
498
	    if (a == '%') return(read_insert(1));
477
	    unread_char ( a ) ;
499
	    unread_char(a);
478
	    break ;
500
	    break;
479
	}
501
	}
480
	case '+' : {
502
	case '+': {
481
	    int a = read_char () ;
503
	    int a = read_char();
482
	    if ( is_alpha ( lookup_char ( a ) ) ) {
504
	    if (is_alpha(lookup_char(a))) {
483
		return ( read_identifier ( c, a, 1 ) ) ;
505
		return(read_identifier(c, a, 1));
484
	    }
506
	    }
485
	    unread_char ( a ) ;
507
	    unread_char(a);
486
	    break ;
508
	    break;
487
	}
509
	}
488
	case '/' : {
510
	case '/': {
489
	    int a = read_char () ;
511
	    int a = read_char();
490
	    if ( a == '*' ) return ( read_c_comment ( 1 ) ) ;
512
	    if (a == '*') return(read_c_comment(1));
491
	    unread_char ( a ) ;
513
	    unread_char(a);
492
	    break ;
514
	    break;
493
	}
515
	}
494
	case ':' : {
516
	case ':': {
495
	    int a = read_char () ;
517
	    int a = read_char();
496
	    if ( a == '=' ) {
518
	    if (a == '=') {
497
		buffer [0] = ( char ) c ;
519
		buffer [0] = (char)c;
498
		buffer [1] = ( char ) a ;
520
		buffer [1] = (char)a;
499
		buffer [2] = 0 ;
521
		buffer [2] = 0;
500
		return ( lex_assign ) ;
522
		return(lex_assign);
501
	    }
523
	    }
502
	    unread_char ( a ) ;
524
	    unread_char(a);
503
	    break ;
525
	    break;
504
	}
526
	}
505
	case '(' : t = lex_open_Hround ; break ;
527
	case '(': t = lex_open_Hround; break;
506
	case ')' : t = lex_close_Hround ; break ;
528
	case ')': t = lex_close_Hround; break;
507
	case '{' : t = lex_open_Hbrace ; break ;
529
	case '{': t = lex_open_Hbrace; break;
508
	case '}' : t = lex_close_Hbrace ; break ;
530
	case '}': t = lex_close_Hbrace; break;
509
	case ';' : t = lex_semicolon ; break ;
531
	case ';': t = lex_semicolon; break;
510
	case ',' : t = lex_comma ; break ;
532
	case ',': t = lex_comma; break;
511
	case LEX_EOF : t = lex_eof ; break ;
533
	case LEX_EOF: t = lex_eof; break;
512
    }
534
    }
513
    buffer [0] = ( char ) c ;
535
    buffer [0] = (char)c;
514
    buffer [1] = 0 ;
536
    buffer [1] = 0;
515
    return ( t ) ;
537
    return(t);
516
}
538
}
517
 
539
 
518
 
540
 
519
/*
541
/*
520
    READ A STRING
542
    READ A STRING
Line 522... Line 544...
522
    This routine reads a string plus one other character from the input
544
    This routine reads a string plus one other character from the input
523
    file, storing the string in str and returning the other character.
545
    file, storing the string in str and returning the other character.
524
    b is set to true if the string is enclosed in brackets.
546
    b is set to true if the string is enclosed in brackets.
525
*/
547
*/
526
 
548
 
527
static int read_pp_string
549
static int
528
    PROTO_N ( ( str, b ) )
-
 
529
    PROTO_T ( char **str X int *b )
550
read_pp_string(char **str, int *b)
530
{
551
{
531
    int c = read_pptoken ( 1 ) ;
552
    int c = read_pptoken(1);
532
    if ( c == lex_open_Hround ) {
553
    if (c == lex_open_Hround) {
533
	*b = 1 ;
554
	*b = 1;
534
	c = read_pptoken ( 1 ) ;
555
	c = read_pptoken(1);
535
    }
556
    }
536
    if ( c != lex_string ) {
557
    if (c != lex_string) {
537
	error ( ERR_SERIOUS, "Syntax error - string expected" ) ;
558
	error(ERR_SERIOUS, "Syntax error - string expected");
538
	*str = "???" ;
559
	*str = "???";
539
	return ( c ) ;
560
	return(c);
540
    }
561
    }
541
    *str = string_copy ( buffer ) ;
562
    *str = string_copy(buffer);
542
    c = read_pptoken ( 1 ) ;
563
    c = read_pptoken(1);
543
    if ( *b ) {
564
    if (*b) {
544
	if ( c != lex_close_Hround ) {
565
	if (c != lex_close_Hround) {
545
	    error ( ERR_SERIOUS, "Syntax error - ')' expected" ) ;
566
	    error(ERR_SERIOUS, "Syntax error - ')' expected");
546
	}
567
	}
547
	c = read_pptoken ( 1 ) ;
568
	c = read_pptoken(1);
548
    }
569
    }
549
    return ( c ) ;
570
    return(c);
550
}
571
}
551
 
572
 
552
 
573
 
553
/*
574
/*
554
    PRINT A SUBSET NAME
575
    PRINT A SUBSET NAME
555
 
576
 
556
    This routine prints the command cmd "api", "file", "subset" to the
577
    This routine prints the command cmd "api", "file", "subset" to the
557
    file output.
578
    file output.
558
*/
579
*/
559
 
580
 
560
static void print_subset_name
581
static void
561
    PROTO_N ( ( output, cmd, api, file, subset, b ) )
-
 
562
    PROTO_T ( FILE *output X char *cmd X
582
print_subset_name(FILE *output, char *cmd, char *api, char *file,
563
	      char *api X char *file X char *subset X int b )
583
		  char *subset, int b)
564
{
584
{
565
    if ( b ) {
585
    if (b) {
566
	IGNORE fprintf ( output, "%s ( \"%s\" )", cmd, api ) ;
586
	IGNORE fprintf(output, "%s ( \"%s\" )", cmd, api);
567
    } else {
587
    } else {
568
	IGNORE fprintf ( output, "%s \"%s\"", cmd, api ) ;
588
	IGNORE fprintf(output, "%s \"%s\"", cmd, api);
569
    }
589
    }
570
    if ( file ) IGNORE fprintf ( output, ", \"%s\"", file ) ;
590
    if (file)IGNORE fprintf(output, ", \"%s\"", file);
571
    if ( subset ) {
591
    if (subset) {
572
	if ( file == null ) IGNORE fputs ( ", \"\"", output ) ;
592
	if (file == null)IGNORE fputs(", \"\"", output);
573
	IGNORE fprintf ( output, ", \"%s\"", subset ) ;
593
	IGNORE fprintf(output, ", \"%s\"", subset);
574
    }
594
    }
575
    return ;
595
    return;
576
}
596
}
577
 
597
 
578
 
598
 
579
/*
599
/*
580
    PRINT THE CURRENT FILE POSITION
600
    PRINT THE CURRENT FILE POSITION
581
 
601
 
582
    This routine prints file name and line number directives to the file
602
    This routine prints file name and line number directives to the file
583
    output.
603
    output.
584
*/
604
*/
585
 
605
 
586
static void print_posn
606
static void
587
    PROTO_N ( ( output ) )
-
 
588
    PROTO_T ( FILE *output )
607
print_posn(FILE *output)
589
{
608
{
590
    static char *last_filename = "" ;
609
    static char *last_filename = "";
591
    if ( !streq ( filename, last_filename ) ) {
610
    if (!streq(filename, last_filename)) {
592
	IGNORE fprintf ( output, "$FILE = \"%s\" ;\n", filename ) ;
611
	IGNORE fprintf(output, "$FILE = \"%s\" ;\n", filename);
593
	last_filename = filename ;
612
	last_filename = filename;
594
    }
613
    }
595
    IGNORE fprintf ( output, "$LINE = %d ;\n", line_no - 1 ) ;
614
    IGNORE fprintf(output, "$LINE = %d ;\n", line_no - 1);
596
    return ;
615
    return;
597
}
616
}
598
 
617
 
599
 
618
 
600
/*
619
/*
601
    PREPROCESS A SUBFILE
620
    PREPROCESS A SUBFILE
602
 
621
 
603
    This routine reads a +IMPLEMENT or +USE directive (indicated by n)
622
    This routine reads a +IMPLEMENT or +USE directive (indicated by n)
604
    from the input file to output.
623
    from the input file to output.
605
*/
624
*/
606
 
625
 
607
static void preproc_subfile
626
static void
608
    PROTO_N ( ( output, cmd ) )
-
 
609
    PROTO_T ( FILE *output X char *cmd )
627
preproc_subfile(FILE *output, char *cmd)
610
{
628
{
611
    int c ;
629
    int c;
612
    int txt ;
630
    int txt;
613
    int b = 0 ;
631
    int b = 0;
614
    char *api = null ;
632
    char *api = null;
615
    char *file = null ;
633
    char *file = null;
616
    char *subset = null ;
634
    char *subset = null;
617
    c = read_pp_string ( &api, &b ) ;
635
    c = read_pp_string(&api, &b);
618
    if ( c == lex_comma ) {
636
    if (c == lex_comma) {
619
	int d = 0 ;
637
	int d = 0;
620
	c = read_pp_string ( &file, &d ) ;
638
	c = read_pp_string(&file, &d);
621
	if ( d ) {
639
	if (d) {
622
	    error ( ERR_SERIOUS, "Illegally bracketed string" ) ;
640
	    error(ERR_SERIOUS, "Illegally bracketed string");
623
	    d = 0 ;
641
	    d = 0;
624
	}
642
	}
625
	if ( c == lex_comma ) {
643
	if (c == lex_comma) {
626
	    c = read_pp_string ( &subset, &d ) ;
644
	    c = read_pp_string(&subset, &d);
627
	    if ( d ) error ( ERR_SERIOUS, "Illegally bracketed string" ) ;
645
	    if (d)error(ERR_SERIOUS, "Illegally bracketed string");
628
	}
646
	}
629
	if ( *file == 0 ) file = null ;
647
	if (*file == 0)file = null;
630
    }
648
    }
631
    if ( c == lex_semicolon ) {
649
    if (c == lex_semicolon) {
632
	txt = ';' ;
650
	txt = ';';
633
    } else if ( c == lex_open_Hround ) {
651
    } else if (c == lex_open_Hround) {
634
	txt = '(' ;
652
	txt = '(';
635
    } else {
653
    } else {
636
	error ( ERR_SERIOUS, "Syntax error - ';' or '(' expected" ) ;
654
	error(ERR_SERIOUS, "Syntax error - ';' or '(' expected");
637
	txt = ';' ;
655
	txt = ';';
638
    }
656
    }
639
    preproc ( output, api, file, subset ) ;
657
    preproc(output, api, file, subset);
640
    print_posn ( output ) ;
658
    print_posn(output);
641
    print_subset_name ( output, cmd, api, file, subset, b ) ;
659
    print_subset_name(output, cmd, api, file, subset, b);
642
    IGNORE fputc ( ' ', output ) ;
660
    IGNORE fputc(' ', output);
643
    IGNORE fputc ( txt, output ) ;
661
    IGNORE fputc(txt, output);
644
    return ;
662
    return;
645
}
663
}
646
 
664
 
647
 
665
 
648
/*
666
/*
649
    PREPROCESS A FILE
667
    PREPROCESS A FILE
650
 
668
 
651
    This routine preprocesses the subset api:file:subset into output.
669
    This routine preprocesses the subset api:file:subset into output.
652
*/
670
*/
653
 
671
 
654
void preproc
672
void
655
    PROTO_N ( ( output, api, file, subset ) )
-
 
656
    PROTO_T ( FILE *output X char *api X char *file X char *subset )
673
preproc(FILE *output, char *api, char *file, char *subset)
657
{
674
{
658
    int c ;
675
    int c;
659
    char *s ;
676
    char *s;
660
    object *p ;
677
    object *p;
661
    char *sn, *nm ;
678
    char *sn, *nm;
662
    FILE *old_file ;
679
    FILE *old_file;
663
    int old_pending ;
680
    int old_pending;
664
    int old_line_no ;
681
    int old_line_no;
665
    char *old_filename ;
682
    char *old_filename;
666
    boolean found = 0 ;
683
    boolean found = 0;
667
    int brackets = 0 ;
684
    int brackets = 0;
668
    int end_brackets = 0 ;
685
    int end_brackets = 0;
669
    int if_depth = 0 ;
686
    int if_depth = 0;
670
    int else_depth = 0 ;
687
    int else_depth = 0;
671
    FILE *input = null ;
688
    FILE *input = null;
672
    boolean printing = ( boolean ) ( subset ? 0 : 1 ) ;
689
    boolean printing = (boolean)(subset ? 0 : 1);
673
 
690
 
674
    /* Check for previous inclusion */
691
    /* Check for previous inclusion */
675
    sn = subset_name ( api, file, subset ) ;
692
    sn = subset_name(api, file, subset);
676
    p = search_hash ( subsets, sn, no_version ) ;
693
    p = search_hash(subsets, sn, no_version);
677
    if ( p != null ) {
694
    if (p != null) {
678
	if ( p->u.u_info == null ) {
695
	if (p->u.u_info == null) {
679
	    error ( ERR_SERIOUS, "Recursive inclusion of '%s'", sn ) ;
696
	    error(ERR_SERIOUS, "Recursive inclusion of '%s'", sn);
680
	} else if ( p->u.u_info->implemented ) {
697
	} else if (p->u.u_info->implemented) {
681
	    error ( ERR_SERIOUS, "Set '%s' not found", sn ) ;
698
	    error(ERR_SERIOUS, "Set '%s' not found", sn);
682
	}
699
	}
683
	return ;
700
	return;
684
    }
701
    }
685
 
702
 
686
    /* Open the input file */
703
    /* Open the input file */
687
    nm = ( file ? file : MASTER_FILE ) ;
704
    nm = (file ? file : MASTER_FILE);
688
    if ( !streq ( api, LOCAL_API ) ) {
705
    if (!streq(api, LOCAL_API)) {
689
	nm = string_printf ( "%s/%s", api, nm ) ;
706
	nm = string_printf("%s/%s", api, nm);
690
    }
707
    }
691
    s = input_dir ;
708
    s = input_dir;
692
    while ( s ) {
709
    while (s) {
693
	char *t = strchr ( s, ':' ) ;
710
	char *t = strchr(s, ':');
694
	if ( t == null ) {
711
	if (t == null) {
695
	   IGNORE sprintf ( buffer, "%s/%s", s, nm ) ;
712
	   IGNORE sprintf(buffer, "%s/%s", s, nm);
696
	   s = null ;
713
	   s = null;
697
	} else {
714
	} else {
698
	   IGNORE strcpy ( buffer, s ) ;
715
	   IGNORE strcpy(buffer, s);
699
	   IGNORE sprintf ( buffer + ( t - s ), "/%s", nm ) ;
716
	   IGNORE sprintf(buffer + (t - s), "/%s", nm);
700
	   s = t + 1 ;
717
	   s = t + 1;
701
	}
718
	}
702
	input = fopen ( buffer, "r" ) ;
719
	input = fopen(buffer, "r");
703
	if ( input ) {
720
	if (input) {
704
	    nm = string_copy ( buffer ) ;
721
	    nm = string_copy(buffer);
705
	    break ;
722
	    break;
706
	}
723
	}
707
    }
724
    }
708
    if ( input == null ) {
725
    if (input == null) {
709
	input = fopen ( nm, "r" ) ;
726
	input = fopen(nm, "r");
710
	if ( input == null ) {
727
	if (input == null) {
711
	    char *err = "Set '%s' not found (can't find file %s)" ;
728
	    char *err = "Set '%s' not found (can't find file %s)";
712
	    error ( ERR_SERIOUS, err, sn, nm ) ;
729
	    error(ERR_SERIOUS, err, sn, nm);
713
	    p = make_object ( sn, OBJ_SUBSET ) ;
730
	    p = make_object(sn, OBJ_SUBSET);
714
	    IGNORE add_hash ( subsets, p, no_version ) ;
731
	    IGNORE add_hash(subsets, p, no_version);
715
	    p->u.u_info = make_info ( api, file, subset ) ;
732
	    p->u.u_info = make_info(api, file, subset);
716
	    p->u.u_info->implemented = 1 ;
733
	    p->u.u_info->implemented = 1;
717
	    return ;
734
	    return;
718
	}
735
	}
719
    }
736
    }
720
    if ( verbose > 1 ) {
737
    if (verbose > 1) {
721
	if ( subset ) {
738
	if (subset) {
722
	    error ( ERR_INFO, "Preprocessing %s [%s] ...", nm, subset ) ;
739
	    IGNORE printf("Preprocessing %s [%s] ...\n", nm, subset);
723
	} else {
740
	} else {
724
	    error ( ERR_INFO, "Preprocessing %s ...", nm ) ;
741
	    IGNORE printf("Preprocessing %s ...\n", nm);
725
	}
742
	}
726
    }
743
    }
727
    old_filename = filename ;
744
    old_filename = filename;
728
    old_line_no = line_no ;
745
    old_line_no = line_no;
729
    old_file = input_file ;
746
    old_file = input_file;
730
    old_pending = input_pending ;
747
    old_pending = input_pending;
731
    filename = nm ;
748
    filename = nm;
732
    line_no = 1 ;
749
    line_no = 1;
733
    input_file = input ;
750
    input_file = input;
734
    input_pending = LEX_EOF ;
751
    input_pending = LEX_EOF;
735
    p = make_object ( sn, OBJ_SUBSET ) ;
752
    p = make_object(sn, OBJ_SUBSET);
736
    IGNORE add_hash ( subsets, p, no_version ) ;
753
    IGNORE add_hash(subsets, p, no_version);
737
 
754
 
738
    /* Print position identifier */
755
    /* Print position identifier */
739
    print_subset_name ( output, "+SET", api, file, subset, 0 ) ;
756
    print_subset_name(output, "+SET", api, file, subset, 0);
740
    IGNORE fputs ( " := {\n", output ) ;
757
    IGNORE fputs(" := {\n", output);
741
    if ( printing ) print_posn ( output ) ;
758
    if (printing)print_posn(output);
742
 
759
 
743
    /* Process the input */
760
    /* Process the input */
744
    while ( c = read_pptoken ( 0 ), c != lex_eof ) {
761
    while (c = read_pptoken(0), c != lex_eof) {
745
	switch ( c ) {
762
	switch (c) {
746
 
763
 
747
	    case lex_subset : {
764
	    case lex_subset: {
748
		/* Deal with subsets */
765
		/* Deal with subsets */
749
		int d = 0 ;
766
		int d = 0;
750
		c = read_pp_string ( &s, &d ) ;
767
		c = read_pp_string(&s, &d);
751
		if ( d ) error ( ERR_SERIOUS, "Illegally bracketed string" ) ;
768
		if (d)error(ERR_SERIOUS, "Illegally bracketed string");
752
		if ( c != lex_assign ) {
769
		if (c != lex_assign) {
753
		    error ( ERR_SERIOUS, "Syntax error - ':=' expected" ) ;
770
		    error(ERR_SERIOUS, "Syntax error - ':=' expected");
754
		}
771
		}
755
		c = read_pptoken ( 1 ) ;
772
		c = read_pptoken(1);
756
		if ( c != lex_open_Hbrace ) {
773
		if (c != lex_open_Hbrace) {
757
		    error ( ERR_SERIOUS, "Syntax error - '{' expected" ) ;
774
		    error(ERR_SERIOUS, "Syntax error - '{' expected");
758
		}
775
		}
759
		brackets++ ;
776
		brackets++;
760
		if ( printing ) {
777
		if (printing) {
761
		    int b = brackets ;
778
		    int b = brackets;
762
		    char *cmd = "+IMPLEMENT" ;
779
		    char *cmd = "+IMPLEMENT";
763
		    preproc ( output, api, file, s ) ;
780
		    preproc(output, api, file, s);
764
		    print_subset_name ( output, cmd, api, file, s, 0 ) ;
781
		    print_subset_name(output, cmd, api, file, s, 0);
765
		    IGNORE fputs ( " ;\n", output ) ;
782
		    IGNORE fputs(" ;\n", output);
766
		    do {
783
		    do {
767
			c = read_pptoken ( 0 ) ;
784
			c = read_pptoken(0);
768
			if ( c == lex_open_Hbrace ) {
785
			if (c == lex_open_Hbrace) {
769
			    brackets++ ;
786
			    brackets++;
770
			} else if ( c == lex_close_Hbrace ) {
787
			} else if (c == lex_close_Hbrace) {
771
			    brackets-- ;
788
			    brackets--;
772
			} else if ( c == lex_eof ) {
789
			} else if (c == lex_eof) {
773
			    char *err = "Can't find end of subset '%s'" ;
790
			    char *err = "Can't find end of subset '%s'";
774
			    error ( ERR_SERIOUS, err, s ) ;
791
			    error(ERR_SERIOUS, err, s);
775
			    goto end_of_file ;
792
			    goto end_of_file;
776
			}
793
			}
777
		    } while ( brackets >= b ) ;
794
		    } while (brackets >= b);
778
		    c = read_pptoken ( 1 ) ;
795
		    c = read_pptoken(1);
779
		    if ( c != lex_semicolon ) {
796
		    if (c != lex_semicolon) {
780
			error ( ERR_SERIOUS, "Syntax error - ';' expected" ) ;
797
			error(ERR_SERIOUS, "Syntax error - ';' expected");
781
		    }
798
		    }
782
		    print_posn ( output ) ;
799
		    print_posn(output);
783
		} else {
800
		} else {
784
		    if ( streq ( s, subset ) ) {
801
		    if (streq(s, subset)) {
785
			if ( found ) {
802
			if (found) {
786
			    char *err = "Set '%s' already defined (line %d)" ;
803
			    char *err = "Set '%s' already defined (line %d)";
787
			    error ( ERR_SERIOUS, err, sn, p->line_no ) ;
804
			    error(ERR_SERIOUS, err, sn, p->line_no);
788
			} else {
805
			} else {
789
			    found = 1 ;
806
			    found = 1;
790
			    printing = 1 ;
807
			    printing = 1;
791
			    print_posn ( output ) ;
808
			    print_posn(output);
792
			    p->line_no = line_no ;
809
			    p->line_no = line_no;
793
			    end_brackets = brackets ;
810
			    end_brackets = brackets;
794
			}
811
			}
795
		    }
812
		    }
796
		}
813
		}
797
		break ;
814
		break;
798
	    }
815
	    }
799
 
816
 
800
	    case lex_implement : {
817
	    case lex_implement: {
801
		/* Deal with subset uses */
818
		/* Deal with subset uses */
802
		if ( printing ) preproc_subfile ( output, "+IMPLEMENT" ) ;
819
		if (printing)preproc_subfile(output, "+IMPLEMENT");
803
		break ;
820
		break;
804
	    }
821
	    }
805
 
822
 
806
	    case lex_use : {
823
	    case lex_use: {
807
		/* Deal with subset uses */
824
		/* Deal with subset uses */
808
		if ( printing ) preproc_subfile ( output, "+USE" ) ;
825
		if (printing)preproc_subfile(output, "+USE");
809
		break ;
826
		break;
810
	    }
827
	    }
811
 
828
 
812
	    case lex_set : {
829
	    case lex_set: {
813
		/* Deal with sets */
830
		/* Deal with sets */
814
		error ( ERR_SERIOUS, "+SET directive in preprocessor" ) ;
831
		error(ERR_SERIOUS, "+SET directive in preprocessor");
815
		goto default_lab ;
832
		goto default_lab;
816
	    }
833
	    }
817
 
834
 
818
	    case lex_if :
835
	    case lex_if:
819
	    case lex_ifdef :
836
	    case lex_ifdef:
820
	    case lex_ifndef : {
837
	    case lex_ifndef: {
821
		if_depth++ ;
838
		if_depth++;
822
		else_depth = 0 ;
839
		else_depth = 0;
823
		goto default_lab ;
840
		goto default_lab;
824
	    }
841
	    }
825
 
842
 
826
	    case lex_else : {
843
	    case lex_else: {
827
		if ( if_depth == 0 ) {
844
		if (if_depth == 0) {
828
		    error ( ERR_SERIOUS, "+ELSE without +IF" ) ;
845
		    error(ERR_SERIOUS, "+ELSE without +IF");
829
		} else {
846
		} else {
830
		    if ( else_depth ) {
847
		    if (else_depth) {
831
			error ( ERR_SERIOUS, "Duplicate +ELSE" ) ;
848
			error(ERR_SERIOUS, "Duplicate +ELSE");
832
		    }
849
		    }
833
		    else_depth = 1 ;
850
		    else_depth = 1;
834
		}
851
		}
835
		goto default_lab ;
852
		goto default_lab;
836
	    }
853
	    }
837
 
854
 
838
	    case lex_endif : {
855
	    case lex_endif: {
839
		if ( if_depth == 0 ) {
856
		if (if_depth == 0) {
840
		    error ( ERR_SERIOUS, "+ENDIF without +IF" ) ;
857
		    error(ERR_SERIOUS, "+ENDIF without +IF");
841
		} else {
858
		} else {
842
		    if_depth-- ;
859
		    if_depth--;
843
		}
860
		}
844
		else_depth = 0 ;
861
		else_depth = 0;
845
		goto default_lab ;
862
		goto default_lab;
846
	    }
863
	    }
847
 
864
 
848
	    case lex_string : {
865
	    case lex_string: {
849
		/* Deal with strings */
866
		/* Deal with strings */
850
		if ( printing ) {
867
		if (printing) {
851
		    IGNORE fprintf ( output, "\"%s\"", buffer ) ;
868
		    IGNORE fprintf(output, "\"%s\"", buffer);
852
		}
869
		}
853
		break ;
870
		break;
854
	    }
871
	    }
855
 
872
 
856
	    case lex_open_Hbrace : {
873
	    case lex_open_Hbrace: {
857
		/* Start of subset */
874
		/* Start of subset */
858
		brackets++ ;
875
		brackets++;
859
		goto default_lab ;
876
		goto default_lab;
860
	    }
877
	    }
861
 
878
 
862
	    case lex_close_Hbrace : {
879
	    case lex_close_Hbrace: {
863
		/* End of subset */
880
		/* End of subset */
864
		brackets-- ;
881
		brackets--;
865
		if ( brackets < 0 ) {
882
		if (brackets < 0) {
866
		    error ( ERR_SERIOUS, "Unmatched '}'" ) ;
883
		    error(ERR_SERIOUS, "Unmatched '}'");
867
		    brackets = 0 ;
884
		    brackets = 0;
868
		}
885
		}
869
		if ( subset && brackets < end_brackets ) {
886
		if (subset && brackets < end_brackets) {
870
		    printing = 0 ;
887
		    printing = 0;
871
		}
888
		}
872
		goto default_lab ;
889
		goto default_lab;
873
	    }
890
	    }
874
 
891
 
875
	    default :
892
	    default :
876
	    default_lab : {
893
	    default_lab : {
877
		/* Deal with simple tokens */
894
		/* Deal with simple tokens */
878
		if ( printing ) IGNORE fputs ( buffer, output ) ;
895
		if (printing)IGNORE fputs(buffer, output);
879
		break ;
896
		break;
880
	    }
897
	    }
881
	}
898
	}
882
    }
899
    }
883
 
900
 
884
    /* End of file */
901
    /* End of file */
885
    end_of_file : {
902
    end_of_file : {
886
	if ( brackets ) {
903
	if (brackets) {
887
	    error ( ERR_SERIOUS, "Bracket imbalance of %d", brackets ) ;
904
	    error(ERR_SERIOUS, "Bracket imbalance of %d", brackets);
888
	}
905
	}
889
	while ( if_depth ) {
906
	while (if_depth) {
890
	    error ( ERR_SERIOUS, "+IF without +ENDIF" ) ;
907
	    error(ERR_SERIOUS, "+IF without +ENDIF");
891
	    if_depth-- ;
908
	    if_depth--;
892
	}
909
	}
893
	IGNORE fputs ( "} ;\n", output ) ;
910
	IGNORE fputs("} ;\n", output);
894
	IGNORE fclose ( input ) ;
911
	IGNORE fclose(input);
895
	p->u.u_info = make_info ( api, file, subset ) ;
912
	p->u.u_info = make_info(api, file, subset);
896
	filename = old_filename ;
913
	filename = old_filename;
897
	line_no = old_line_no ;
914
	line_no = old_line_no;
898
	input_file = old_file ;
915
	input_file = old_file;
899
	input_pending = old_pending ;
916
	input_pending = old_pending;
900
	if ( subset && !found ) {
917
	if (subset && !found) {
901
	    char *err = "Set '%s' not found (can't find subset '%s')" ;
918
	    char *err = "Set '%s' not found (can't find subset '%s')";
902
	    error ( ERR_SERIOUS, err, sn, subset ) ;
919
	    error(ERR_SERIOUS, err, sn, subset);
903
	    p->u.u_info->implemented = 1 ;
920
	    p->u.u_info->implemented = 1;
904
	}
921
	}
905
	return ;
922
	return;
906
    }
923
    }
907
}
924
}