]>
Commit | Line | Data |
---|---|---|
30fdf114 LG |
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-2000\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 ) /* MR23 */ printMessage(f," (");\r | |
75 | lisp_action(f);\r | |
76 | if ( down()!=NULL ) down()->lisp(f);\r | |
77 | if ( down() != NULL ) /* MR23 */ printMessage(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=NULL /*MR23*/, *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]; /* MR23 Remove "static" */\r | |
149 | /*** static ***/ int tsp = MaxTreeStackDepth; /* MR23 Remove "static" */\r | |
150 | \r | |
151 | ////static int nesting = 0; /* MR23 Not referenced */\r | |
152 | \r | |
153 | if ( *cursor == NULL ) return NULL;\r | |
154 | if ( *cursor!=this ) sib = *cursor;\r | |
155 | else {\r | |
156 | /* else, first time--start at top of template 't' */\r | |
157 | tsp = MaxTreeStackDepth;\r | |
158 | sib = this;\r | |
159 | /* bottom of stack is always a NULL--"cookie" indicates "done" */\r | |
160 | _push(template_stack, &tsp, NULL);\r | |
161 | }\r | |
162 | \r | |
163 | keep_looking:\r | |
164 | if ( sib==NULL ) /* hit end of sibling list */\r | |
165 | {\r | |
166 | sib = _pop(template_stack, &tsp);\r | |
167 | if ( sib == NULL ) { *cursor = NULL; return NULL; }\r | |
168 | }\r | |
169 | \r | |
170 | if ( sib->type() != u->type() )\r | |
171 | {\r | |
172 | /* look for another match */\r | |
173 | if ( sib->down()!=NULL )\r | |
174 | {\r | |
175 | if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right());\r | |
176 | sib=sib->down();\r | |
177 | goto keep_looking;\r | |
178 | }\r | |
179 | /* nothing below to try, try next sibling */\r | |
180 | sib=sib->right();\r | |
181 | goto keep_looking;\r | |
182 | }\r | |
183 | \r | |
184 | /* found a matching root node, try to match what's below */\r | |
185 | if ( match_partial(sib, u) )\r | |
186 | {\r | |
187 | /* record sibling cursor so we can pick up next from there */\r | |
188 | if ( sib->down()!=NULL )\r | |
189 | {\r | |
190 | if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right());\r | |
191 | *cursor = sib->down();\r | |
192 | }\r | |
193 | else if ( sib->right()!=NULL ) *cursor = sib->right();\r | |
194 | else *cursor = _pop(template_stack, &tsp);\r | |
195 | return sib;\r | |
196 | }\r | |
197 | \r | |
198 | /* no match, keep searching */\r | |
199 | if ( sib->down()!=NULL )\r | |
200 | {\r | |
201 | if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right());\r | |
202 | sib=sib->down();\r | |
203 | }\r | |
204 | else sib = sib->right(); /* else, try to right if zip below */\r | |
205 | goto keep_looking;\r | |
206 | }\r | |
207 | \r | |
208 | /* are two trees exactly alike? */\r | |
209 | int PCCTS_AST::\r | |
210 | match(PCCTS_AST *u)\r | |
211 | {\r | |
212 | PCCTS_AST *t = this;\r | |
213 | PCCTS_AST *sib;\r | |
214 | \r | |
215 | if ( u==NULL ) return 0;\r | |
216 | \r | |
217 | for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right())\r | |
218 | {\r | |
219 | if ( sib->type() != u->type() ) return 0;\r | |
220 | if ( sib->down()!=NULL )\r | |
221 | if ( !sib->down()->match(u->down()) ) return 0;\r | |
222 | }\r | |
223 | return 1;\r | |
224 | }\r | |
225 | \r | |
226 | /* Is 'u' a subtree of 't' beginning at the root? */\r | |
227 | int PCCTS_AST::\r | |
228 | match_partial(PCCTS_AST *t, PCCTS_AST *u)\r | |
229 | {\r | |
230 | PCCTS_AST *sib;\r | |
231 | \r | |
232 | if ( u==NULL ) return 1;\r | |
233 | if ( t==NULL ) return 0; /* MR23 removed unreachable code */\r | |
234 | \r | |
235 | for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right())\r | |
236 | {\r | |
237 | if ( sib->type() != u->type() ) return 0;\r | |
238 | if ( sib->down()!=NULL )\r | |
239 | if ( !match_partial(sib->down(), u->down()) ) return 0;\r | |
240 | }\r | |
241 | return 1;\r | |
242 | }\r | |
243 | \r | |
244 | #ifdef _MSC_VER // MR23\r | |
245 | //Turn off "unreachable code" warning\r | |
246 | #pragma warning(disable : 4702)\r | |
247 | #endif\r | |
248 | /* Walk the template tree 't' (matching against 'this'), filling in the\r | |
249 | * 'labels' array, and setting 'n' according to how many labels were matched.\r | |
250 | */\r | |
251 | int PCCTS_AST::\r | |
252 | scanmatch(ScanAST *t, PCCTS_AST **labels[], int *n)\r | |
253 | {\r | |
254 | ScanAST *sib;\r | |
255 | PCCTS_AST *u = this;\r | |
256 | \r | |
257 | if ( u==NULL ) return 0;\r | |
258 | \r | |
259 | for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right())\r | |
260 | {\r | |
261 | /* make sure tokens match; token of '0' means wildcard match */\r | |
262 | if ( sib->type() != u->type() && sib->type()!=0 ) return 0;\r | |
263 | /* we have a matched token here; set label pointers if exists */\r | |
264 | if ( sib->label_num>0 )\r | |
265 | {\r | |
266 | require(labels!=NULL, "label found in template, but no array of labels");\r | |
267 | (*n)++;\r | |
268 | *(labels[sib->label_num-1]) = u;\r | |
269 | }\r | |
270 | /* match what's below if something there and current node is not wildcard */\r | |
271 | if ( sib->down()!=NULL && sib->type()!=0 )\r | |
272 | {\r | |
273 | if ( sib->down()==NULL ) \r | |
274 | {\r | |
275 | if ( u->down()!=NULL ) \r | |
276 | return 0; \r | |
277 | else \r | |
278 | return 1;\r | |
279 | }\r | |
280 | if ( !u->down()->scanmatch(sib->down(), labels, n) ) return 0;\r | |
281 | }\r | |
282 | }\r | |
283 | return 1;\r | |
284 | }\r | |
285 | #ifdef _MSC_VER // MR23\r | |
286 | #pragma warning(default : 4702)\r | |
287 | #endif\r | |
288 | \r | |
289 | void PCCTS_AST::\r | |
290 | insert_after(PCCTS_AST *b)\r | |
291 | {\r | |
292 | PCCTS_AST *end;\r | |
293 | if ( b==NULL ) return;\r | |
294 | /* find end of b's child list */\r | |
295 | for (end=b; end->right()!=NULL; end=end->right()) {;}\r | |
296 | end->setRight(this->right());\r | |
297 | this->setRight(b);\r | |
298 | }\r | |
299 | \r | |
300 | void PCCTS_AST::\r | |
301 | append(PCCTS_AST *b)\r | |
302 | {\r | |
303 | PCCTS_AST *end;\r | |
304 | require(b!=NULL, "append: NULL input tree");\r | |
305 | /* find end of child list */\r | |
306 | for (end=this; end->right()!=NULL; end=end->right()) {;}\r | |
307 | end->setRight(b);\r | |
308 | }\r | |
309 | \r | |
310 | PCCTS_AST *PCCTS_AST::\r | |
311 | tail()\r | |
312 | {\r | |
313 | PCCTS_AST *end;\r | |
314 | /* find end of child list */\r | |
315 | for (end=this; end->right()!=NULL; end=end->right()) {;}\r | |
316 | return end;\r | |
317 | }\r | |
318 | \r | |
319 | PCCTS_AST *PCCTS_AST::\r | |
320 | bottom()\r | |
321 | {\r | |
322 | PCCTS_AST *end;\r | |
323 | /* find end of child list */\r | |
324 | for (end=this; end->down()!=NULL; end=end->down()) {;}\r | |
325 | return end;\r | |
326 | }\r | |
327 | \r | |
328 | PCCTS_AST *PCCTS_AST::\r | |
329 | cut_between(PCCTS_AST *a, PCCTS_AST *b)\r | |
330 | {\r | |
331 | PCCTS_AST *end, *ret;\r | |
332 | if (a==NULL||b==NULL) return NULL;\r | |
333 | /* find node pointing to b */\r | |
334 | for (end=a; end->right()!=NULL&&end->right()!=b; end=end->right())\r | |
335 | {;}\r | |
336 | if (end->right()==NULL) return NULL; //ast_cut_between: a,b not connected\r | |
337 | end->setRight(NULL); /* don't want it point to 'b' anymore */\r | |
338 | ret = a->right();\r | |
339 | a->setRight(b);\r | |
340 | return ret;\r | |
341 | }\r | |
342 | \r | |
343 | #ifdef NOT_YET\r | |
344 | SList *PCCTS_AST::\r | |
345 | to_slist()\r | |
346 | {\r | |
347 | SList *list = new SList;\r | |
348 | PCCTS_AST *p;\r | |
349 | \r | |
350 | for (p=this; p!=NULL; p=p->right())\r | |
351 | {\r | |
352 | list->add(p);\r | |
353 | }\r | |
354 | return list;\r | |
355 | }\r | |
356 | #endif\r | |
357 | \r | |
358 | void PCCTS_AST::\r | |
359 | tfree()\r | |
360 | {\r | |
361 | PCCTS_AST *t = this;\r | |
362 | if ( t->down()!=NULL ) t->down()->tfree();\r | |
363 | if ( t->right()!=NULL ) t->right()->tfree();\r | |
364 | delete t;\r | |
365 | }\r | |
366 | \r | |
367 | int PCCTS_AST::\r | |
368 | nsiblings()\r | |
369 | {\r | |
370 | PCCTS_AST *t = this;\r | |
371 | int n=0;\r | |
372 | \r | |
373 | while ( t!=NULL )\r | |
374 | {\r | |
375 | n++;\r | |
376 | t = t->right();\r | |
377 | }\r | |
378 | return n;\r | |
379 | }\r | |
380 | \r | |
381 | PCCTS_AST *PCCTS_AST::\r | |
382 | sibling_index(int i)\r | |
383 | {\r | |
384 | PCCTS_AST *t = this;\r | |
385 | int j=1;\r | |
386 | require(i>0, "sibling_index: i<=0");\r | |
387 | \r | |
388 | while ( t!=NULL )\r | |
389 | {\r | |
390 | if ( j==i ) return t;\r | |
391 | j++;\r | |
392 | t = t->right();\r | |
393 | }\r | |
394 | return NULL;\r | |
395 | }\r | |
396 | \r | |
397 | /* Assume this is a root node of a tree--\r | |
398 | * duplicate that node and what's below; ignore siblings of root node.\r | |
399 | */\r | |
400 | \r | |
401 | // MR9 23-Sep-97 RJV\r | |
402 | // MR9\r | |
403 | // MR9 RJV: Original version only duplicated the node and down elements.\r | |
404 | // MR9 Made copies of the pointers to sibling.\r | |
405 | // MR9 Changed call "down()->deepCopy()" to "down()->deepCopyBushy()"\r | |
406 | // MR9\r | |
407 | \r | |
408 | PCCTS_AST *PCCTS_AST::\r | |
409 | deepCopy()\r | |
410 | {\r | |
411 | PCCTS_AST *u = this->shallowCopy();\r | |
412 | if ( down()!=NULL ) u->setDown(down()->deepCopyBushy());\r | |
413 | u->setRight(NULL);\r | |
414 | return u;\r | |
415 | }\r | |
416 | \r | |
417 | /* Copy all nodes including siblings of root. */\r | |
418 | PCCTS_AST *PCCTS_AST::\r | |
419 | deepCopyBushy()\r | |
420 | {\r | |
421 | PCCTS_AST *u = this->shallowCopy();\r | |
422 | /* copy the rest of the tree */\r | |
423 | if ( down()!=NULL ) u->setDown(down()->deepCopyBushy());\r | |
424 | if ( right()!=NULL ) u->setRight(right()->deepCopyBushy());\r | |
425 | return u;\r | |
426 | }\r | |
427 | \r | |
428 | void PCCTS_AST::\r | |
429 | scanast_free(ScanAST *t)\r | |
430 | {\r | |
431 | if ( t == NULL ) return;\r | |
432 | scanast_free( t->down() );\r | |
433 | scanast_free( t->right() );\r | |
434 | free( (char *) t ); // MR1\r | |
435 | }\r | |
436 | \r | |
437 | /*\r | |
438 | * scan\r | |
439 | *\r | |
440 | * This function is like scanf(): it attempts to match a template\r | |
441 | * against an input tree. A variable number of tree pointers\r | |
442 | * may be set according to the '%i' labels in the template string.\r | |
443 | * For example:\r | |
444 | *\r | |
445 | * t->ast_scan("#( 6 #(5 %1:4 %2:3) #(1 %3:3 %4:3) )",\r | |
446 | * &w, &x, &y, &z);\r | |
447 | *\r | |
448 | * Naturally, you'd want this converted from\r | |
449 | *\r | |
450 | * t->ast_scan("#( RangeOp #(Minus %1:IConst %2:Var) #(Plus %3:Var %4Var) )",\r | |
451 | * &w, &x, &y, &z);\r | |
452 | *\r | |
453 | * by SORCERER.\r | |
454 | *\r | |
455 | * This function call must be done withing a SORCERER file because SORCERER\r | |
456 | * must convert the token references to the associated token number.\r | |
457 | *\r | |
458 | * This functions parses the template and creates trees which are then\r | |
459 | * matched against the input tree. The labels are set as they are\r | |
460 | * encountered; hence, partial matches may leave some pointers set\r | |
461 | * and some NULL. This routines initializes all argument pointers to NULL\r | |
462 | * at the beginning.\r | |
463 | *\r | |
464 | * This function returns the number of labels matched.\r | |
465 | */\r | |
466 | int PCCTS_AST::\r | |
467 | ast_scan(char *templ, ...)\r | |
468 | {\r | |
469 | va_list ap;\r | |
470 | ScanAST *tmpl;\r | |
471 | int n, i, found=0;\r | |
472 | PCCTS_AST ***label_ptrs=NULL;\r | |
473 | \r | |
474 | va_start(ap, templ);\r | |
475 | \r | |
476 | /* make a ScanAST tree out of the template */\r | |
477 | tmpl = stringparser_parse_scanast(templ, &n);\r | |
478 | \r | |
479 | /* make an array out of the labels */\r | |
480 | if ( n>0 )\r | |
481 | {\r | |
482 | label_ptrs = (PCCTS_AST ***) calloc(n, sizeof(PCCTS_AST **));\r | |
483 | require(label_ptrs!=NULL, "scan: out of memory");\r | |
484 | for (i=1; i<=n; i++)\r | |
485 | {\r | |
486 | label_ptrs[i-1] = va_arg(ap, PCCTS_AST **);\r | |
487 | *(label_ptrs[i-1]) = NULL;\r | |
488 | }\r | |
489 | }\r | |
490 | \r | |
491 | /* match the input tree against the template */\r | |
492 | scanmatch(tmpl, label_ptrs, &found);\r | |
493 | \r | |
494 | scanast_free(tmpl);\r | |
495 | free( (char *) label_ptrs); // MR1\r | |
496 | \r | |
497 | return found;\r | |
498 | }\r | |
499 | \r | |
500 | ScanAST *PCCTS_AST::\r | |
501 | new_scanast(int tok)\r | |
502 | {\r | |
503 | ScanAST *p = (ScanAST *) calloc(1, sizeof(ScanAST));\r | |
504 | //\r | |
505 | // 7-Apr-97 133MR1\r | |
506 | //\r | |
507 | if ( p == NULL )\r | |
508 | panic("out of memory\n"); // MR23\r | |
509 | p->_token = tok;\r | |
510 | return p;\r | |
511 | }\r | |
512 | \r | |
513 | ScanAST *PCCTS_AST::\r | |
514 | stringparser_parse_scanast(char *templ, int *num_labels)\r | |
515 | {\r | |
516 | StringLexer lex;\r | |
517 | StringParser parser;\r | |
518 | ScanAST *t;\r | |
519 | \r | |
520 | stringlexer_init(&lex, templ);\r | |
521 | stringparser_init(&parser, &lex);\r | |
522 | t = stringparser_parse_tree(&parser);\r | |
523 | *num_labels = parser.num_labels;\r | |
524 | return t;\r | |
525 | }\r | |
526 | \r | |
527 | void PCCTS_AST::\r | |
528 | stringparser_match(StringParser *parser, int token)\r | |
529 | {\r | |
530 | if ( parser->token != token ) panic("bad tree in scan()");\r | |
531 | }\r | |
532 | \r | |
533 | /*\r | |
534 | * Match a tree of the form:\r | |
535 | * (root child1 child2 ... childn)\r | |
536 | * or,\r | |
537 | * node\r | |
538 | *\r | |
539 | * where the elements are integers or labeled integers.\r | |
540 | */\r | |
541 | ScanAST *PCCTS_AST::\r | |
542 | stringparser_parse_tree(StringParser *parser)\r | |
543 | {\r | |
544 | ScanAST *t=NULL, *root, *child, *last=NULL /*MR23*/;\r | |
545 | \r | |
546 | if ( parser->token != __POUND )\r | |
547 | {\r | |
548 | return stringparser_parse_element(parser);\r | |
549 | }\r | |
550 | stringparser_match(parser,__POUND);\r | |
551 | parser->token = stringscan_gettok(parser->lexer);\r | |
552 | stringparser_match(parser,__LPAREN);\r | |
553 | parser->token = stringscan_gettok(parser->lexer);\r | |
554 | root = stringparser_parse_element(parser);\r | |
555 | while ( parser->token != __RPAREN )\r | |
556 | {\r | |
557 | child = stringparser_parse_element(parser);\r | |
558 | if ( t==NULL ) { t = child; last = t; }\r | |
559 | else { last->_right = child; last = child; }\r | |
560 | }\r | |
561 | stringparser_match(parser,__RPAREN);\r | |
562 | parser->token = stringscan_gettok(parser->lexer);\r | |
563 | root->_down = t;\r | |
564 | return root;\r | |
565 | }\r | |
566 | \r | |
567 | ScanAST *PCCTS_AST::\r | |
568 | stringparser_parse_element(StringParser *parser)\r | |
569 | {\r | |
570 | char ebuf[100];\r | |
571 | int label = 0;\r | |
572 | \r | |
573 | if ( parser->token == __POUND )\r | |
574 | {\r | |
575 | return stringparser_parse_tree(parser);\r | |
576 | }\r | |
577 | if ( parser->token == __PERCENT )\r | |
578 | {\r | |
579 | parser->token = stringscan_gettok(parser->lexer);\r | |
580 | stringparser_match(parser,__INT);\r | |
581 | label = atoi(parser->lexer->text);\r | |
582 | parser->num_labels++;\r | |
583 | if ( label==0 ) panic("%%0 is an invalid label");\r | |
584 | parser->token = stringscan_gettok(parser->lexer);\r | |
585 | stringparser_match(parser,__COLON);\r | |
586 | parser->token = stringscan_gettok(parser->lexer);\r | |
587 | /* can label tokens and wildcards */\r | |
588 | if ( parser->token != __INT && parser->token != __PERIOD )\r | |
589 | panic("can only label tokens");\r | |
590 | }\r | |
591 | if ( parser->token == __INT )\r | |
592 | {\r | |
593 | ScanAST *p = new_scanast(atoi(parser->lexer->text));\r | |
594 | parser->token = stringscan_gettok(parser->lexer);\r | |
595 | p->label_num = label;\r | |
596 | return p;\r | |
597 | }\r | |
598 | if ( parser->token == __PERIOD )\r | |
599 | {\r | |
600 | ScanAST *p = new_scanast(0); /* token of 0 is wildcard */\r | |
601 | parser->token = stringscan_gettok(parser->lexer);\r | |
602 | p->label_num = label;\r | |
603 | return p;\r | |
604 | }\r | |
605 | sprintf(ebuf, "mismatch token in scan(): %s", scan_token_str(parser->token));\r | |
606 | panic(ebuf);\r | |
607 | return NULL;\r | |
608 | }\r | |
609 | \r | |
610 | void PCCTS_AST::\r | |
611 | stringparser_init(StringParser *parser, StringLexer *input)\r | |
612 | {\r | |
613 | parser->lexer = input;\r | |
614 | parser->token = stringscan_gettok(parser->lexer);\r | |
615 | parser->num_labels = 0;\r | |
616 | }\r | |
617 | \r | |
618 | void PCCTS_AST::\r | |
619 | stringlexer_init(StringLexer *scanner, char *input)\r | |
620 | {\r | |
621 | scanner->text[0]='\0';\r | |
622 | scanner->input = input;\r | |
623 | scanner->p = input;\r | |
624 | stringscan_advance(scanner);\r | |
625 | }\r | |
626 | \r | |
627 | void PCCTS_AST::\r | |
628 | stringscan_advance(StringLexer *scanner)\r | |
629 | {\r | |
630 | if ( *(scanner->p) == '\0' ) scanner->c = __StringScanEOF;\r | |
631 | scanner->c = *(scanner->p)++;\r | |
632 | }\r | |
633 | \r | |
634 | int PCCTS_AST::\r | |
635 | stringscan_gettok(StringLexer *scanner)\r | |
636 | {\r | |
637 | char *index = &scanner->text[0];\r | |
638 | char ebuf[100]; /* MR23 Remove static */\r | |
639 | \r | |
640 | while ( isspace(scanner->c) ) { stringscan_advance(scanner); }\r | |
641 | if ( isdigit(scanner->c) )\r | |
642 | {\r | |
643 | int tok = __INT;\r | |
644 | while ( isdigit(scanner->c) ) {\r | |
645 | *index++ = (char) /* static_cast<char> */ (scanner->c); // MR23\r | |
646 | stringscan_advance(scanner);\r | |
647 | }\r | |
648 | *index = '\0';\r | |
649 | return tok;\r | |
650 | }\r | |
651 | switch ( scanner->c )\r | |
652 | {\r | |
653 | case '#' : stringscan_advance(scanner); return __POUND;\r | |
654 | case '(' : stringscan_advance(scanner); return __LPAREN;\r | |
655 | case ')' : stringscan_advance(scanner); return __RPAREN;\r | |
656 | case '%' : stringscan_advance(scanner); return __PERCENT;\r | |
657 | case ':' : stringscan_advance(scanner); return __COLON;\r | |
658 | case '.' : stringscan_advance(scanner); return __PERIOD;\r | |
659 | case '\0' : return __StringScanEOF;\r | |
660 | case __StringScanEOF : return __StringScanEOF;\r | |
661 | default :\r | |
662 | sprintf(ebuf, "invalid char in scan: '%c'", scanner->c);\r | |
663 | panic(ebuf);\r | |
664 | }\r | |
665 | return __StringScanEOF; // never reached\r | |
666 | }\r | |
667 | \r | |
668 | const char *PCCTS_AST:: /* MR20 const */\r | |
669 | scan_token_str(int t)\r | |
670 | {\r | |
671 | if ( VALID_SCAN_TOKEN(t) ) return scan_token_tbl[t];\r | |
672 | else if ( t==__StringScanEOF ) return "<end-of-string>";\r | |
673 | else return "<invalid-token>";\r | |
674 | }\r | |
675 | \r | |
676 | //MR23\r | |
677 | int PCCTS_AST::printMessage(FILE* pFile, const char* pFormat, ...)\r | |
678 | {\r | |
679 | va_list marker;\r | |
680 | va_start( marker, pFormat );\r | |
681 | int iRet = vfprintf(pFile, pFormat, marker);\r | |
682 | va_end( marker );\r | |
683 | return iRet;\r | |
684 | }\r |