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