Subversion Repositories tendra.SVN

Rev

Rev 5 | Details | Compare with Previous | 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 "char.h"
63
#include "error.h"
64
#include "lex.h"
65
#include "output.h"
66
 
67
 
68
/*
69
    OUTPUT FILE
70
 
71
    This variable gives the main output file.  out is used within this file
72
    as a shorthand for lex_output.
73
*/
74
 
6 7u83 75
FILE *lex_output;
2 7u83 76
#define out lex_output
77
 
78
 
79
/*
80
    OUTPUT INDENTATION
81
 
82
    This routine outputs an indentation of d.
83
*/
84
 
6 7u83 85
static void
86
output_indent(int d)
2 7u83 87
{
6 7u83 88
    int n = 4 * d;
89
    for (; n >= 8; n -= 8)fputc_v('\t', out);
90
    for (; n; n--)fputc_v(' ', out);
91
    return;
2 7u83 92
}
93
 
94
 
95
/*
96
    FIND A CHARACTER LITERAL
97
 
98
    This routine finds the character literal corresponding to c.
99
*/
100
 
6 7u83 101
static char *
102
char_lit(letter c)
2 7u83 103
{
6 7u83 104
    static char buff [10];
105
    switch (c) {
106
	case '\n': return("'\\n'");
107
	case '\t': return("'\\t'");
108
	case '\v': return("'\\v'");
109
	case '\f': return("'\\f'");
110
	case '\\': return("'\\\\'");
111
	case '\'': return("'\\''");
2 7u83 112
    }
6 7u83 113
    if (c == EOF_LETTER) return("LEX_EOF");
114
    if (c > 127) return("'?'");
115
    sprintf_v(buff, "'%c'",(char)c);
116
    return(buff);
2 7u83 117
}
118
 
119
 
120
/*
121
    OUTPUT OPTIONS
122
 
123
    The flag in_pre_pass is used to indicate the preliminary pass to
124
    output_pass.  read_name gives the name of the character reading
125
    function used in the output routines.
126
*/
127
 
6 7u83 128
static int in_pre_pass = 0;
129
static char *read_name = "read_char";
2 7u83 130
 
131
 
132
/*
133
    OUTPUT PASS INFORMATION
134
 
135
    This routine outputs code for the lexical pass indicated by p.  n
136
    gives the depth of recursion and d gives the indentation.
137
*/
138
 
6 7u83 139
static int
140
output_pass(character *p, int n, int d)
2 7u83 141
{
6 7u83 142
    character *q;
143
    int cases = 0;
144
    int classes = 0;
145
    char *ret = NULL;
146
    char *args = NULL;
147
    char *cond = NULL;
2 7u83 148
 
149
    /* First pass */
6 7u83 150
    for (q = p->next; q != NULL; q = q->opt) {
151
	letter c = q->ch;
152
	if (c == LAST_LETTER) {
153
	    ret = q->defn;
154
	    args = q->args;
155
	    cond = q->cond;
156
	} else if (c <= SIMPLE_LETTER) {
157
	    cases++;
2 7u83 158
	} else {
6 7u83 159
	    classes++;
2 7u83 160
	}
161
    }
162
 
163
    /* Deal with cases */
6 7u83 164
    if (cases || classes) {
165
	int w1 = (n == 0 && !in_pre_pass);
166
	int w2 = (n == 0 && in_pre_pass);
167
	output_indent(d);
168
	fprintf_v(out, "int c%d = %s()", n, read_name);
169
	if (classes || w1)fprintf_v(out, ", t%d", n);
170
	fputs_v(";\n", out);
171
	if (w1) {
172
	    output_indent(d);
173
	    fputs_v("t0 = lookup_char(c0);\n", out);
174
	    output_indent(d);
175
	    fputs_v("if (is_white(t0)) goto start;\n", out);
2 7u83 176
	}
6 7u83 177
	if (w2) {
178
	    output_indent(d);
179
	    fputs_v("restart: {\n", out);
180
	    d++;
2 7u83 181
	}
182
 
6 7u83 183
	if (cases > 4) {
2 7u83 184
	    /* Small number of cases */
6 7u83 185
	    output_indent(d);
186
	    fprintf_v(out, "switch (c%d) {\n", n);
187
	    for (q = p->next; q != NULL; q = q->opt) {
188
		letter c = q->ch;
189
		if (c != LAST_LETTER && c <= SIMPLE_LETTER) {
190
		    output_indent(d + 1);
191
		    fprintf_v(out, "case %s: {\n", char_lit(c));
192
		    if (output_pass(q, n + 1, d + 2) == 0) {
193
			output_indent(d + 2);
194
			fputs_v("break;\n", out);
2 7u83 195
		    }
6 7u83 196
		    output_indent(d + 1);
197
		    fputs_v("}\n", out);
2 7u83 198
		}
199
	    }
6 7u83 200
	    output_indent(d);
201
	    fputs_v("}\n", out);
2 7u83 202
	} else {
203
	    /* Large number of cases */
6 7u83 204
	    int started = 0;
205
	    for (q = p->next; q != NULL; q = q->opt) {
206
		letter c = q->ch;
207
		if (c != LAST_LETTER && c <= SIMPLE_LETTER) {
208
		    output_indent(d);
209
		    if (started)fputs_v("} else ", out);
210
		    fprintf_v(out, "if (c%d == %s) {\n",
211
				n, char_lit(c));
212
		    IGNORE output_pass(q, n + 1, d + 1);
213
		    started = 1;
2 7u83 214
		}
215
	    }
6 7u83 216
	    if (started) {
217
		output_indent(d);
218
		fputs_v("}\n", out);
2 7u83 219
	    }
220
	}
221
 
6 7u83 222
	if (classes) {
2 7u83 223
	    /* Complex cases */
6 7u83 224
	    int started = 0;
225
	    if (!w1) {
226
		output_indent(d);
227
		fprintf_v(out, "t%d = lookup_char(c%d);\n", n, n);
2 7u83 228
	    }
6 7u83 229
	    for (q = p->next; q != NULL; q = q->opt) {
230
		letter c = q->ch;
231
		if (c != LAST_LETTER && c > SIMPLE_LETTER) {
232
		    char *gnm;
233
		    if (c == WHITE_LETTER) {
234
			gnm = "white";
2 7u83 235
		    } else {
6 7u83 236
			int g = (int)(c - GROUP_LETTER);
237
			gnm = groups [g].name;
2 7u83 238
		    }
6 7u83 239
		    output_indent(d);
240
		    if (started)fputs_v("} else ", out);
241
		    fprintf_v(out, "if (is_%s(t%d)) {\n", gnm, n);
242
		    IGNORE output_pass(q, n + 1, d + 1);
243
		    started = 1;
2 7u83 244
		}
245
	    }
6 7u83 246
	    output_indent(d);
247
	    fputs_v("}\n", out);
2 7u83 248
	}
6 7u83 249
	if (w2) {
250
	    d--;
251
	    output_indent(d);
252
	    fputs_v("}\n", out);
2 7u83 253
	}
6 7u83 254
	if (n) {
255
	    output_indent(d);
256
	    fprintf_v(out, "unread_char(c%d);\n", n);
2 7u83 257
	}
258
    }
259
 
260
    /* Deal with return */
6 7u83 261
    if (ret) {
262
	if (in_pre_pass) {
263
	    int m = *ret;
264
	    if (m) {
265
		char *str;
266
		if (m == '\\') {
267
		    str = char_lit(find_escape(ret [1]));
268
		    m = ret [2];
2 7u83 269
		} else {
6 7u83 270
		    str = char_lit((letter)m);
271
		    m = ret [1];
2 7u83 272
		}
6 7u83 273
		if (m) {
274
		    error(ERROR_SERIOUS, "Bad mapping string, '%s'", ret);
2 7u83 275
		}
6 7u83 276
		if (cond) {
277
		    output_indent(d);
278
		    fprintf_v(out, "if (%s) {\n", cond);
279
		    output_indent(d + 1);
280
		    fprintf_v(out, "c0 = %s;\n", str);
281
		    output_indent(d + 1);
282
		    fputs_v("goto restart;\n", out);
283
		    output_indent(d);
284
		    fputs_v("}\n", out);
2 7u83 285
		} else {
6 7u83 286
		    output_indent(d);
287
		    fprintf_v(out, "c0 = %s;\n", str);
288
		    output_indent(d);
289
		    fputs_v("goto restart;\n", out);
2 7u83 290
		}
291
	    } else {
6 7u83 292
		output_indent(d);
293
		if (cond)fprintf_v(out, "if (%s) ", cond);
294
		fputs_v("goto start;\n", out);
2 7u83 295
	    }
296
	} else {
6 7u83 297
	    output_indent(d);
298
	    if (cond)fprintf_v(out, "if (%s) ", cond);
299
	    fprintf_v(out, "return(%s", ret);
300
	    if (args) {
301
		int i;
302
		fputs_v("(c0", out);
303
		for (i = 1; i < n; i++)fprintf_v(out, ", c%d", i);
304
		fputs_v(")", out);
2 7u83 305
	    }
6 7u83 306
	    fputs_v(");\n", out);
2 7u83 307
	}
308
    }
6 7u83 309
    return((ret && (cond == NULL))? 1 : 0);
2 7u83 310
}
311
 
312
 
313
/*
314
    OUTPUT INITIAL COMMENT
315
 
316
    This routine outputs a comment stating that the file is automatically
317
    generated.
318
*/
319
 
6 7u83 320
static void
321
output_comment(void)
2 7u83 322
{
6 7u83 323
    if (first_comment) {
2 7u83 324
	/* Print copyright comment, if present */
6 7u83 325
	fprintf_v(out, "%s\n\n", first_comment);
2 7u83 326
    }
6 7u83 327
    fputs_v ( "/*\n *  AUTOMATICALLY GENERATED", out ) ;
2 7u83 328
    fprintf_v ( out, " BY %s VERSION %s", progname, progvers ) ;
6 7u83 329
    fputs_v ( "\n */\n\n\n", out ) ;
330
    return;
2 7u83 331
}
332
 
333
 
334
/*
335
    MAIN OUTPUT ROUTINE
336
 
337
    This routine is the entry point for the main output routine.
338
*/
339
 
6 7u83 340
void
341
output_all(void)
2 7u83 342
{
6 7u83 343
    int c, n;
2 7u83 344
 
345
    /* Initial comment */
6 7u83 346
    output_comment();
2 7u83 347
 
348
    /* Character look-up table */
349
    fputs_v ( "/* LOOKUP TABLE */\n\n", out ) ;
6 7u83 350
    fprintf_v(out, "static unsigned %s lookup_tab[257] = {\n",
351
		(no_groups >= 8 ? "short" : "char"));
352
    for (c = 0; c <= 256; c++) {
353
	unsigned int m = 0;
354
	letter a = (c == 256 ? EOF_LETTER :(letter)c);
355
	if (in_group(white_space, a))m = 1;
356
	for (n = 0; n < no_groups; n++) {
357
	    if (in_group(groups [n].defn, a)) {
358
		m |= (unsigned int)(1 << (n + 1));
2 7u83 359
	    }
360
	}
6 7u83 361
	if ((c % 8) == 0)fputs_v("    ", out);
362
	fprintf_v(out, "0x%04x", m);
363
	if (c != 256) {
364
	    if ((c % 8) == 7) {
365
		fputs_v(",\n", out);
2 7u83 366
	    } else {
6 7u83 367
		fputs_v(", ", out);
2 7u83 368
	    }
369
	}
370
    }
6 7u83 371
    fputs_v("\n};\n\n", out);
2 7u83 372
 
373
    /* Macros for accessing table */
6 7u83 374
    fputs_v("#ifndef LEX_EOF\n", out);
375
    fputs_v("#define LEX_EOF\t\t256\n", out);
376
    fputs_v("#endif\n\n", out);
377
    fputs_v("#define lookup_char(C)\t", out);
378
    fputs_v("((int)lookup_tab[(C)])\n", out);
379
    fputs_v("#define is_white(T)\t((T) & 0x0001)\n", out);
380
    for (n = 0; n < no_groups; n++) {
381
	char *gnm = groups [n].name;
382
	unsigned int m = (unsigned int)(1 << (n + 1));
383
	fprintf_v(out, "#define is_%s(T)\t", gnm);
384
	/*if ((int)strlen(gnm) < 8)fputc_v('\t', out);*/
385
	fprintf_v(out, "((T) & 0x%04x)\n", m);
2 7u83 386
    }
6 7u83 387
    fputs_v("\n\n", out);
2 7u83 388
 
389
    /* Lexical pre-pass */
6 7u83 390
    if (pre_pass->next) {
391
	in_pre_pass = 1;
2 7u83 392
	fputs_v ( "/* PRE-PASS ANALYSER */\n\n", out ) ;
6 7u83 393
	fputs_v("static int read_char_aux(void)\n", out);
394
	fputs_v("{\n", out);
395
	fputs_v("    start: {\n", out);
396
	IGNORE output_pass(pre_pass, 0, 2);
397
	fputs_v("\treturn(c0);\n", out);
398
	fputs_v("    }\n", out);
399
	fputs_v("}\n\n\n", out);
400
	read_name = "read_char_aux";
2 7u83 401
    }
402
 
403
    /* Main pass */
6 7u83 404
    in_pre_pass = 0;
2 7u83 405
    fputs_v ( "/* MAIN PASS ANALYSER */\n\n", out ) ;
6 7u83 406
    fputs_v("int\nread_token(void)\n", out);
407
    fputs_v("{\n", out);
408
    fputs_v("    start: {\n", out);
409
    IGNORE output_pass(main_pass, 0, 2);
410
    fputs_v("\treturn(unknown_token(c0));\n", out);
411
    fputs_v("    }\n", out);
412
    fputs_v("}\n", out);
413
    return;
2 7u83 414
}
415
 
416
 
417
/*
418
    OUTPUT CODE FOR A SINGLE KEYWORD
419
 
420
    This routine outputs code for the keyword p.
421
*/
422
 
6 7u83 423
static void
424
output_word(keyword *p)
2 7u83 425
{
6 7u83 426
    fprintf_v(out, "MAKE_KEYWORD(\"%s\", %s", p->name, p->defn);
427
    if (p->args)fputs_v("()", out);
428
    fputs_v(");\n", out);
429
    p->done = 1;
430
    return;
2 7u83 431
}
432
 
433
 
434
/*
435
    KEYWORD OUTPUT ROUTINE
436
 
437
    This routine outputs code to generate all keywords.
438
*/
439
 
6 7u83 440
void
441
output_keyword(void)
2 7u83 442
{
6 7u83 443
    keyword *p, *q;
444
    output_comment();
2 7u83 445
    fputs_v ( "/* KEYWORDS */\n\n", out ) ;
6 7u83 446
    for (p = keywords; p != NULL; p = p->next) {
447
	if (p->done == 0) {
448
	    char *cond = p->cond;
449
	    if (cond) {
450
		fprintf_v(out, "if (%s) {\n    ", cond);
451
		output_word(p);
452
		for (q = p->next; q != NULL; q = q->next) {
453
		    if (q->cond && streq(q->cond, cond)) {
454
			fputs_v("    ", out);
455
			output_word(q);
2 7u83 456
		    }
457
		}
6 7u83 458
		fputs_v("}\n", out);
2 7u83 459
	    } else {
6 7u83 460
		output_word(p);
461
		for (q = p->next; q != NULL; q = q->next) {
462
		    if (q->cond == NULL)output_word(q);
2 7u83 463
		}
464
	    }
465
	}
466
    }
6 7u83 467
    return;
2 7u83 468
}