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