Subversion Repositories tendra.SVN

Rev

Rev 2 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
 
30
 
31
#include "config.h"
32
#include "char.h"
33
#include "error.h"
34
#include "lex.h"
35
#include "output.h"
36
 
37
 
38
/*
39
    OUTPUT FILE
40
 
41
    This variable gives the main output file.  out is used within this file
42
    as a shorthand for lex_output.
43
*/
44
 
45
FILE *lex_output ;
46
#define out lex_output
47
 
48
 
49
/*
50
    OUTPUT INDENTATION
51
 
52
    This routine outputs an indentation of d.
53
*/
54
 
55
static void output_indent
56
    PROTO_N ( ( d ) )
57
    PROTO_T ( int d )
58
{
59
    int n = 4 * d ;
60
    for ( ; n >= 8 ; n -= 8 ) fputc_v ( '\t', out ) ;
61
    for ( ; n ; n-- ) fputc_v ( ' ', out ) ;
62
    return ;
63
}
64
 
65
 
66
/*
67
    FIND A CHARACTER LITERAL
68
 
69
    This routine finds the character literal corresponding to c.
70
*/
71
 
72
static char *char_lit
73
    PROTO_N ( ( c ) )
74
    PROTO_T ( letter c )
75
{
76
    static char buff [10] ;
77
    switch ( c ) {
78
	case '\n' : return ( "'\\n'" ) ;
79
	case '\t' : return ( "'\\t'" ) ;
80
	case '\v' : return ( "'\\v'" ) ;
81
	case '\f' : return ( "'\\f'" ) ;
82
	case '\\' : return ( "'\\\\'" ) ;
83
	case '\'' : return ( "'\\''" ) ;
84
    }
85
    if ( c == EOF_LETTER ) return ( "LEX_EOF" ) ;
86
    if ( c > 127 ) return ( "'?'" ) ;
87
    sprintf_v ( buff, "'%c'", ( char ) c ) ;
88
    return ( buff ) ;
89
}
90
 
91
 
92
/*
93
    OUTPUT OPTIONS
94
 
95
    The flag in_pre_pass is used to indicate the preliminary pass to
96
    output_pass.  read_name gives the name of the character reading
97
    function used in the output routines.
98
*/
99
 
100
static int in_pre_pass = 0 ;
101
static char *read_name = "read_char" ;
102
 
103
 
104
/*
105
    OUTPUT PASS INFORMATION
106
 
107
    This routine outputs code for the lexical pass indicated by p.  n
108
    gives the depth of recursion and d gives the indentation.
109
*/
110
 
111
static int output_pass
112
    PROTO_N ( ( p, n, d ) )
113
    PROTO_T ( character *p X int n X int d )
114
{
115
    character *q ;
116
    int cases = 0 ;
117
    int classes = 0 ;
118
    char *ret = NULL ;
119
    char *args = NULL ;
120
    char *cond = NULL ;
121
 
122
    /* First pass */
123
    for ( q = p->next ; q != NULL ; q = q->opt ) {
124
	letter c = q->ch ;
125
	if ( c == LAST_LETTER ) {
126
	    ret = q->defn ;
127
	    args = q->args ;
128
	    cond = q->cond ;
129
	} else if ( c <= SIMPLE_LETTER ) {
130
	    cases++ ;
131
	} else {
132
	    classes++ ;
133
	}
134
    }
135
 
136
    /* Deal with cases */
137
    if ( cases || classes ) {
138
	int w1 = ( n == 0 && !in_pre_pass ) ;
139
	int w2 = ( n == 0 && in_pre_pass ) ;
140
	output_indent ( d ) ;
141
	fprintf_v ( out, "int c%d = %s ()", n, read_name ) ;
142
	if ( classes || w1 ) fprintf_v ( out, ", t%d", n ) ;
143
	fputs_v ( " ;\n", out ) ;
144
	if ( w1 ) {
145
	    output_indent ( d ) ;
146
	    fputs_v ( "t0 = lookup_char ( c0 ) ;\n", out ) ;
147
	    output_indent ( d ) ;
148
	    fputs_v ( "if ( is_white ( t0 ) ) goto start ;\n", out ) ;
149
	}
150
	if ( w2 ) {
151
	    output_indent ( d ) ;
152
	    fputs_v ( "restart : {\n", out ) ;
153
	    d++ ;
154
	}
155
 
156
	if ( cases > 4 ) {
157
	    /* Small number of cases */
158
	    output_indent ( d ) ;
159
	    fprintf_v ( out, "switch ( c%d ) {\n", n ) ;
160
	    for ( q = p->next ; q != NULL ; q = q->opt ) {
161
		letter c = q->ch ;
162
		if ( c != LAST_LETTER && c <= SIMPLE_LETTER ) {
163
		    output_indent ( d + 1 ) ;
164
		    fprintf_v ( out, "case %s : {\n", char_lit ( c ) ) ;
165
		    if ( output_pass ( q, n + 1, d + 2 ) == 0 ) {
166
			output_indent ( d + 2 ) ;
167
			fputs_v ( "break ;\n", out ) ;
168
		    }
169
		    output_indent ( d + 1 ) ;
170
		    fputs_v ( "}\n", out ) ;
171
		}
172
	    }
173
	    output_indent ( d ) ;
174
	    fputs_v ( "}\n", out ) ;
175
	} else {
176
	    /* Large number of cases */
177
	    int started = 0 ;
178
	    for ( q = p->next ; q != NULL ; q = q->opt ) {
179
		letter c = q->ch ;
180
		if ( c != LAST_LETTER && c <= SIMPLE_LETTER ) {
181
		    output_indent ( d ) ;
182
		    if ( started ) fputs_v ( "} else ", out ) ;
183
		    fprintf_v ( out, "if ( c%d == %s ) {\n",
184
				n, char_lit ( c ) ) ;
185
		    IGNORE output_pass ( q, n + 1, d + 1 ) ;
186
		    started = 1 ;
187
		}
188
	    }
189
	    if ( started ) {
190
		output_indent ( d ) ;
191
		fputs_v ( "}\n", out ) ;
192
	    }
193
	}
194
 
195
	if ( classes ) {
196
	    /* Complex cases */
197
	    int started = 0 ;
198
	    if ( !w1 ) {
199
		output_indent ( d ) ;
200
		fprintf_v ( out, "t%d = lookup_char ( c%d ) ;\n", n, n ) ;
201
	    }
202
	    for ( q = p->next ; q != NULL ; q = q->opt ) {
203
		letter c = q->ch ;
204
		if ( c != LAST_LETTER && c > SIMPLE_LETTER ) {
205
		    char *gnm ;
206
		    if ( c == WHITE_LETTER ) {
207
			gnm = "white" ;
208
		    } else {
209
			int g = ( int ) ( c - GROUP_LETTER ) ;
210
			gnm = groups [g].name ;
211
		    }
212
		    output_indent ( d ) ;
213
		    if ( started ) fputs_v ( "} else ", out ) ;
214
		    fprintf_v ( out, "if ( is_%s ( t%d ) ) {\n", gnm, n ) ;
215
		    IGNORE output_pass ( q, n + 1, d + 1 ) ;
216
		    started = 1 ;
217
		}
218
	    }
219
	    output_indent ( d ) ;
220
	    fputs_v ( "}\n", out ) ;
221
	}
222
	if ( w2 ) {
223
	    d-- ;
224
	    output_indent ( d ) ;
225
	    fputs_v ( "}\n", out ) ;
226
	}
227
	if ( n ) {
228
	    output_indent ( d ) ;
229
	    fprintf_v ( out, "unread_char ( c%d ) ;\n", n ) ;
230
	}
231
    }
232
 
233
    /* Deal with return */
234
    if ( ret ) {
235
	if ( in_pre_pass ) {
236
	    int m = *ret ;
237
	    if ( m ) {
238
		char *str ;
239
		if ( m == '\\' ) {
240
		    str = char_lit ( find_escape ( ret [1] ) ) ;
241
		    m = ret [2] ;
242
		} else {
243
		    str = char_lit ( ( letter ) m ) ;
244
		    m = ret [1] ;
245
		}
246
		if ( m ) {
247
		    error ( ERROR_SERIOUS, "Bad mapping string, '%s'", ret ) ;
248
		}
249
		if ( cond ) {
250
		    output_indent ( d ) ;
251
		    fprintf_v ( out, "if ( %s ) {\n", cond ) ;
252
		    output_indent ( d + 1 ) ;
253
		    fprintf_v ( out, "c0 = %s ;\n", str ) ;
254
		    output_indent ( d + 1 ) ;
255
		    fputs_v ( "goto restart ;\n", out ) ;
256
		    output_indent ( d ) ;
257
		    fputs_v ( "}\n", out ) ;
258
		} else {
259
		    output_indent ( d ) ;
260
		    fprintf_v ( out, "c0 = %s ;\n", str ) ;
261
		    output_indent ( d ) ;
262
		    fputs_v ( "goto restart ;\n", out ) ;
263
		}
264
	    } else {
265
		output_indent ( d ) ;
266
		if ( cond ) fprintf_v ( out, "if ( %s ) ", cond ) ;
267
		fputs_v ( "goto start ;\n", out ) ;
268
	    }
269
	} else {
270
	    output_indent ( d ) ;
271
	    if ( cond ) fprintf_v ( out, "if ( %s ) ", cond ) ;
272
	    fprintf_v ( out, "return ( %s", ret ) ;
273
	    if ( args ) {
274
		int i ;
275
		fputs_v ( " ( c0", out ) ;
276
		for ( i = 1 ; i < n ; i++ ) fprintf_v ( out, ", c%d", i ) ;
277
		fputs_v ( " )", out ) ;
278
	    }
279
	    fputs_v ( " ) ;\n", out ) ;
280
	}
281
    }
282
    return ( ( ret && ( cond == NULL ) ) ? 1 : 0 ) ;
283
}
284
 
285
 
286
/*
287
    OUTPUT INITIAL COMMENT
288
 
289
    This routine outputs a comment stating that the file is automatically
290
    generated.
291
*/
292
 
293
static void output_comment
294
    PROTO_Z ()
295
{
296
    if ( first_comment ) {
297
	/* Print copyright comment, if present */
298
	fprintf_v ( out, "%s\n\n", first_comment ) ;
299
    }
300
    fputs_v ( "/*\n    AUTOMATICALLY GENERATED", out ) ;
301
    fprintf_v ( out, " BY %s VERSION %s", progname, progvers ) ;
302
    fputs_v ( "\n*/\n\n\n", out ) ;
303
    return ;
304
}
305
 
306
 
307
/*
308
    MAIN OUTPUT ROUTINE
309
 
310
    This routine is the entry point for the main output routine.
311
*/
312
 
313
void output_all
314
    PROTO_Z ()
315
{
316
    int c, n ;
317
 
318
    /* Initial comment */
319
    output_comment () ;
320
 
321
    /* Character look-up table */
322
    fputs_v ( "/* LOOKUP TABLE */\n\n", out ) ;
323
    fprintf_v ( out, "static unsigned %s lookup_tab [257] = {\n",
324
		( no_groups >= 8 ? "short" : "char" ) ) ;
325
    for ( c = 0 ; c <= 256 ; c++ ) {
326
	unsigned int m = 0 ;
327
	letter a = ( c == 256 ? EOF_LETTER : ( letter ) c ) ;
328
	if ( in_group ( white_space, a ) ) m = 1 ;
329
	for ( n = 0 ; n < no_groups ; n++ ) {
330
	    if ( in_group ( groups [n].defn, a ) ) {
331
		m |= ( unsigned int ) ( 1 << ( n + 1 ) ) ;
332
	    }
333
	}
334
	if ( ( c % 8 ) == 0 ) fputs_v ( "    ", out ) ;
335
	fprintf_v ( out, "0x%04x", m ) ;
336
	if ( c != 256 ) {
337
	    if ( ( c % 8 ) == 7 ) {
338
		fputs_v ( ",\n", out ) ;
339
	    } else {
340
		fputs_v ( ", ", out ) ;
341
	    }
342
	}
343
    }
344
    fputs_v ( "\n} ;\n\n", out ) ;
345
 
346
    /* Macros for accessing table */
347
    fputs_v ( "#ifndef LEX_EOF\n", out ) ;
348
    fputs_v ( "#define LEX_EOF\t\t\t256\n", out ) ;
349
    fputs_v ( "#endif\n\n", out ) ;
350
    fputs_v ( "#define lookup_char( C )\t", out ) ;
351
    fputs_v ( "( ( int ) lookup_tab [ ( C ) ] )\n", out ) ;
352
    fputs_v ( "#define is_white( T )\t\t( ( T ) & 0x0001 )\n", out ) ;
353
    for ( n = 0 ; n < no_groups ; n++ ) {
354
	char *gnm = groups [n].name ;
355
	unsigned int m = ( unsigned int ) ( 1 << ( n + 1 ) ) ;
356
	fprintf_v ( out, "#define is_%s( T )\t", gnm ) ;
357
	if ( ( int ) strlen ( gnm ) < 8 ) fputc_v ( '\t', out ) ;
358
	fprintf_v ( out, "( ( T ) & 0x%04x )\n", m ) ;
359
    }
360
    fputs_v ( "\n", out ) ;
361
    fputs_v ( "#ifndef PROTO_Z\n", out ) ;
362
    fputs_v ( "#ifdef __STDC__\n", out ) ;
363
    fputs_v ( "#define PROTO_Z()\t\t( void )\n", out ) ;
364
    fputs_v ( "#else\n", out ) ;
365
    fputs_v ( "#define PROTO_Z()\t\t()\n", out ) ;
366
    fputs_v ( "#endif\n", out ) ;
367
    fputs_v ( "#endif\n\n\n", out ) ;
368
 
369
    /* Lexical pre-pass */
370
    if ( pre_pass->next ) {
371
	in_pre_pass = 1 ;
372
	fputs_v ( "/* PRE-PASS ANALYSER */\n\n", out ) ;
373
	fputs_v ( "static int read_char_aux PROTO_Z ()\n", out ) ;
374
	fputs_v ( "{\n", out ) ;
375
	fputs_v ( "    start : {\n", out ) ;
376
	IGNORE output_pass ( pre_pass, 0, 2 ) ;
377
	fputs_v ( "\treturn ( c0 ) ;\n", out ) ;
378
	fputs_v ( "    }\n", out ) ;
379
	fputs_v ( "}\n\n\n", out ) ;
380
	read_name = "read_char_aux" ;
381
    }
382
 
383
    /* Main pass */
384
    in_pre_pass = 0 ;
385
    fputs_v ( "/* MAIN PASS ANALYSER */\n\n", out ) ;
386
    fputs_v ( "int read_token PROTO_Z ()\n", out ) ;
387
    fputs_v ( "{\n", out ) ;
388
    fputs_v ( "    start : {\n", out ) ;
389
    IGNORE output_pass ( main_pass, 0, 2 ) ;
390
    fputs_v ( "\treturn ( unknown_token ( c0 ) ) ;\n", out ) ;
391
    fputs_v ( "    }\n", out ) ;
392
    fputs_v ( "}\n", out ) ;
393
    return ;
394
}
395
 
396
 
397
/*
398
    OUTPUT CODE FOR A SINGLE KEYWORD
399
 
400
    This routine outputs code for the keyword p.
401
*/
402
 
403
static void output_word
404
    PROTO_N ( ( p ) )
405
    PROTO_T ( keyword *p )
406
{
407
    fprintf_v ( out, "MAKE_KEYWORD ( \"%s\", %s", p->name, p->defn ) ;
408
    if ( p->args ) fputs_v ( " ()", out ) ;
409
    fputs_v ( " ) ;\n", out ) ;
410
    p->done = 1 ;
411
    return ;
412
}
413
 
414
 
415
/*
416
    KEYWORD OUTPUT ROUTINE
417
 
418
    This routine outputs code to generate all keywords.
419
*/
420
 
421
void output_keyword
422
    PROTO_Z ()
423
{
424
    keyword *p, *q ;
425
    output_comment () ;
426
    fputs_v ( "/* KEYWORDS */\n\n", out ) ;
427
    for ( p = keywords ; p != NULL ; p = p->next ) {
428
	if ( p->done == 0 ) {
429
	    char *cond = p->cond ;
430
	    if ( cond ) {
431
		fprintf_v ( out, "if ( %s ) {\n    ", cond ) ;
432
		output_word ( p ) ;
433
		for ( q = p->next ; q != NULL ; q = q->next ) {
434
		    if ( q->cond && streq ( q->cond, cond ) ) {
435
			fputs_v ( "    ", out ) ;
436
			output_word ( q ) ;
437
		    }
438
		}
439
		fputs_v ( "}\n", out ) ;
440
	    } else {
441
		output_word ( p ) ;
442
		for ( q = p->next ; q != NULL ; q = q->next ) {
443
		    if ( q->cond == NULL ) output_word ( q ) ;
444
		}
445
	    }
446
	}
447
    }
448
    return ;
449
}