Mercurial > ~dholland > hg > ag > index.cgi
comparison tests/agcl/oldagsrc/mas.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 | |
5 | |
6 Copyright (c) 1993, Parsifal Software. | |
7 All Rights Reserved. | |
8 | |
9 Macro argument substitution module | |
10 */ | |
11 | |
12 #include "mpp.h" | |
13 | |
14 } | |
15 | |
16 | |
17 // Configuration Section | |
18 | |
19 [ | |
20 ~allow macros | |
21 line numbers | |
22 pointer input | |
23 pointer type = token * | |
24 input values | |
25 ~error frame | |
26 error trace | |
27 ~lines and columns | |
28 ~backtrack | |
29 ~test range | |
30 default input type = token | |
31 ~declare pcb | |
32 subgrammar { | |
33 parse unit | |
34 } | |
35 enum { | |
36 eof =0, | |
37 SPACE =' ', | |
38 ANDAND ='A', // "&&" | |
39 ANDassign, // "&=" | |
40 ARROW, // "->" | |
41 CONCAT, // "##" | |
42 DECR, // "--" | |
43 DIVassign, // "/=" | |
44 ELLIPSIS, // "..." | |
45 EQ, // "==" | |
46 ERassign, // "^=" | |
47 GE, // ">=" | |
48 ICR, // "++" | |
49 LE, // "<=" | |
50 LS, // "<<" | |
51 LSassign, // "<<=" | |
52 MODassign, // "%=" | |
53 MINUSassign, // "-=" | |
54 MULTassign, // "*=" | |
55 NE, // "!=" | |
56 ORassign, // "|=" | |
57 OROR, // "||" | |
58 PLUSassign, // "+=" | |
59 RS, // ">>" | |
60 RSassign, // ">>=" | |
61 CHARACTERconstant, // character constant | |
62 STRINGliteral, // character string | |
63 HEXconstant =129, | |
64 OCTconstant, | |
65 DECconstant, | |
66 FLOATconstant, // real | |
67 NAME, | |
68 AUTO, // "auto" | |
69 BREAK, // "break" | |
70 CASE, // "case" | |
71 CHAR, // "char" | |
72 CONSTANT, // "const" | |
73 CONTINUE, // "continue" | |
74 DEFAULT, // "default" | |
75 DO, // "do" | |
76 DOUBLE, // "double" | |
77 ELSE, // "else" | |
78 ENUM, // "enum" | |
79 EXTERN, // "extern" | |
80 FLOAT, // "float" | |
81 FOR, // "for" | |
82 GOTO, // "goto" | |
83 IF, // "if" | |
84 INT, // "int" | |
85 LONG, // "long" | |
86 REGISTER, // "register" | |
87 RETURN, // "return" | |
88 SHORT, // "short" | |
89 SIGNED, // "signed" | |
90 SIZEOF, // "sizeof" | |
91 STATIC, // "static" | |
92 STRUCT, // "struct" | |
93 SWITCH, // "switch" | |
94 TYPEDEF, // "typedef" | |
95 UNION, // "union" | |
96 UNSIGNED, // "unsigned" | |
97 VOIDkey, // "void" | |
98 VOLATILE, // "volatile" | |
99 WHILE, // "while" | |
100 UNRECOGNIZED, | |
101 } | |
102 parser file name = "#.cpp" | |
103 ] | |
104 | |
105 grammar | |
106 ->space, parse unit?..., eof | |
107 | |
108 | |
109 // Accumulate optional space | |
110 | |
111 space | |
112 -> =reset(space_stack); | |
113 -> space, ' ':s ={if (args_only) space_stack << s;} | |
114 | |
115 | |
116 // Basic parse units | |
117 | |
118 parse unit | |
119 -> parameter expansion | |
120 -> simple parse unit, space =ta << space_stack; | |
121 -> concatenation, space =ta << space_stack; | |
122 -> macro:t, space =ta << t << space_stack; | |
123 | |
124 simple parse unit | |
125 -> ~eof - NAME - CONCAT - '#'- ' ':t =ta << t; | |
126 -> '#', parameter name:n =ta << make_string(n.handle); | |
127 -> variable:t =ta << t; | |
128 -> simple macro:t =expand_macro(t,0), concat(ta); | |
129 -> macro:t, space, '(', macro arg list:n, ')' =expand_macro(t,n), concat(ta); | |
130 -> defined, macro name:n =ta << defined(n.handle); | |
131 | |
132 (token) macro name | |
133 -> space, NAME:n =n; | |
134 -> space, '(', space, NAME:n, space, ')' =n; | |
135 | |
136 (token) variable, parameter name, simple macro, macro, defined | |
137 -> NAME:n =id_macro(n); | |
138 | |
139 parameter expansion | |
140 -> parameter name:name, space =expand_arg(name.handle), ta << space_stack; | |
141 | |
142 | |
143 // Implementation of "##" operator | |
144 | |
145 concatenation | |
146 -> left side, space, | |
147 parameter name:name =ta << args[name.handle], concatenate(); | |
148 -> left side, space, right side =concatenate(); | |
149 | |
150 left side | |
151 -> parameter name:n, space, CONCAT =ta << args[n.handle], ++ta; | |
152 -> simple parse unit, space, CONCAT =++ta; | |
153 -> macro:t, space, CONCAT =ta << t, ++ta; | |
154 -> concatenation, space, CONCAT =++ta; | |
155 | |
156 right side | |
157 -> ~eof - NAME - CONCAT - '#'- ' ':t =ta << t; | |
158 -> '#', parameter name:n =ta << make_string(n.handle); | |
159 -> not parameter:t =ta << t; | |
160 | |
161 (token) not parameter | |
162 -> variable | |
163 -> simple macro | |
164 -> macro | |
165 -> defined | |
166 | |
167 | |
168 // Gather Macro Arguments | |
169 | |
170 (int) macro arg list | |
171 -> space = 0; | |
172 -> space, arg elements = 1; | |
173 -> macro arg list:n, ',', space, arg elements =n+1; | |
174 | |
175 initial arg element | |
176 -> ~eof - ',' - '(' - ')' - SPACE:t =++ta << t; | |
177 -> nested elements, ')':t =ta << t; | |
178 | |
179 arg element | |
180 -> ~eof - ',' - '(' - ')':t =ta << t; | |
181 -> nested elements, ')':t =concat(ta) << t; | |
182 | |
183 arg elements | |
184 -> initial arg element | |
185 -> arg elements, arg element | |
186 | |
187 nested elements | |
188 -> '(':t =++ta << t; | |
189 -> nested elements, arg element | |
190 -> nested elements, ',':t =ta << t; | |
191 | |
192 | |
193 { // Embedded C | |
194 #include "array.h" // AnaGram\CLASSLIB\INCLUDE\array.h | |
195 #include "stack.h" // AnaGram\CLASSLIB\INCLUDE\stack.h | |
196 | |
197 | |
198 // Macro Definitions | |
199 | |
200 #define INPUT_CODE(T) (T).id | |
201 #define PCB (*mas_pcb) | |
202 #define SYNTAX_ERROR syntax_error(PCB.error_message); | |
203 | |
204 | |
205 // Static variables | |
206 | |
207 static stack<unsigned> active_macros(200,20); | |
208 static token **args; | |
209 static int args_only = 0; | |
210 static mas_pcb_type *mas_pcb; | |
211 static int n_concats = 0; | |
212 static int n_args; | |
213 static unsigned *params; | |
214 static token_accumulator space_stack(100); | |
215 | |
216 | |
217 /* | |
218 | |
219 expand_text() is a shell procedure which calls the mas parser a | |
220 number of times. It is used to expand arguments before substituting | |
221 them into a macro, and to expand the body of a macro. Notice that | |
222 expand_text() is recursive, since macros encountered during the an | |
223 expansion process may themselves need to be expanded. | |
224 | |
225 expand_text() takes three explicit arguments: | |
226 token *text: | |
227 points to a string of tokens, terminated by an eof token. | |
228 | |
229 int n: | |
230 specifies the number of arguments. Defaults to 0. The arguments | |
231 themselves are token strings on the token accumulator stack. | |
232 expand_text() makes copies of them and stores pointers to them in | |
233 the args array. | |
234 | |
235 unsigned *p: | |
236 An array of n dictionary indices which gives the names of the | |
237 parameters for which the arguments are to be substituted. p | |
238 defaults to NULL. | |
239 | |
240 global switches | |
241 Two global switches affect the expansion of text: if_clause and | |
242 args_only. Setting if_clause affects the treatment of the token | |
243 "defined". Setting args_only causes only macro parameters to be | |
244 expanded. | |
245 | |
246 */ | |
247 | |
248 void expand_text(token *text, int n, unsigned *p) { | |
249 mas_pcb_type pcb; | |
250 | |
251 // Save old status | |
252 mas_pcb_type *save_pcb = mas_pcb; | |
253 int save_n_args = n_args; | |
254 token **save_args = args; | |
255 unsigned *save_params = params; | |
256 int save_switch = args_only; | |
257 | |
258 // pop args from accumlator stack and expand them | |
259 args_only = 0; | |
260 token **new_args; | |
261 int k = n; | |
262 if (n) { | |
263 new_args = new token*[n]; | |
264 args_only = 1; | |
265 while (k--) { | |
266 token t; | |
267 while (ta[0].id == SPACE) ta >> t; //trim space on right | |
268 array<token> arg_tokens(ta, size(ta) + 1); | |
269 token *tp = arg_tokens; | |
270 while (tp->id == SPACE) tp++; //trim space on left | |
271 --ta; | |
272 mas_pcb = &pcb; | |
273 pcb.pointer = tp; | |
274 ++ta; | |
275 mas(); | |
276 new_args[k] = copy(ta); | |
277 --ta; | |
278 } | |
279 args_only = 0; | |
280 } | |
281 else new_args = NULL; | |
282 | |
283 // Expand text | |
284 args = new_args; | |
285 n_args = n; | |
286 params = p; | |
287 pcb.pointer = text; | |
288 mas_pcb = &pcb; | |
289 ++ta; | |
290 ++active_macros; | |
291 n_concats = 0; | |
292 mas(); | |
293 | |
294 // If any new tokens were created by concatenation, rescan | |
295 while (n_concats) { | |
296 array<token> expansion(ta,size(ta) + 1); | |
297 --ta; | |
298 pcb.pointer = expansion; | |
299 ++ta; | |
300 n_concats = 0; | |
301 n = size(active_macros); | |
302 while (n--) macro[active_macros[n]].busy_flag = 1; | |
303 mas(); | |
304 } | |
305 n = size(active_macros); | |
306 while (n--) macro[active_macros[n]].busy_flag = 0; | |
307 --active_macros; | |
308 | |
309 // Discard argument strings | |
310 | |
311 n = n_args; | |
312 while (n--) delete [] args[n]; | |
313 if (n_args) delete [] args; | |
314 | |
315 // Restore old status | |
316 | |
317 args_only = save_switch; | |
318 args = save_args; | |
319 n_args = save_n_args; | |
320 params = save_params; | |
321 mas_pcb = save_pcb; | |
322 } | |
323 | |
324 /* | |
325 | |
326 expand_macro() is a shell procedure which sets up a call to | |
327 expand_text for a specific macro. | |
328 | |
329 */ | |
330 | |
331 void expand_macro(token t, unsigned n_args) { | |
332 unsigned id = macro_id[t.handle]; | |
333 token *body = macro[id].body; | |
334 assert(n_args == macro[id].n_args); | |
335 if (body == NULL) { | |
336 while (n_args--) --ta; | |
337 ++ta; | |
338 return; | |
339 } | |
340 expand_text(body,n_args,macro[id].arg_names); | |
341 } | |
342 | |
343 /* | |
344 | |
345 expand_arg() is another shell procedure for expand_text() which does | |
346 a complete expansion of a single macro argument. | |
347 | |
348 */ | |
349 | |
350 static void expand_arg(unsigned n) { | |
351 expand_text(args[n]); | |
352 concat(ta); | |
353 } | |
354 | |
355 /* | |
356 | |
357 id_macro() is very nearly the same as id_macro() in TS.SYN. The | |
358 primary difference is that this one deals in tokens, the other in | |
359 character strings. | |
360 | |
361 */ | |
362 | |
363 static token id_macro(token t) { | |
364 unsigned n = n_args; | |
365 unsigned id; | |
366 | |
367 while (n--) if (t.handle == params[n]) { | |
368 CHANGE_REDUCTION(parameter_name); | |
369 t.handle = n; | |
370 return t; | |
371 } | |
372 if (args_only) return t; | |
373 if (if_clause && t.handle == defined_value) { | |
374 CHANGE_REDUCTION(defined); | |
375 return t; | |
376 } | |
377 id = macro_id[t.handle]; | |
378 if (id == 0) return t; | |
379 if (macro[id].busy_flag) return t; | |
380 active_macros << id; | |
381 if (macro[id].parens) CHANGE_REDUCTION(macro); | |
382 else CHANGE_REDUCTION(simple_macro); | |
383 return t; | |
384 } | |
385 | |
386 /* | |
387 | |
388 defined() is very nearly the same as defined() in TS.SYN. The primary | |
389 difference is that this one deals in tokens, the other in character | |
390 strings. | |
391 | |
392 */ | |
393 | |
394 static token defined(unsigned handle) { | |
395 token t; | |
396 t.id = DECconstant; | |
397 t.handle = macro_id[handle] ? one_value : zero_value; | |
398 return t; | |
399 } | |
400 | |
401 /* | |
402 | |
403 concatenate() implements the splicing together of two tokens by the | |
404 "##" operator in a macro definition. Because of the way the grammar | |
405 has been written, spaces have already been trimmed on both sides of the | |
406 ## by the parser. | |
407 | |
408 If there are actually two tokens to concatenate, the last token on | |
409 the left is popped off, its string value is obtained from the token | |
410 dictionary and pushed onto the string accumulator, ditto for the | |
411 first token on the right. The string is then identified and the token | |
412 is classified. If the new token is the name of a macro, a new scan | |
413 will be required to expand it. | |
414 | |
415 */ | |
416 | |
417 static void concatenate(void) { | |
418 array<token> right_arg(ta, size(ta) + 1); | |
419 token t; | |
420 token *tp = right_arg; | |
421 | |
422 --ta; // discard right argument from stack | |
423 | |
424 if (size(ta) && tp->id != END_OF_FILE) { | |
425 ta >> t; // pop left token | |
426 ++sa << td[t.handle] << td[tp->handle]; // left string + right string | |
427 t.handle = td << sa; // identify string | |
428 t.id = classify_token(sa); // classify token | |
429 --sa; // discard string | |
430 ++tp; // discard old token on right | |
431 if (macro_id[t.handle]) n_concats++; // if macro, signal rescan | |
432 ta << t; // output new token | |
433 } | |
434 ta << tp; // remainder of right side | |
435 } | |
436 | |
437 /* | |
438 | |
439 make_string() implements the '#' operator in macro expansions, that | |
440 is, it turns its operand into a string constant. To do this it must | |
441 provide "" marks and must quote any embedded " or \ characters with | |
442 the \ character. | |
443 | |
444 */ | |
445 | |
446 static token make_string(unsigned n) { | |
447 token *tp; | |
448 token t; | |
449 | |
450 tp = args[n]; | |
451 ++sa << '"'; | |
452 while (tp->id != END_OF_FILE) { | |
453 char *p = td[tp->handle]; | |
454 char c; | |
455 while ((c = *p++) != 0) { | |
456 if (c == '"' || c == '\\') sa << '\\'; | |
457 sa << c; | |
458 } | |
459 tp++; | |
460 } | |
461 sa << '"'; | |
462 t.id = STRINGliteral; | |
463 t.handle = td << sa; | |
464 --sa; | |
465 return t; | |
466 } | |
467 | |
468 } // End of Embedded C |