]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Other/Maintained/Tools/Pccts/h/PCCTSAST.cpp
Add in the 1st version of ECP.
[mirror_edk2.git] / EdkCompatibilityPkg / Other / Maintained / Tools / Pccts / h / PCCTSAST.cpp
CommitLineData
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
38PCCTS_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
46const 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
57void PCCTS_AST::\r
58addChild(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
71void PCCTS_AST::\r
72lisp(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
94PCCTS_AST *PCCTS_AST::\r
95make(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
123void 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
131PCCTS_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
144PCCTS_AST *PCCTS_AST::\r
145ast_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
162keep_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
208int PCCTS_AST::\r
209match(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
226int PCCTS_AST::\r
227match_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
246int PCCTS_AST::\r
247scanmatch(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
275void PCCTS_AST::\r
276insert_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
286void PCCTS_AST::\r
287append(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
296PCCTS_AST *PCCTS_AST::\r
297tail()\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
305PCCTS_AST *PCCTS_AST::\r
306bottom()\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
314PCCTS_AST *PCCTS_AST::\r
315cut_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
330SList *PCCTS_AST::\r
331to_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
344void PCCTS_AST::\r
345tfree()\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
353int PCCTS_AST::\r
354nsiblings()\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
367PCCTS_AST *PCCTS_AST::\r
368sibling_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
394PCCTS_AST *PCCTS_AST::\r
395deepCopy()\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
404PCCTS_AST *PCCTS_AST::\r
405deepCopyBushy()\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
414void PCCTS_AST::\r
415scanast_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
452int PCCTS_AST::\r
453ast_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
486ScanAST *PCCTS_AST::\r
487new_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
501ScanAST *PCCTS_AST::\r
502stringparser_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
515void PCCTS_AST::\r
516stringparser_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
529ScanAST *PCCTS_AST::\r
530stringparser_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
555ScanAST *PCCTS_AST::\r
556stringparser_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
598void PCCTS_AST::\r
599stringparser_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
606void PCCTS_AST::\r
607stringlexer_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
615void PCCTS_AST::\r
616stringscan_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
622int PCCTS_AST::\r
623stringscan_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
656const char *PCCTS_AST:: /* MR20 const */\r
657scan_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