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