]>
Commit | Line | Data |
---|---|---|
3eb9473e | 1 | /*\r |
2 | * PCCTSAST.C\r | |
3 | *\r | |
4 | * SOFTWARE RIGHTS\r | |
5 | *\r | |
6 | * We reserve no LEGAL rights to SORCERER -- SORCERER is in the public\r | |
7 | * domain. An individual or company may do whatever they wish with\r | |
8 | * source code distributed with SORCERER or the code generated by\r | |
9 | * SORCERER, including the incorporation of SORCERER, or its output, into\r | |
10 | * commerical software.\r | |
11 | *\r | |
12 | * We encourage users to develop software with SORCERER. However, we do\r | |
13 | * ask that credit is given to us for developing SORCERER. By "credit",\r | |
14 | * we mean that if you incorporate our source code into one of your\r | |
15 | * programs (commercial product, research project, or otherwise) that you\r | |
16 | * acknowledge this fact somewhere in the documentation, research report,\r | |
17 | * etc... If you like SORCERER and have developed a nice tool with the\r | |
18 | * output, please mention that you developed it using SORCERER. In\r | |
19 | * addition, we ask that this header remain intact in our source code.\r | |
20 | * As long as these guidelines are kept, we expect to continue enhancing\r | |
21 | * this system and expect to make other tools available as they are\r | |
22 | * completed.\r | |
23 | *\r | |
24 | * SORCERER 1.00B14 and ANTLR 1.33\r | |
25 | * Terence Parr\r | |
26 | * Parr Research Corporation\r | |
27 | * AHPCRC, University of Minnesota\r | |
28 | * 1992-1998\r | |
29 | */\r | |
30 | \r | |
31 | #define ANTLR_SUPPORT_CODE\r | |
32 | \r | |
33 | #include "pcctscfg.h"\r | |
34 | \r | |
35 | #include "PCCTSAST.h"\r | |
36 | #include "pccts_stdarg.h"\r | |
37 | \r | |
38 | PCCTS_NAMESPACE_STD\r | |
39 | \r | |
40 | #include <ctype.h>\r | |
41 | \r | |
42 | //#include "SList.h"\r | |
43 | \r | |
44 | /* String Scanning/Parsing Stuff */\r | |
45 | \r | |
46 | const char *PCCTS_AST::scan_token_tbl[] = { /* MR20 const */\r | |
47 | "invalid", /* 0 */\r | |
48 | "LPAREN", /* 1 */\r | |
49 | "RPAREN", /* 2 */\r | |
50 | "PERCENT", /* 3 */\r | |
51 | "INT", /* 4 */\r | |
52 | "COLON", /* 5 */\r | |
53 | "POUND", /* 6 */\r | |
54 | "PERIOD", /* 7 */\r | |
55 | };\r | |
56 | \r | |
57 | void PCCTS_AST::\r | |
58 | addChild(PCCTS_AST *t)\r | |
59 | {\r | |
60 | if ( t==NULL ) return;\r | |
61 | PCCTS_AST *s = down();\r | |
62 | if ( s!=NULL )\r | |
63 | {\r | |
64 | while ( s->right()!=NULL ) s = s->right();\r | |
65 | s->setRight(t);\r | |
66 | }\r | |
67 | else\r | |
68 | this->setDown(t);\r | |
69 | }\r | |
70 | \r | |
71 | void PCCTS_AST::\r | |
72 | lisp(FILE *f)\r | |
73 | {\r | |
74 | if ( down() != NULL ) fprintf(f," (");\r | |
75 | lisp_action(f);\r | |
76 | if ( down()!=NULL ) down()->lisp(f);\r | |
77 | if ( down() != NULL ) fprintf(f," )");\r | |
78 | if ( right()!=NULL ) right()->lisp(f);\r | |
79 | }\r | |
80 | \r | |
81 | /* build a tree (root child1 child2 ... NULL)\r | |
82 | * If root is NULL, simply make the children siblings and return ptr\r | |
83 | * to 1st sibling (child1). If root is not single node, return NULL.\r | |
84 | *\r | |
85 | * Siblings that are actually sibling lists themselves are handled\r | |
86 | * correctly. For example #( NULL, #( NULL, A, B, C), D) results\r | |
87 | * in the tree ( NULL A B C D ).\r | |
88 | *\r | |
89 | * Requires at least two parameters with the last one being NULL. If\r | |
90 | * both are NULL, return NULL.\r | |
91 | *\r | |
92 | * The down() and right() down/right pointers are used to make the tree.\r | |
93 | */\r | |
94 | PCCTS_AST *PCCTS_AST::\r | |
95 | make(PCCTS_AST *rt, ...)\r | |
96 | {\r | |
97 | va_list ap;\r | |
98 | register PCCTS_AST *child, *sibling=NULL, *tail, *w;\r | |
99 | PCCTS_AST *root;\r | |
100 | \r | |
101 | va_start(ap, rt);\r | |
102 | root = rt;\r | |
103 | \r | |
104 | if ( root != NULL )\r | |
105 | if ( root->down() != NULL ) return NULL;\r | |
106 | child = va_arg(ap, PCCTS_AST *);\r | |
107 | while ( child != NULL )\r | |
108 | {\r | |
109 | /* find end of child */\r | |
110 | for (w=child; w->right()!=NULL; w=w->right()) {;}\r | |
111 | if ( sibling == NULL ) {sibling = child; tail = w;}\r | |
112 | else {tail->setRight(child); tail = w;}\r | |
113 | child = va_arg(ap, PCCTS_AST *);\r | |
114 | }\r | |
115 | if ( root==NULL ) root = sibling;\r | |
116 | else root->setDown(sibling);\r | |
117 | va_end(ap);\r | |
118 | return root;\r | |
119 | }\r | |
120 | \r | |
121 | /* The following push and pop routines are only used by ast_find_all() */\r | |
122 | \r | |
123 | void PCCTS_AST::\r | |
124 | _push(PCCTS_AST **st, int *sp, PCCTS_AST *e)\r | |
125 | {\r | |
126 | (*sp)--;\r | |
127 | require((*sp)>=0, "stack overflow");\r | |
128 | st[(*sp)] = e;\r | |
129 | }\r | |
130 | \r | |
131 | PCCTS_AST *PCCTS_AST::\r | |
132 | _pop(PCCTS_AST **st, int *sp)\r | |
133 | {\r | |
134 | PCCTS_AST *e = st[*sp];\r | |
135 | (*sp)++;\r | |
136 | require((*sp)<=MaxTreeStackDepth, "stack underflow");\r | |
137 | return e;\r | |
138 | }\r | |
139 | \r | |
140 | /* Find all occurrences of u in t.\r | |
141 | * 'cursor' must be initialized to 't'. It eventually\r | |
142 | * returns NULL when no more occurrences of 'u' are found.\r | |
143 | */\r | |
144 | PCCTS_AST *PCCTS_AST::\r | |
145 | ast_find_all(PCCTS_AST *u, PCCTS_AST **cursor)\r | |
146 | {\r | |
147 | PCCTS_AST *sib;\r | |
148 | static PCCTS_AST *template_stack[MaxTreeStackDepth];\r | |
149 | static int tsp = MaxTreeStackDepth;\r | |
150 | static int nesting = 0;\r | |
151 | \r | |
152 | if ( *cursor == NULL ) return NULL;\r | |
153 | if ( *cursor!=this ) sib = *cursor;\r | |
154 | else {\r | |
155 | /* else, first time--start at top of template 't' */\r | |
156 | tsp = MaxTreeStackDepth;\r | |
157 | sib = this;\r | |
158 | /* bottom of stack is always a NULL--"cookie" indicates "done" */\r | |
159 | _push(template_stack, &tsp, NULL);\r | |
160 | }\r | |
161 | \r | |
162 | keep_looking:\r | |
163 | if ( sib==NULL ) /* hit end of sibling list */\r | |
164 | {\r | |
165 | sib = _pop(template_stack, &tsp);\r | |
166 | if ( sib == NULL ) { *cursor = NULL; return NULL; }\r | |
167 | }\r | |
168 | \r | |
169 | if ( sib->type() != u->type() )\r | |
170 | {\r | |
171 | /* look for another match */\r | |
172 | if ( sib->down()!=NULL )\r | |
173 | {\r | |
174 | if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right());\r | |
175 | sib=sib->down();\r | |
176 | goto keep_looking;\r | |
177 | }\r | |
178 | /* nothing below to try, try next sibling */\r | |
179 | sib=sib->right();\r | |
180 | goto keep_looking;\r | |
181 | }\r | |
182 | \r | |
183 | /* found a matching root node, try to match what's below */\r | |
184 | if ( match_partial(sib, u) )\r | |
185 | {\r | |
186 | /* record sibling cursor so we can pick up next from there */\r | |
187 | if ( sib->down()!=NULL )\r | |
188 | {\r | |
189 | if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right());\r | |
190 | *cursor = sib->down();\r | |
191 | }\r | |
192 | else if ( sib->right()!=NULL ) *cursor = sib->right();\r | |
193 | else *cursor = _pop(template_stack, &tsp);\r | |
194 | return sib;\r | |
195 | }\r | |
196 | \r | |
197 | /* no match, keep searching */\r | |
198 | if ( sib->down()!=NULL )\r | |
199 | {\r | |
200 | if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right());\r | |
201 | sib=sib->down();\r | |
202 | }\r | |
203 | else sib = sib->right(); /* else, try to right if zip below */\r | |
204 | goto keep_looking;\r | |
205 | }\r | |
206 | \r | |
207 | /* are two trees exactly alike? */\r | |
208 | int PCCTS_AST::\r | |
209 | match(PCCTS_AST *u)\r | |
210 | {\r | |
211 | PCCTS_AST *t = this;\r | |
212 | PCCTS_AST *sib;\r | |
213 | \r | |
214 | if ( u==NULL ) return 0;\r | |
215 | \r | |
216 | for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right())\r | |
217 | {\r | |
218 | if ( sib->type() != u->type() ) return 0;\r | |
219 | if ( sib->down()!=NULL )\r | |
220 | if ( !sib->down()->match(u->down()) ) return 0;\r | |
221 | }\r | |
222 | return 1;\r | |
223 | }\r | |
224 | \r | |
225 | /* Is 'u' a subtree of 't' beginning at the root? */\r | |
226 | int PCCTS_AST::\r | |
227 | match_partial(PCCTS_AST *t, PCCTS_AST *u)\r | |
228 | {\r | |
229 | PCCTS_AST *sib;\r | |
230 | \r | |
231 | if ( u==NULL ) return 1;\r | |
232 | if ( t==NULL ) if ( u!=NULL ) return 0; else return 1;\r | |
233 | \r | |
234 | for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right())\r | |
235 | {\r | |
236 | if ( sib->type() != u->type() ) return 0;\r | |
237 | if ( sib->down()!=NULL )\r | |
238 | if ( !match_partial(sib->down(), u->down()) ) return 0;\r | |
239 | }\r | |
240 | return 1;\r | |
241 | }\r | |
242 | \r | |
243 | /* Walk the template tree 't' (matching against 'this'), filling in the\r | |
244 | * 'labels' array, and setting 'n' according to how many labels were matched.\r | |
245 | */\r | |
246 | int PCCTS_AST::\r | |
247 | scanmatch(ScanAST *t, PCCTS_AST **labels[], int *n)\r | |
248 | {\r | |
249 | ScanAST *sib;\r | |
250 | PCCTS_AST *u = this;\r | |
251 | \r | |
252 | if ( u==NULL ) return 0;\r | |
253 | \r | |
254 | for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right())\r | |
255 | {\r | |
256 | /* make sure tokens match; token of '0' means wildcard match */\r | |
257 | if ( sib->type() != u->type() && sib->type()!=0 ) return 0;\r | |
258 | /* we have a matched token here; set label pointers if exists */\r | |
259 | if ( sib->label_num>0 )\r | |
260 | {\r | |
261 | require(labels!=NULL, "label found in template, but no array of labels");\r | |
262 | (*n)++;\r | |
263 | *(labels[sib->label_num-1]) = u;\r | |
264 | }\r | |
265 | /* match what's below if something there and current node is not wildcard */\r | |
266 | if ( sib->down()!=NULL && sib->type()!=0 )\r | |
267 | {\r | |
268 | if ( sib->down()==NULL ) if ( u->down()!=NULL ) return 0; else return 1;\r | |
269 | if ( !u->down()->scanmatch(sib->down(), labels, n) ) return 0;\r | |
270 | }\r | |
271 | }\r | |
272 | return 1;\r | |
273 | }\r | |
274 | \r | |
275 | void PCCTS_AST::\r | |
276 | insert_after(PCCTS_AST *b)\r | |
277 | {\r | |
278 | PCCTS_AST *end;\r | |
279 | if ( b==NULL ) return;\r | |
280 | /* find end of b's child list */\r | |
281 | for (end=b; end->right()!=NULL; end=end->right()) {;}\r | |
282 | end->setRight(this->right());\r | |
283 | this->setRight(b);\r | |
284 | }\r | |
285 | \r | |
286 | void PCCTS_AST::\r | |
287 | append(PCCTS_AST *b)\r | |
288 | {\r | |
289 | PCCTS_AST *end;\r | |
290 | require(b!=NULL, "append: NULL input tree");\r | |
291 | /* find end of child list */\r | |
292 | for (end=this; end->right()!=NULL; end=end->right()) {;}\r | |
293 | end->setRight(b);\r | |
294 | }\r | |
295 | \r | |
296 | PCCTS_AST *PCCTS_AST::\r | |
297 | tail()\r | |
298 | {\r | |
299 | PCCTS_AST *end;\r | |
300 | /* find end of child list */\r | |
301 | for (end=this; end->right()!=NULL; end=end->right()) {;}\r | |
302 | return end;\r | |
303 | }\r | |
304 | \r | |
305 | PCCTS_AST *PCCTS_AST::\r | |
306 | bottom()\r | |
307 | {\r | |
308 | PCCTS_AST *end;\r | |
309 | /* find end of child list */\r | |
310 | for (end=this; end->down()!=NULL; end=end->down()) {;}\r | |
311 | return end;\r | |
312 | }\r | |
313 | \r | |
314 | PCCTS_AST *PCCTS_AST::\r | |
315 | cut_between(PCCTS_AST *a, PCCTS_AST *b)\r | |
316 | {\r | |
317 | PCCTS_AST *end, *ret;\r | |
318 | if (a==NULL||b==NULL) return NULL;\r | |
319 | /* find node pointing to b */\r | |
320 | for (end=a; end->right()!=NULL&&end->right()!=b; end=end->right())\r | |
321 | {;}\r | |
322 | if (end->right()==NULL) return NULL; //ast_cut_between: a,b not connected\r | |
323 | end->setRight(NULL); /* don't want it point to 'b' anymore */\r | |
324 | ret = a->right();\r | |
325 | a->setRight(b);\r | |
326 | return ret;\r | |
327 | }\r | |
328 | \r | |
329 | #ifdef NOT_YET\r | |
330 | SList *PCCTS_AST::\r | |
331 | to_slist()\r | |
332 | {\r | |
333 | SList *list = new SList;\r | |
334 | PCCTS_AST *p;\r | |
335 | \r | |
336 | for (p=this; p!=NULL; p=p->right())\r | |
337 | {\r | |
338 | list->add(p);\r | |
339 | }\r | |
340 | return list;\r | |
341 | }\r | |
342 | #endif\r | |
343 | \r | |
344 | void PCCTS_AST::\r | |
345 | tfree()\r | |
346 | {\r | |
347 | PCCTS_AST *t = this;\r | |
348 | if ( t->down()!=NULL ) t->down()->tfree();\r | |
349 | if ( t->right()!=NULL ) t->right()->tfree();\r | |
350 | delete t;\r | |
351 | }\r | |
352 | \r | |
353 | int PCCTS_AST::\r | |
354 | nsiblings()\r | |
355 | {\r | |
356 | PCCTS_AST *t = this;\r | |
357 | int n=0;\r | |
358 | \r | |
359 | while ( t!=NULL )\r | |
360 | {\r | |
361 | n++;\r | |
362 | t = t->right();\r | |
363 | }\r | |
364 | return n;\r | |
365 | }\r | |
366 | \r | |
367 | PCCTS_AST *PCCTS_AST::\r | |
368 | sibling_index(int i)\r | |
369 | {\r | |
370 | PCCTS_AST *t = this;\r | |
371 | int j=1;\r | |
372 | require(i>0, "sibling_index: i<=0");\r | |
373 | \r | |
374 | while ( t!=NULL )\r | |
375 | {\r | |
376 | if ( j==i ) return t;\r | |
377 | j++;\r | |
378 | t = t->right();\r | |
379 | }\r | |
380 | return NULL;\r | |
381 | }\r | |
382 | \r | |
383 | /* Assume this is a root node of a tree--\r | |
384 | * duplicate that node and what's below; ignore siblings of root node.\r | |
385 | */\r | |
386 | \r | |
387 | // MR9 23-Sep-97 RJV\r | |
388 | // MR9\r | |
389 | // MR9 RJV: Original version only duplicated the node and down elements.\r | |
390 | // MR9 Made copies of the pointers to sibling.\r | |
391 | // MR9 Changed call "down()->deepCopy()" to "down()->deepCopyBushy()"\r | |
392 | // MR9\r | |
393 | \r | |
394 | PCCTS_AST *PCCTS_AST::\r | |
395 | deepCopy()\r | |
396 | {\r | |
397 | PCCTS_AST *u = this->shallowCopy();\r | |
398 | if ( down()!=NULL ) u->setDown(down()->deepCopyBushy());\r | |
399 | u->setRight(NULL);\r | |
400 | return u;\r | |
401 | }\r | |
402 | \r | |
403 | /* Copy all nodes including siblings of root. */\r | |
404 | PCCTS_AST *PCCTS_AST::\r | |
405 | deepCopyBushy()\r | |
406 | {\r | |
407 | PCCTS_AST *u = this->shallowCopy();\r | |
408 | /* copy the rest of the tree */\r | |
409 | if ( down()!=NULL ) u->setDown(down()->deepCopyBushy());\r | |
410 | if ( right()!=NULL ) u->setRight(right()->deepCopyBushy());\r | |
411 | return u;\r | |
412 | }\r | |
413 | \r | |
414 | void PCCTS_AST::\r | |
415 | scanast_free(ScanAST *t)\r | |
416 | {\r | |
417 | if ( t == NULL ) return;\r | |
418 | scanast_free( t->down() );\r | |
419 | scanast_free( t->right() );\r | |
420 | free( (char *) t ); // MR1\r | |
421 | }\r | |
422 | \r | |
423 | /*\r | |
424 | * scan\r | |
425 | *\r | |
426 | * This function is like scanf(): it attempts to match a template\r | |
427 | * against an input tree. A variable number of tree pointers\r | |
428 | * may be set according to the '%i' labels in the template string.\r | |
429 | * For example:\r | |
430 | *\r | |
431 | * t->ast_scan("#( 6 #(5 %1:4 %2:3) #(1 %3:3 %4:3) )",\r | |
432 | * &w, &x, &y, &z);\r | |
433 | *\r | |
434 | * Naturally, you'd want this converted from\r | |
435 | *\r | |
436 | * t->ast_scan("#( RangeOp #(Minus %1:IConst %2:Var) #(Plus %3:Var %4Var) )",\r | |
437 | * &w, &x, &y, &z);\r | |
438 | *\r | |
439 | * by SORCERER.\r | |
440 | *\r | |
441 | * This function call must be done withing a SORCERER file because SORCERER\r | |
442 | * must convert the token references to the associated token number.\r | |
443 | *\r | |
444 | * This functions parses the template and creates trees which are then\r | |
445 | * matched against the input tree. The labels are set as they are\r | |
446 | * encountered; hence, partial matches may leave some pointers set\r | |
447 | * and some NULL. This routines initializes all argument pointers to NULL\r | |
448 | * at the beginning.\r | |
449 | *\r | |
450 | * This function returns the number of labels matched.\r | |
451 | */\r | |
452 | int PCCTS_AST::\r | |
453 | ast_scan(char *templ, ...)\r | |
454 | {\r | |
455 | va_list ap;\r | |
456 | ScanAST *tmpl;\r | |
457 | int n, i, found=0;\r | |
458 | PCCTS_AST ***label_ptrs=NULL;\r | |
459 | \r | |
460 | va_start(ap, templ);\r | |
461 | \r | |
462 | /* make a ScanAST tree out of the template */\r | |
463 | tmpl = stringparser_parse_scanast(templ, &n);\r | |
464 | \r | |
465 | /* make an array out of the labels */\r | |
466 | if ( n>0 )\r | |
467 | {\r | |
468 | label_ptrs = (PCCTS_AST ***) calloc(n, sizeof(PCCTS_AST **));\r | |
469 | require(label_ptrs!=NULL, "scan: out of memory");\r | |
470 | for (i=1; i<=n; i++)\r | |
471 | {\r | |
472 | label_ptrs[i-1] = va_arg(ap, PCCTS_AST **);\r | |
473 | *(label_ptrs[i-1]) = NULL;\r | |
474 | }\r | |
475 | }\r | |
476 | \r | |
477 | /* match the input tree against the template */\r | |
478 | scanmatch(tmpl, label_ptrs, &found);\r | |
479 | \r | |
480 | scanast_free(tmpl);\r | |
481 | free( (char *) label_ptrs); // MR1\r | |
482 | \r | |
483 | return found;\r | |
484 | }\r | |
485 | \r | |
486 | ScanAST *PCCTS_AST::\r | |
487 | new_scanast(int tok)\r | |
488 | {\r | |
489 | ScanAST *p = (ScanAST *) calloc(1, sizeof(ScanAST));\r | |
490 | //\r | |
491 | // 7-Apr-97 133MR1\r | |
492 | //\r | |
493 | if ( p == NULL ) { // MR1\r | |
494 | fprintf(stderr, "out of mem\n"); // MR1\r | |
495 | exit(PCCTS_EXIT_FAILURE); // MR1\r | |
496 | }; // MR1\r | |
497 | p->_token = tok;\r | |
498 | return p;\r | |
499 | }\r | |
500 | \r | |
501 | ScanAST *PCCTS_AST::\r | |
502 | stringparser_parse_scanast(char *templ, int *num_labels)\r | |
503 | {\r | |
504 | StringLexer lex;\r | |
505 | StringParser parser;\r | |
506 | ScanAST *t;\r | |
507 | \r | |
508 | stringlexer_init(&lex, templ);\r | |
509 | stringparser_init(&parser, &lex);\r | |
510 | t = stringparser_parse_tree(&parser);\r | |
511 | *num_labels = parser.num_labels;\r | |
512 | return t;\r | |
513 | }\r | |
514 | \r | |
515 | void PCCTS_AST::\r | |
516 | stringparser_match(StringParser *parser, int token)\r | |
517 | {\r | |
518 | if ( parser->token != token ) panic("bad tree in scan()");\r | |
519 | }\r | |
520 | \r | |
521 | /*\r | |
522 | * Match a tree of the form:\r | |
523 | * (root child1 child2 ... childn)\r | |
524 | * or,\r | |
525 | * node\r | |
526 | *\r | |
527 | * where the elements are integers or labeled integers.\r | |
528 | */\r | |
529 | ScanAST *PCCTS_AST::\r | |
530 | stringparser_parse_tree(StringParser *parser)\r | |
531 | {\r | |
532 | ScanAST *t=NULL, *root, *child, *last;\r | |
533 | \r | |
534 | if ( parser->token != __POUND )\r | |
535 | {\r | |
536 | return stringparser_parse_element(parser);\r | |
537 | }\r | |
538 | stringparser_match(parser,__POUND);\r | |
539 | parser->token = stringscan_gettok(parser->lexer);\r | |
540 | stringparser_match(parser,__LPAREN);\r | |
541 | parser->token = stringscan_gettok(parser->lexer);\r | |
542 | root = stringparser_parse_element(parser);\r | |
543 | while ( parser->token != __RPAREN )\r | |
544 | {\r | |
545 | child = stringparser_parse_element(parser);\r | |
546 | if ( t==NULL ) { t = child; last = t; }\r | |
547 | else { last->_right = child; last = child; }\r | |
548 | }\r | |
549 | stringparser_match(parser,__RPAREN);\r | |
550 | parser->token = stringscan_gettok(parser->lexer);\r | |
551 | root->_down = t;\r | |
552 | return root;\r | |
553 | }\r | |
554 | \r | |
555 | ScanAST *PCCTS_AST::\r | |
556 | stringparser_parse_element(StringParser *parser)\r | |
557 | {\r | |
558 | static char ebuf[100];\r | |
559 | int label = 0;\r | |
560 | \r | |
561 | if ( parser->token == __POUND )\r | |
562 | {\r | |
563 | return stringparser_parse_tree(parser);\r | |
564 | }\r | |
565 | if ( parser->token == __PERCENT )\r | |
566 | {\r | |
567 | parser->token = stringscan_gettok(parser->lexer);\r | |
568 | stringparser_match(parser,__INT);\r | |
569 | label = atoi(parser->lexer->text);\r | |
570 | parser->num_labels++;\r | |
571 | if ( label==0 ) panic("%%0 is an invalid label");\r | |
572 | parser->token = stringscan_gettok(parser->lexer);\r | |
573 | stringparser_match(parser,__COLON);\r | |
574 | parser->token = stringscan_gettok(parser->lexer);\r | |
575 | /* can label tokens and wildcards */\r | |
576 | if ( parser->token != __INT && parser->token != __PERIOD )\r | |
577 | panic("can only label tokens");\r | |
578 | }\r | |
579 | if ( parser->token == __INT )\r | |
580 | {\r | |
581 | ScanAST *p = new_scanast(atoi(parser->lexer->text));\r | |
582 | parser->token = stringscan_gettok(parser->lexer);\r | |
583 | p->label_num = label;\r | |
584 | return p;\r | |
585 | }\r | |
586 | if ( parser->token == __PERIOD )\r | |
587 | {\r | |
588 | ScanAST *p = new_scanast(0); /* token of 0 is wildcard */\r | |
589 | parser->token = stringscan_gettok(parser->lexer);\r | |
590 | p->label_num = label;\r | |
591 | return p;\r | |
592 | }\r | |
593 | sprintf(ebuf, "mismatch token in scan(): %s", scan_token_str(parser->token));\r | |
594 | panic(ebuf);\r | |
595 | return NULL;\r | |
596 | }\r | |
597 | \r | |
598 | void PCCTS_AST::\r | |
599 | stringparser_init(StringParser *parser, StringLexer *input)\r | |
600 | {\r | |
601 | parser->lexer = input;\r | |
602 | parser->token = stringscan_gettok(parser->lexer);\r | |
603 | parser->num_labels = 0;\r | |
604 | }\r | |
605 | \r | |
606 | void PCCTS_AST::\r | |
607 | stringlexer_init(StringLexer *scanner, char *input)\r | |
608 | {\r | |
609 | scanner->text[0]='\0';\r | |
610 | scanner->input = input;\r | |
611 | scanner->p = input;\r | |
612 | stringscan_advance(scanner);\r | |
613 | }\r | |
614 | \r | |
615 | void PCCTS_AST::\r | |
616 | stringscan_advance(StringLexer *scanner)\r | |
617 | {\r | |
618 | if ( *(scanner->p) == '\0' ) scanner->c = __StringScanEOF;\r | |
619 | scanner->c = *(scanner->p)++;\r | |
620 | }\r | |
621 | \r | |
622 | int PCCTS_AST::\r | |
623 | stringscan_gettok(StringLexer *scanner)\r | |
624 | {\r | |
625 | char *index = &scanner->text[0];\r | |
626 | static char ebuf[100];\r | |
627 | \r | |
628 | while ( isspace(scanner->c) ) { stringscan_advance(scanner); }\r | |
629 | if ( isdigit(scanner->c) )\r | |
630 | {\r | |
631 | int tok = __INT;\r | |
632 | while ( isdigit(scanner->c) ) {\r | |
633 | *index++ = scanner->c;\r | |
634 | stringscan_advance(scanner);\r | |
635 | }\r | |
636 | *index = '\0';\r | |
637 | return tok;\r | |
638 | }\r | |
639 | switch ( scanner->c )\r | |
640 | {\r | |
641 | case '#' : stringscan_advance(scanner); return __POUND;\r | |
642 | case '(' : stringscan_advance(scanner); return __LPAREN;\r | |
643 | case ')' : stringscan_advance(scanner); return __RPAREN;\r | |
644 | case '%' : stringscan_advance(scanner); return __PERCENT;\r | |
645 | case ':' : stringscan_advance(scanner); return __COLON;\r | |
646 | case '.' : stringscan_advance(scanner); return __PERIOD;\r | |
647 | case '\0' : return __StringScanEOF;\r | |
648 | case __StringScanEOF : return __StringScanEOF;\r | |
649 | default :\r | |
650 | sprintf(ebuf, "invalid char in scan: '%c'", scanner->c);\r | |
651 | panic(ebuf);\r | |
652 | }\r | |
653 | return __StringScanEOF; // never reached\r | |
654 | }\r | |
655 | \r | |
656 | const char *PCCTS_AST:: /* MR20 const */\r | |
657 | scan_token_str(int t)\r | |
658 | {\r | |
659 | if ( VALID_SCAN_TOKEN(t) ) return scan_token_tbl[t];\r | |
660 | else if ( t==__StringScanEOF ) return "<end-of-string>";\r | |
661 | else return "<invalid-token>";\r | |
662 | }\r |