Mercurial > ~dholland > hg > ag > index.cgi
comparison tests/agcl/oldagsrc/ts.syn @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:13d2b8934445 |
---|---|
1 { | |
2 /* | |
3 AnaGram, a System for Syntax Directed Programming | |
4 C Macro preprocessor and parser | |
5 | |
6 Copyright (c) 1993, Parsifal Software. | |
7 All Rights Reserved. | |
8 | |
9 TS.SYN: Token Scanner Module | |
10 */ | |
11 | |
12 #include "mpp.h" | |
13 | |
14 | |
15 // context structure for diagnostics | |
16 | |
17 struct location { unsigned line, column;}; | |
18 | |
19 } | |
20 | |
21 | |
22 // Configuration section | |
23 | |
24 [ | |
25 context type = location // request context tracking | |
26 ~allow macros // function defs for red procs | |
27 auto resynch | |
28 line numbers // #line statements in output | |
29 error trace // build trace on syntax error | |
30 ~test range // not necessary | |
31 ~declare pcb | |
32 ~error frame | |
33 subgrammar { | |
34 simple token, | |
35 expanded token, | |
36 initial arg element, | |
37 ws, | |
38 eol, | |
39 macro definition header, | |
40 } | |
41 parser file name = "#.cpp" | |
42 ] | |
43 | |
44 | |
45 // Character Set Definitions | |
46 | |
47 any text char = ~eof - newline - '\\' | |
48 ascii = 1..126 | |
49 blank = ' ' + '\t' + '\r' + '\f' + '\v' | |
50 digit = '0-9' | |
51 eof = -1 + 0 | |
52 hex digit = '0-9' + 'A-F' + 'a-f' | |
53 newline = '\n' | |
54 letter = 'a-z' + 'A-Z' + '_' | |
55 not punctuation = '#' + blank + letter + digit + '\'' + '"' + newline + '\\' | |
56 punctuation = ascii - not punctuation | |
57 simple char = ~eof - ('\'' + '\\' + '\n') | |
58 string char = ~eof - ('"' + '\\' + '\n') | |
59 | |
60 | |
61 // Grammar, or Start token | |
62 | |
63 input file $ // Grammar Token | |
64 -> [section | eol]/..., eof // Alternating sequence | |
65 | |
66 eol | |
67 -> newline, [newline | space]... | |
68 | |
69 | |
70 // Conditional Compilation Control | |
71 | |
72 section | |
73 -> expanded token... =*scanner_sink << op('\n'); | |
74 -> control line | |
75 -> conditional block | |
76 | |
77 conditional block | |
78 -> true if section, eol, endif line | |
79 -> true if section, eol, skip else section, eol, endif line | |
80 -> false if section, eol, endif line | |
81 -> false if section, eol, else section, eol, endif line | |
82 | |
83 true if section | |
84 -> true condition | |
85 -> true if section, eol, section | |
86 -> false if section, eol, true else condition | |
87 | |
88 false if section | |
89 -> false condition | |
90 -> false if section, eol, skip section | |
91 -> false if section, eol, false else condition | |
92 | |
93 else section | |
94 -> '#', ws?, "else", ws? | |
95 -> else section, eol, section | |
96 | |
97 endif line | |
98 -> '#', ws?, "endif", ws? | |
99 | |
100 skip section | |
101 -> skip line | |
102 -> skip if section, eol, endif line | |
103 | |
104 skip if section | |
105 -> '#', ws?, {"if" | "ifdef" | "ifndef"}, any text?... | |
106 -> skip if section, eol, skip section | |
107 -> skip if section, eol, skip else line | |
108 | |
109 skip else section | |
110 -> skip else line | |
111 -> skip else section, eol, skip else line | |
112 -> skip else section, eol, skip section | |
113 | |
114 skip else line | |
115 -> '#', ws?, "elif", any text?... | |
116 -> '#', ws?, "else", ws? | |
117 | |
118 skip line | |
119 -> '#', ws?, [{"define" | "undefine" | "include" | "line" | | |
120 "error" | "pragma"}, any text?...] | |
121 -> not control mark, any text?... | |
122 | |
123 any text | |
124 -> any text char | |
125 -> '\\', ~eof | |
126 | |
127 not control mark | |
128 -> any text char - '#' | |
129 -> '\\', ~eof | |
130 | |
131 | |
132 // Conditional Control Lines | |
133 | |
134 true condition, false condition | |
135 -> '#', ws?, "ifdef", ws, name string, ws? =check_defined(1); | |
136 -> '#', ws?, "ifndef", ws, name string, ws? =check_defined(0); | |
137 -> '#', ws?, if header, expanded token... =eval_if(); | |
138 | |
139 true else condition, false else condition | |
140 -> '#', ws?, else if header, expanded token... =eval_elif(); | |
141 | |
142 if header | |
143 -> "if", ws =init_condition(); | |
144 | |
145 else if header | |
146 -> "elif", ws =init_condition(); | |
147 | |
148 | |
149 // Other Control Lines | |
150 | |
151 control line | |
152 -> include header, expanded token... =include_file(); | |
153 -> '#', ws?, "undef", ws, name string, ws? =undefine(); | |
154 -> '#', ws?, [{"line" | "error" | "pragma"}, any text?...] | |
155 -> macro definition header:id, simple token?... =save_macro_body(id); | |
156 | |
157 include header | |
158 -> '#', ws?, "include" =save_sink << scanner_sink, scanner_sink = &++ta; | |
159 | |
160 | |
161 // Macro Definitions | |
162 | |
163 (int) macro definition header | |
164 -> '#', ws?, "define", ws, name string =init_macro_def(0,0); | |
165 -> '#', ws?, "define", ws, name string, | |
166 '(', ws?, parameter list:n, ')' =init_macro_def(n,1); | |
167 | |
168 (int) parameter list | |
169 -> =0; | |
170 -> names, ws? | |
171 | |
172 (int) names | |
173 -> name string =1; | |
174 -> names:n, ws?, ',', ws?, name string =n+1; | |
175 | |
176 | |
177 // Unexpanded text (for macro definitions | |
178 | |
179 simple token | |
180 -> space:c =*scanner_sink << space_op(c); | |
181 -> word | |
182 -> separator | |
183 -> '#' =*scanner_sink << op('#'); | |
184 -> qualified real | |
185 -> integer constant | |
186 | |
187 word | |
188 -> name string =*scanner_sink << name_token(); | |
189 | |
190 | |
191 // Expanded text | |
192 | |
193 expanded token | |
194 -> expanded word | |
195 -> separator | |
196 -> space | |
197 -> qualified real | |
198 -> integer constant | |
199 | |
200 expanded word | |
201 -> variable:t =*scanner_sink << t; | |
202 -> simple macro:t =expand(t,0); | |
203 -> macro:t, ws? =*scanner_sink << t; | |
204 -> macro:t, ws?, '(', ws?, macro arg list:n, ')' =expand(t,n); | |
205 -> defined, ws?, '(', ws?, name string, ws?, ')' =*scanner_sink << defined(); | |
206 -> defined, ws, name string =*scanner_sink << defined(); | |
207 | |
208 | |
209 // Name classification | |
210 | |
211 (token) variable, simple macro, macro, defined | |
212 -> name string =id_macro(); | |
213 | |
214 | |
215 // Macro Arguments | |
216 | |
217 (int) macro arg list | |
218 -> =0; | |
219 -> !save_sink << scanner_sink, scanner_sink = &ta;, macro args:n = | |
220 save_sink >> scanner_sink, n; | |
221 | |
222 (int) macro args | |
223 -> !++ta;, arg elements =1; | |
224 -> macro args:n, ',', ws?, !++ta;, arg elements =n+1; | |
225 | |
226 arg elements | |
227 -> initial arg element | |
228 -> arg elements, arg element | |
229 | |
230 arg element | |
231 -> space:c =*scanner_sink << space_op(c); | |
232 -> initial arg element | |
233 | |
234 initial arg element | |
235 -> name string =*scanner_sink << name_token(); | |
236 -> qualified real | |
237 -> integer constant | |
238 -> string literal =*scanner_sink << tkn(STRINGliteral); | |
239 -> character constant =*scanner_sink << tkn(CHARACTERconstant); | |
240 -> operator | |
241 -> punctuation - '(' - ',' - ')':p =*scanner_sink << op(p); | |
242 -> nested elements, ')':t =*scanner_sink << op(t); | |
243 | |
244 nested elements | |
245 -> '(':t =*scanner_sink << op(t); | |
246 -> nested elements, arg element | |
247 -> nested elements, ',':t =*scanner_sink << op(t); | |
248 | |
249 | |
250 // Basic syntactic elements | |
251 | |
252 separator | |
253 -> string literal =*scanner_sink << tkn(STRINGliteral); | |
254 -> character constant =*scanner_sink << tkn(CHARACTERconstant); | |
255 -> operator | |
256 -> punctuation:p =*scanner_sink << op(p); | |
257 -> '\\', '\n' | |
258 | |
259 (int) space | |
260 -> blank | |
261 -> comment =' '; | |
262 | |
263 ws = space... | |
264 | |
265 comment | |
266 -> comment head, "*/" | |
267 | |
268 comment head | |
269 -> "/*" | |
270 -> comment head, ~eof | |
271 | |
272 comment, comment head | |
273 -> comment head, comment ={if (nest_comments) CHANGE_REDUCTION(comment_head);} | |
274 | |
275 operator | |
276 -> '&', '&' =*scanner_sink << op(ANDAND); | |
277 -> '&', '=' =*scanner_sink << op(ANDassign); | |
278 -> '-', '>' =*scanner_sink << op(ARROW); | |
279 -> '#', '#' =*scanner_sink << op(CONCAT); | |
280 -> '-', '-' =*scanner_sink << op(DECR); | |
281 -> '/', '=' =*scanner_sink << op(DIVassign); | |
282 -> '.', '.', '.' =*scanner_sink << op(ELLIPSIS); | |
283 -> '=', '=' =*scanner_sink << op(EQ); | |
284 -> '^', '=' =*scanner_sink << op(ERassign); | |
285 -> '>', '=' =*scanner_sink << op(GE); | |
286 -> '+', '+' =*scanner_sink << op(ICR); | |
287 -> '<', '=' =*scanner_sink << op(LE); | |
288 -> '<', '<' =*scanner_sink << op(LS); | |
289 -> '<', '<', '=' =*scanner_sink << op(LSassign); | |
290 -> '%', '=' =*scanner_sink << op(MODassign); | |
291 -> '-', '=' =*scanner_sink << op(MINUSassign); | |
292 -> '*', '=' =*scanner_sink << op(MULTassign); | |
293 -> '!', '=' =*scanner_sink << op(NE); | |
294 -> '|', '=' =*scanner_sink << op(ORassign); | |
295 -> '|', '|' =*scanner_sink << op(OROR); | |
296 -> '+', '=' =*scanner_sink << op(PLUSassign); | |
297 -> '>', '>' =*scanner_sink << op(RS); | |
298 -> '>', '>', '=' =*scanner_sink << op(RSassign); | |
299 | |
300 | |
301 // Numeric constants | |
302 | |
303 qualified real | |
304 -> real constant, floating qualifier =*scanner_sink << tkn(FLOATconstant); | |
305 | |
306 real constant | |
307 -> real | |
308 | |
309 floating qualifier | |
310 -> | |
311 -> 'f' + 'F' =sa << 'F'; | |
312 -> 'l' + 'L' =sa << 'L'; | |
313 | |
314 real | |
315 -> simple real | |
316 -> simple real, exponent | |
317 -> confusion, exponent | |
318 -> decimal integer, exponent | |
319 | |
320 simple real | |
321 -> confusion, '.' =sa << '.'; | |
322 -> octal integer, '.' | |
323 -> decimal integer, '.' =sa << '.'; | |
324 -> '.', '0-9':d =++sa << '.' << d; | |
325 -> simple real, '0-9':d =sa << d; | |
326 | |
327 confusion | |
328 -> octal integer, '8-9':d =sa << d; | |
329 -> confusion, '0-9':d =sa << d; | |
330 | |
331 exponent | |
332 -> 'e' + 'E', '-', '0-9':d =sa << '-' << d; | |
333 -> 'e' + 'E', '+'?, '0-9':d =sa << '+' << d; | |
334 -> exponent, '0-9':d =sa << d; | |
335 | |
336 integer qualifier | |
337 -> 'u' + 'U' =sa << 'U'; | |
338 -> 'l' + 'L' =sa << 'L'; | |
339 | |
340 integer constant | |
341 -> octal constant =*scanner_sink << tkn(OCTconstant); | |
342 -> decimal constant =*scanner_sink << tkn(DECconstant); | |
343 -> hex constant =*scanner_sink << tkn(HEXconstant); | |
344 | |
345 octal constant | |
346 -> octal integer | |
347 -> octal constant, integer qualifier | |
348 | |
349 octal integer | |
350 -> '0' =++sa << '0'; | |
351 -> octal integer, '0-7':d =sa << d; | |
352 | |
353 hex constant | |
354 -> hex integer | |
355 -> hex constant, integer qualifier | |
356 | |
357 hex integer | |
358 -> '0', 'x' + 'X', hex digit:d =++sa << "0X" << d; | |
359 -> hex integer, hex digit:d =sa << d; | |
360 | |
361 decimal constant | |
362 -> decimal integer | |
363 -> decimal constant, integer qualifier | |
364 | |
365 decimal integer | |
366 -> '1-9':d =++sa << d; | |
367 -> decimal integer, '0-9':d =sa << d; | |
368 | |
369 | |
370 // String Literals and Character Constants | |
371 | |
372 string literal | |
373 -> string chars, '"' =sa << '"'; | |
374 | |
375 string chars | |
376 -> '"' =++sa << '"'; | |
377 -> string chars, string char:c =sa << c; | |
378 -> string chars, '\\', ~eof - '\n':c =sa << '\\' << c; | |
379 -> string chars, '\\', '\n' | |
380 | |
381 | |
382 // Character constants | |
383 | |
384 character constant | |
385 -> simple chars, '\'' =sa << '\''; | |
386 | |
387 simple chars | |
388 -> '\'' =++sa << '\''; | |
389 -> simple chars, simple char:c = sa << c; | |
390 -> simple chars, '\\', ~eof - '\n': c = sa << '\\' << c; | |
391 -> simple chars, '\\', '\n' | |
392 | |
393 | |
394 // Identifiers | |
395 | |
396 name string | |
397 -> letter:c =++sa << c; | |
398 -> name string, letter+digit:c =sa << c; | |
399 | |
400 | |
401 { // Embedded C | |
402 #include "array.h" // \AnaGram\classlib\include\array.h | |
403 #include "stack.h" // \AnaGram\classlib\include\stack.h | |
404 #include <io.h> // If not found, not necessary | |
405 #include <sys/types.h> // If not found, not necessary | |
406 #include <sys/stat.h> | |
407 #include <fcntl.h> | |
408 | |
409 | |
410 // Macro Definitions | |
411 | |
412 #define SYNTAX_ERROR syntax_error_scanning(PCB.error_message) | |
413 #define GET_CONTEXT (CONTEXT.line = PCB.line, CONTEXT.column = PCB.column) | |
414 #define GET_INPUT (PCB.input_code = getc(input.file)) | |
415 #define PCB input.pcb | |
416 | |
417 | |
418 // Structure Definition | |
419 | |
420 struct file_descriptor { | |
421 char *name; // name of file | |
422 FILE *file; // source of input characters | |
423 ts_pcb_type pcb; // parser control block for file | |
424 }; | |
425 | |
426 | |
427 // Static Data Declarations | |
428 | |
429 static char *error_modifier = ""; | |
430 static file_descriptor input; | |
431 static stack<token_sink *> save_sink(5); | |
432 | |
433 | |
434 // Syntax Error Reporting | |
435 /* | |
436 syntax_error() provides an error diagnostic procedure for those | |
437 parsers which are called by the token scanner. error_modifier is set | |
438 by expand() so that an error encountered during a macro expansion | |
439 will be so described. Otherwise, the diagnostic will not make | |
440 sense. | |
441 | |
442 Since all other parsers are called from reduction procedures, the | |
443 line and column number of the token they are dealing with is given | |
444 by the context of the token scanner production that is being | |
445 reduced. | |
446 */ | |
447 | |
448 void syntax_error(char *msg) { | |
449 printf("%s: Line %d, Column %d: %s%s\n", | |
450 input.name, CONTEXT.line, CONTEXT.column, msg, error_modifier); | |
451 } | |
452 | |
453 /* | |
454 syntax_error_scanning() provides an error diagnostic procedure for | |
455 the token scanner itself. The locus of the error is given by the | |
456 current line and column number of the token scan, as given in the | |
457 parser control block. | |
458 */ | |
459 | |
460 static void syntax_error_scanning(char *msg) { | |
461 printf("%s: Line %d, Column %d: %s\n", | |
462 input.name, PCB.line, PCB.column, msg); | |
463 } | |
464 | |
465 | |
466 // Support for Reduction Procedures | |
467 /* | |
468 name_token() looks up the name string in the string accumulator, | |
469 identifies it in the token dictionary, checks to see if it is a | |
470 reserved word, and creates a token. | |
471 */ | |
472 | |
473 static token name_token(void) { | |
474 token t; | |
475 t.id = NAME; | |
476 t.handle = td << sa; | |
477 --sa; | |
478 if (t.handle <= n_reserved_words) t.id = reserved_words[t.handle].id; | |
479 return t; | |
480 } | |
481 | |
482 /* | |
483 op() creates a token for a punctuation character. | |
484 */ | |
485 | |
486 static token op(unsigned x) { | |
487 token t; | |
488 t.id = (token_id) x; | |
489 t.handle = token_handles[x]; | |
490 return t; | |
491 } | |
492 | |
493 /* | |
494 space_op() creates a token for a space character. Note that a space | |
495 could be a tab, vertical tab, or form feed character as well as a | |
496 blank. | |
497 */ | |
498 | |
499 static token space_op(unsigned x) { | |
500 token t; | |
501 t.id = (token_id) ' '; | |
502 t.handle = token_handles[x]; | |
503 return t; | |
504 } | |
505 | |
506 /* | |
507 tkn() creates a token with a specified id for the string on the top | |
508 of the string accumulator | |
509 */ | |
510 | |
511 static token tkn(token_id id) { | |
512 token t; | |
513 t.id = id; | |
514 t.handle = td << sa; | |
515 --sa; | |
516 return t; | |
517 } | |
518 | |
519 | |
520 // Macro Processing Procedures | |
521 | |
522 /* | |
523 check_defined() looks up the name on the string accumulator to see if | |
524 it is the name of a macro. It then selects a reduction token according | |
525 to the outcome of the test and an input flag. | |
526 */ | |
527 | |
528 static void check_defined(int flag) { | |
529 unsigned id = macro_id[td[sa]]; | |
530 --sa; | |
531 flag ^= id != 0; | |
532 if (flag) CHANGE_REDUCTION(false_condition); | |
533 else CHANGE_REDUCTION(true_condition); | |
534 } | |
535 | |
536 /* | |
537 defined() returns a decimal constant token equal to one or zero | |
538 depending on whether the token named on the string accumulator is or | |
539 is not defined as a macro | |
540 */ | |
541 | |
542 static token defined(void) { | |
543 unsigned id = macro_id[td[sa]]; | |
544 token t; | |
545 t.id = DECconstant; | |
546 t.handle = id ? one_value : zero_value; | |
547 --sa; | |
548 return t; | |
549 } | |
550 | |
551 /* | |
552 expand() expands and outputs a macro. t.handle is the token dictionary | |
553 index of the macro name. n is the number of arguments found. | |
554 | |
555 Since it is possible that scanner sink is pointing to ta, it is | |
556 necessary to pop the expanded macro from ta before passing it on to | |
557 scanner_sink. Otherwise, we would have effectively ta << ta, a | |
558 situation which causes an infinite loop. | |
559 */ | |
560 | |
561 static void expand(token t, unsigned n) { | |
562 error_modifier = " in macro expansion"; // fix error diagnostic | |
563 expand_macro(t,n); // Defined in MAS.SYN | |
564 if (size(ta)) { | |
565 array<token> x(ta,size(ta) + 1); | |
566 --ta; | |
567 *scanner_sink << x; | |
568 } else --ta; | |
569 error_modifier = ""; | |
570 } | |
571 | |
572 /* | |
573 Look up the name string on the string accumulator. Determine whether | |
574 it is a reserved word, or a simple identifier. Then determine | |
575 whether it is the name of a macro. | |
576 */ | |
577 | |
578 static token id_macro(void) { | |
579 token t; | |
580 unsigned id; | |
581 | |
582 t.id = NAME; | |
583 t.handle = td << sa; | |
584 --sa; | |
585 if (t.handle <= n_reserved_words) t.id = reserved_words[t.handle].id; | |
586 | |
587 if (if_clause && t.handle == defined_value) { | |
588 CHANGE_REDUCTION(defined); | |
589 return t; | |
590 } | |
591 id = macro_id[t.handle]; | |
592 if (id == 0) return t; | |
593 | |
594 if (macro[id].parens) CHANGE_REDUCTION(macro); | |
595 else CHANGE_REDUCTION(simple_macro); | |
596 return t; | |
597 } | |
598 | |
599 /* | |
600 Start a macro definition. This procedure defines all but the body of | |
601 the macro. | |
602 | |
603 nargs is the count of parameters that were found. flag is set if | |
604 the macro was defined with parentheses. | |
605 | |
606 The parameter names are on the string accumulator, with the last | |
607 name on the top of the stack, so they must be popped off, identified | |
608 and stored in reverse order. | |
609 | |
610 The name of the macro is beneath the parameter names on the string | |
611 accumulator. | |
612 | |
613 Before returning, this procedure saves the current value of | |
614 scanner_sink, increments the level on the token stack and sets | |
615 scanner_sink so that subsequent tokens produced by the token scanner | |
616 will accumulate on the token stack. These tokens comprise the body | |
617 of the macro. When the end of the macro body is encountered, the | |
618 procedure save_macro_body will remove them from the token stack and | |
619 restore the value of scanner_sink. | |
620 */ | |
621 | |
622 static int init_macro_def(int nargs, int flag) { | |
623 int k; | |
624 int id = ++n_macros; | |
625 unsigned name; | |
626 unsigned *arg_list = nargs ? new unsigned[nargs] : NULL; | |
627 | |
628 assert(id < N_MACROS); | |
629 for (k = nargs; k--;) { | |
630 arg_list[k] = td << sa; | |
631 --sa; | |
632 } | |
633 | |
634 macro[id].arg_names = arg_list; | |
635 macro[id].n_args = nargs; | |
636 | |
637 macro[id].name = name = td << sa; | |
638 --sa; | |
639 | |
640 macro_id[name] = id; | |
641 | |
642 macro[id].busy_flag = 0; | |
643 macro[id].parens = flag ; | |
644 | |
645 save_sink << scanner_sink; | |
646 scanner_sink = &++ta; | |
647 return id; | |
648 } | |
649 | |
650 /* | |
651 save_macro_body() finishes the definition of a macro by making a | |
652 permanent copy of the token string on the token accumulator. It then | |
653 restores the scanner_sink to the value it had when the macro | |
654 definition was encountered. | |
655 */ | |
656 | |
657 static void save_macro_body(int id) { | |
658 macro[id].body = size(ta) ? copy(ta) : NULL; | |
659 --ta; | |
660 save_sink >> scanner_sink; | |
661 } | |
662 | |
663 /* | |
664 undefine() deletes the macro definition for the macro whose name is | |
665 on the top of the string accumulator. If there is no macro with the | |
666 given name, undefine simply returns. | |
667 | |
668 Otherwise, it frees the storage associated with the macro. It then | |
669 fills the resulting hole in the table with the last macro in the | |
670 table. The macro_id table is updated appropriately. | |
671 */ | |
672 | |
673 static void undefine(void) { | |
674 unsigned name = td << sa; | |
675 int id = macro_id[name]; | |
676 --sa; | |
677 if (id == 0) return; | |
678 macro_id[name] = 0; | |
679 if (macro[id].arg_names) delete [] macro[id].arg_names; | |
680 if (macro[id].body) delete [] macro[id].body; | |
681 macro[id] = macro[n_macros--]; | |
682 macro_id[macro[id].name] = id; | |
683 } | |
684 | |
685 | |
686 // Include file procedures | |
687 | |
688 /* | |
689 file_name() interprets the file name provided by an #include | |
690 statement. If the file name is enclosed in <> brackets it scans the | |
691 directory list in paths to try to find the file. If it finds it, it | |
692 prefixes the path to the file name. | |
693 | |
694 If the file name is enclosed in "" quotation marks, file_name() | |
695 simply strips the quotation marks. | |
696 | |
697 If file_name() succeeds, it returns 1 and provides path-name in the | |
698 string accumulator, otherwise it returns 0 and nothing in the string | |
699 accumulator. | |
700 | |
701 Note that file name uses a temporary string accumulator, lsa. | |
702 */ | |
703 | |
704 static int file_name(char *file) { | |
705 int c; | |
706 int tc; | |
707 string_accumulator lsa(100); // for temporary storage of name | |
708 | |
709 while (*file == ' ') file++; | |
710 tc = *file++; | |
711 if (tc == '<') tc = '>'; | |
712 else if (tc != '"') return 0; | |
713 while ((c = *file++) != 0 && c != tc) lsa << c; | |
714 if (c != tc) return 0; | |
715 if (tc == '>') { | |
716 int k, n; | |
717 n = size(paths); | |
718 for (k = 0; k < n; k++) { | |
719 FILE *f; | |
720 ++sa << paths[k]; | |
721 if (sa[0] != '\\' || sa[0] != '/') sa << '/'; | |
722 sa << lsa; | |
723 f = fopen(sa,"rt"); | |
724 if (f != NULL) { | |
725 fclose(f); | |
726 return 1; | |
727 } | |
728 --sa; | |
729 } | |
730 return 0; | |
731 } | |
732 ++sa << lsa; | |
733 return 1; | |
734 } | |
735 | |
736 /* | |
737 include_file() is called in response to a #include statement. | |
738 | |
739 First, it saves the file_descriptor for the current input. Then it | |
740 restores the scanner_sink which was saved prior to accumulating | |
741 macro expanded tokens on the token_accumulator. | |
742 | |
743 When include_file() is called, the argument of the #include | |
744 statement exists in the form of tokens on the token accumulator. | |
745 These tokens are passed to a token_translator which turns the tokens | |
746 into a string on the string accumulator. | |
747 | |
748 file_name() is then called to distinguish between "" and <> files. | |
749 In the latter case, file_name() prefixes a directory path to the name. | |
750 The name is then in the string accumulator. | |
751 | |
752 scan_input() is then called to scan the include file. | |
753 | |
754 Finally, before returning, the previous file_descriptor is restored. | |
755 */ | |
756 | |
757 static void include_file(void) { | |
758 file_descriptor save_input = input; // save input state | |
759 int flag; | |
760 | |
761 save_sink >> scanner_sink; // restore scanner_sink | |
762 | |
763 token_translator tt(&++sa); | |
764 tt << ta; // recover string from tokens | |
765 --ta; // discard token string | |
766 | |
767 array<char> file(sa, size(sa)+1); // local copy of string | |
768 --sa; | |
769 | |
770 flag = file_name(file); | |
771 | |
772 if (!flag) { | |
773 fprintf(stderr, "Bad include file name: %s\n", (char *) file); | |
774 return; | |
775 } | |
776 array<char> path(sa, size(sa) + 1); | |
777 --sa; | |
778 scan_input(path); // recursive call to ts() | |
779 input = save_input; // restore input state | |
780 return; | |
781 } | |
782 | |
783 | |
784 // Conditional compilation procedures | |
785 | |
786 /* | |
787 init_condition() prepares for evaluation the condition expression in | |
788 #if and #elif statements. | |
789 | |
790 It protects scanner_sink by pushing it onto the save_sink stack. | |
791 Then it resets the expression evaluatior, condition, and sets | |
792 scanner_sink to point to it. | |
793 | |
794 Finally it sets the if_clause flag so that defined() will be handled | |
795 properly. | |
796 */ | |
797 | |
798 static void init_condition(void) { | |
799 save_sink << scanner_sink; | |
800 scanner_sink = &reset(condition); | |
801 if_clause = 1; | |
802 } | |
803 | |
804 /* | |
805 eval_condition() is called to deal with #if and #elif statements. The | |
806 init_condition() procedure has redirected scanner output to the | |
807 expression evaluator, so eval_condition() restores the previous | |
808 scanner destination. | |
809 | |
810 It then sends an eof token to the expression evaluator, resets | |
811 if_clause and reads the value of the condition. Remember that | |
812 (long) condition returns the value of the expression. | |
813 */ | |
814 | |
815 static int eval_condition(void) { | |
816 save_sink >> scanner_sink; | |
817 condition << op(0); // eof to exp evaluator | |
818 if_clause = 0; | |
819 return condition != 0L; | |
820 } | |
821 | |
822 /* | |
823 In eval_if() and eval_elif() note the use of CHANGE_REDUCTION to | |
824 select the appropriate reduction token depending on the outcome of | |
825 the condition. | |
826 */ | |
827 | |
828 static void eval_elif(void) { | |
829 if (eval_condition()) CHANGE_REDUCTION(true_else_condition); | |
830 else CHANGE_REDUCTION(false_else_condition); | |
831 } | |
832 | |
833 static void eval_if(void) { | |
834 if (eval_condition()) CHANGE_REDUCTION(true_condition); | |
835 else CHANGE_REDUCTION(false_condition); | |
836 } | |
837 | |
838 | |
839 // Do token scan | |
840 | |
841 /* | |
842 scan_input() | |
843 1) opens the specified file, if possible | |
844 2) calls the parser | |
845 3) closes the input file | |
846 */ | |
847 | |
848 void scan_input(char *path) { | |
849 input.file = fopen(path, "rt"); | |
850 input.name = path; | |
851 if (input.file == NULL) { | |
852 fprintf(stderr,"Cannot open %s\n", (char *) path); | |
853 return; | |
854 } | |
855 ts(); | |
856 fclose(input.file); | |
857 } | |
858 | |
859 } // End of Embedded C |