]>
git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Other/Maintained/Tools/Pccts/sorcerer/lib/astlib.c
6 * We reserve no LEGAL rights to SORCERER -- SORCERER is in the public
7 * domain. An individual or company may do whatever they wish with
8 * source code distributed with SORCERER or the code generated by
9 * SORCERER, including the incorporation of SORCERER, or its output, into
10 * commerical software.
12 * We encourage users to develop software with SORCERER. However, we do
13 * ask that credit is given to us for developing SORCERER. By "credit",
14 * we mean that if you incorporate our source code into one of your
15 * programs (commercial product, research project, or otherwise) that you
16 * acknowledge this fact somewhere in the documentation, research report,
17 * etc... If you like SORCERER and have developed a nice tool with the
18 * output, please mention that you developed it using SORCERER. In
19 * addition, we ask that this header remain intact in our source code.
20 * As long as these guidelines are kept, we expect to continue enhancing
21 * this system and expect to make other tools available as they are
26 * AHPCRC, University of Minnesota
34 #define SORCERER_TRANSFORM
39 #ifdef PCCTS_USE_STDARG
45 /* String Scanning/Parsing Stuff */
47 #define StringScanMaxText 50
49 typedef struct stringlexer
{
57 char text
[StringScanMaxText
];
67 #define StringScanEOF -1
68 #define VALID_SCAN_TOKEN(t) (t>=LPAREN && t<=PERIOD)
70 static char *scan_token_tbl
[] = {
89 if ( VALID_SCAN_TOKEN(t
) ) return scan_token_tbl
[t
];
90 else if ( t
==StringScanEOF
) return "<end-of-string>";
91 else return "<invalid-token>";
94 typedef struct stringparser
{
100 /* This type ONLY USED by ast_scan() */
102 typedef struct _scanast
{
103 struct _scanast
*right
, *down
;
109 static void stringlexer_init(StringLexer
*scanner
, char *input
);
110 static void stringparser_init(StringParser
*, StringLexer
*);
111 static ScanAST
*stringparser_parse_scanast(char *templ
, int *n
);
112 static ScanAST
*stringparser_parse_tree(StringParser
*parser
);
113 static ScanAST
*stringparser_parse_element(StringParser
*parser
);
114 static void stringscan_advance(StringLexer
*scanner
);
115 static int stringscan_gettok(StringLexer
*scanner
);
117 static void stringlexer_init();
118 static void stringparser_init();
119 static ScanAST
*stringparser_parse_scanast();
120 static ScanAST
*stringparser_parse_tree();
121 static ScanAST
*stringparser_parse_element();
122 static void stringscan_advance();
123 static int stringscan_gettok();
126 /* build a tree (root child1 child2 ... NULL)
127 * If root is NULL, simply make the children siblings and return ptr
128 * to 1st sibling (child1). If root is not single node, return NULL.
130 * Siblings that are actually sibling lists themselves are handled
131 * correctly. For example #( NULL, #( NULL, A, B, C), D) results
132 * in the tree ( NULL A B C D ).
134 * Requires at least two parameters with the last one being NULL. If
135 * both are NULL, return NULL.
137 * The ast_down and ast_right down/right pointers are used to make the tree.
140 #ifdef PCCTS_USE_STDARG
141 ast_make(SORAST
*rt
, ...)
148 register SORAST
*child
, *sibling
=NULL
, *tail
= NULL
, *w
;
151 #ifdef PCCTS_USE_STDARG
156 root
= va_arg(ap
, SORAST
*);
160 if ( root
->ast_down
!= NULL
) return NULL
;
161 child
= va_arg(ap
, SORAST
*);
162 while ( child
!= NULL
)
164 /* find end of child */
165 for (w
=child
; w
->ast_right
!=NULL
; w
=w
->ast_right
) {;}
166 if ( sibling
== NULL
) {sibling
= child
; tail
= w
;}
167 else {tail
->ast_right
= child
; tail
= w
;}
168 child
= va_arg(ap
, SORAST
*);
170 if ( root
==NULL
) root
= sibling
;
171 else root
->ast_down
= sibling
;
176 /* The following push and pop routines are only used by ast_find_all() */
180 _push(SORAST
**st
, int *sp
, SORAST
*e
)
189 require((*sp
)>=0, "stack overflow");
195 _pop(SORAST
**st
, int *sp
)
204 require((*sp
)<=MaxTreeStackDepth
, "stack underflow");
208 /* Is 'u' a subtree of 't' beginning at the root? */
211 ast_match_partial(SORAST
*t
, SORAST
*u
)
213 ast_match_partial(t
, u
)
219 if ( u
==NULL
) return 1;
220 if ( t
==NULL
) if ( u
!=NULL
) return 0; else return 1;
222 for (sib
=t
; sib
!=NULL
&&u
!=NULL
; sib
=sib
->ast_right
, u
=u
->ast_right
)
224 if ( sib
->token
!= u
->token
) return 0;
225 if ( sib
->ast_down
!=NULL
)
226 if ( !ast_match_partial(sib
->ast_down
, u
->ast_down
) ) return 0;
231 /* Find all occurrences of u in t.
232 * 'cursor' must be initialized to 't'. It eventually
233 * returns NULL when no more occurrences of 'u' are found.
237 ast_find_all(SORAST
*t
, SORAST
*u
, SORAST
**cursor
)
239 ast_find_all(t
, u
, cursor
)
240 SORAST
*t
, *u
, **cursor
;
244 static SORAST
*template_stack
[MaxTreeStackDepth
];
245 static int tsp
= MaxTreeStackDepth
;
247 if ( *cursor
== NULL
) return NULL
;
248 if ( *cursor
!=t
) sib
= *cursor
;
250 /* else, first time--start at top of template 't' */
251 tsp
= MaxTreeStackDepth
;
253 /* bottom of stack is always a NULL--"cookie" indicates "done" */
254 _push(template_stack
, &tsp
, NULL
);
258 if ( sib
==NULL
) /* hit end of sibling list */
260 sib
= _pop(template_stack
, &tsp
);
261 if ( sib
== NULL
) { *cursor
= NULL
; return NULL
; }
264 if ( sib
->token
!= u
->token
)
266 /* look for another match */
267 if ( sib
->ast_down
!=NULL
)
269 if ( sib
->ast_right
!=NULL
) _push(template_stack
, &tsp
, sib
->ast_right
);
273 /* nothing below to try, try next sibling */
278 /* found a matching root node, try to match what's below */
279 if ( ast_match_partial(sib
, u
) )
281 /* record sibling cursor so we can pick up next from there */
282 if ( sib
->ast_down
!=NULL
)
284 if ( sib
->ast_right
!=NULL
) _push(template_stack
, &tsp
, sib
->ast_right
);
285 *cursor
= sib
->ast_down
;
287 else if ( sib
->ast_right
!=NULL
) *cursor
= sib
->ast_right
;
288 else *cursor
= _pop(template_stack
, &tsp
);
292 /* no match, keep searching */
293 if ( sib
->ast_down
!=NULL
)
295 if ( sib
->ast_right
!=NULL
) _push(template_stack
, &tsp
, sib
->ast_right
);
298 else sib
= sib
->ast_right
; /* else, try to right if zip below */
302 /* are two trees exactly alike? */
305 ast_match(SORAST
*t
, SORAST
*u
)
313 if ( t
==NULL
) if ( u
!=NULL
) return 0; else return 1;
314 if ( u
==NULL
) return 0;
316 for (sib
=t
; sib
!=NULL
&&u
!=NULL
; sib
=sib
->ast_right
, u
=u
->ast_right
)
318 if ( sib
->token
!= u
->token
) return 0;
319 if ( sib
->ast_down
!=NULL
)
320 if ( !ast_match(sib
->ast_down
, u
->ast_down
) ) return 0;
327 ast_scanmatch(ScanAST
*t
, SORAST
*u
, SORAST
**labels
[], int *n
)
329 ast_scanmatch(t
, u
, labels
, n
)
338 if ( t
==NULL
) if ( u
!=NULL
) return 0; else return 1;
339 if ( u
==NULL
) return 0;
341 for (sib
=t
; sib
!=NULL
&&u
!=NULL
; sib
=sib
->right
, u
=u
->ast_right
)
343 /* make sure tokens match; token of '0' means wildcard match */
344 if ( sib
->token
!= u
->token
&& sib
->token
!=0 ) return 0;
345 /* we have a matched token here; set label pointers if exists */
346 if ( sib
->label_num
>0 )
348 require(labels
!=NULL
, "label found in template, but no array of labels");
350 *(labels
[sib
->label_num
-1]) = u
;
352 /* match what's below if something there and current node is not wildcard */
353 if ( sib
->down
!=NULL
&& sib
->token
!=0 )
354 if ( !ast_scanmatch(sib
->down
, u
->ast_down
, labels
, n
) ) return 0;
361 ast_insert_after(SORAST
*a
, SORAST
*b
)
363 ast_insert_after(a
, b
)
368 require(a
!=NULL
, "ast_insert_after: NULL input tree");
369 if ( b
==NULL
) return;
370 /* find end of b's child list */
371 for (end
=b
; end
->ast_right
!=NULL
; end
=end
->ast_right
) {;}
372 end
->ast_right
= a
->ast_right
;
378 ast_append(SORAST
*a
, SORAST
*b
)
385 require(a
!=NULL
&&b
!=NULL
, "ast_append: NULL input tree");
386 /* find end of child list */
387 for (end
=a
; end
->ast_right
!=NULL
; end
=end
->ast_right
) {;}
400 require(a
!=NULL
, "ast_tail: NULL input tree");
401 /* find end of child list */
402 for (end
=a
; end
->ast_right
!=NULL
; end
=end
->ast_right
) {;}
408 ast_bottom(SORAST
*a
)
415 require(a
!=NULL
, "ast_bottom: NULL input tree");
416 /* find end of child list */
417 for (end
=a
; end
->ast_down
!=NULL
; end
=end
->ast_down
) {;}
423 ast_cut_between(SORAST
*a
, SORAST
*b
)
425 ast_cut_between(a
, b
)
430 require(a
!=NULL
&&b
!=NULL
, "ast_cut_between: NULL input tree");
431 /* find node pointing to b */
432 for (end
=a
; end
->ast_right
!=NULL
&&end
->ast_right
!=b
; end
=end
->ast_right
)
434 require(end
->ast_right
!=NULL
, "ast_cut_between: a,b not connected");
435 end
->ast_right
= NULL
; /* don't want it point to 'b' anymore */
443 ast_to_slist(SORAST
*t
)
452 for (p
=t
; p
!=NULL
; p
=p
->ast_right
)
461 slist_to_ast(SList
*list
)
467 SORAST
*t
=NULL
, *last
=NULL
;
470 for (p
= list
->next
; p
!=NULL
; p
=p
->next
)
472 SORAST
*u
= (SORAST
*)p
->elem
;
473 if ( last
==NULL
) last
= t
= u
;
474 else { last
->ast_right
= u
; last
= u
; }
487 if ( t
== NULL
) return;
488 ast_free( t
->ast_down
);
489 ast_free( t
->ast_right
);
495 ast_nsiblings(SORAST
*t
)
513 ast_sibling_index(SORAST
*t
, int i
)
515 ast_sibling_index(t
,i
)
521 require(i
>0, "ast_sibling_index: i<=0");
525 if ( j
==i
) return t
;
534 scanast_free(ScanAST
*t
)
540 if ( t
== NULL
) return;
541 scanast_free( t
->down
);
542 scanast_free( t
->right
);
549 * This function is like scanf(): it attempts to match a template
550 * against an input tree. A variable number of tree pointers
551 * may be set according to the '%i' labels in the template string.
554 * ast_scan("#( 6 #(5 %1:4 %2:3) #(1 %3:3 %4:3) )",
555 * t, &w, &x, &y, &z);
557 * Naturally, you'd want this converted from
559 * ast_scan("#( RangeOp #(Minus %1:IConst %2:Var) #(Plus %3:Var %4Var) )",
560 * t, &w, &x, &y, &z);
564 * This function call must be done withing a SORCERER file because SORCERER
565 * must convert the token references to the associated token number.
567 * This functions parses the template and creates trees which are then
568 * matched against the input tree. The labels are set as they are
569 * encountered; hence, partial matches may leave some pointers set
570 * and some NULL. This routines initializes all argument pointers to NULL
573 * This function returns the number of labels matched.
576 #ifdef PCCTS_USE_STDARG
577 ast_scan(char *templ
, SORAST
*tree
, ...)
586 SORAST
***label_ptrs
=NULL
;
588 #ifdef PCCTS_USE_STDARG
595 templ
= va_arg(ap
, char *);
596 tree
= va_arg(ap
, SORAST
*);
599 /* make a ScanAST tree out of the template */
600 t
= stringparser_parse_scanast(templ
, &n
);
602 /* make an array out of the labels */
605 label_ptrs
= (SORAST
***) calloc(n
, sizeof(SORAST
**));
606 require(label_ptrs
!=NULL
, "ast_scan: out of memory");
609 label_ptrs
[i
-1] = va_arg(ap
, SORAST
**);
610 *(label_ptrs
[i
-1]) = NULL
;
614 /* match the input tree against the template */
615 ast_scanmatch(t
, tree
, label_ptrs
, &found
);
631 ScanAST
*p
= (ScanAST
*) calloc(1, sizeof(ScanAST
));
632 if ( p
== NULL
) {fprintf(stderr
, "out of mem\n"); exit(-1);}
639 stringparser_parse_scanast(char *templ
, int *num_labels
)
641 stringparser_parse_scanast(templ
, num_labels
)
650 stringlexer_init(&lex
, templ
);
651 stringparser_init(&parser
, &lex
);
652 t
= stringparser_parse_tree(&parser
);
653 *num_labels
= parser
.num_labels
;
659 stringparser_match(StringParser
*parser
, int token
)
661 stringparser_match(parser
, token
)
662 StringParser
*parser
;
666 if ( parser
->token
!= token
) sorcerer_panic("bad tree in ast_scan()");
670 * Match a tree of the form:
671 * (root child1 child2 ... childn)
675 * where the elements are integers or labeled integers.
679 stringparser_parse_tree(StringParser
*parser
)
681 stringparser_parse_tree(parser
)
682 StringParser
*parser
;
685 ScanAST
*t
=NULL
, *root
, *child
, *last
= NULL
;
687 if ( parser
->token
!= POUND
)
689 return stringparser_parse_element(parser
);
691 stringparser_match(parser
,POUND
);
692 parser
->token
= stringscan_gettok(parser
->lexer
);
693 stringparser_match(parser
,LPAREN
);
694 parser
->token
= stringscan_gettok(parser
->lexer
);
695 root
= stringparser_parse_element(parser
);
696 while ( parser
->token
!= RPAREN
)
698 child
= stringparser_parse_element(parser
);
699 if ( t
==NULL
) { t
= child
; last
= t
; }
700 else { last
->right
= child
; last
= child
; }
702 stringparser_match(parser
,RPAREN
);
703 parser
->token
= stringscan_gettok(parser
->lexer
);
710 stringparser_parse_element(StringParser
*parser
)
712 stringparser_parse_element(parser
)
713 StringParser
*parser
;
716 static char ebuf
[100];
719 if ( parser
->token
== POUND
)
721 return stringparser_parse_tree(parser
);
723 if ( parser
->token
== PERCENT
)
725 parser
->token
= stringscan_gettok(parser
->lexer
);
726 stringparser_match(parser
,INT
);
727 label
= atoi(parser
->lexer
->text
);
728 parser
->num_labels
++;
729 if ( label
==0 ) sorcerer_panic("%%0 is an invalid label");
730 parser
->token
= stringscan_gettok(parser
->lexer
);
731 stringparser_match(parser
,COLON
);
732 parser
->token
= stringscan_gettok(parser
->lexer
);
733 /* can label tokens and wildcards */
734 if ( parser
->token
!= INT
&& parser
->token
!= PERIOD
)
735 sorcerer_panic("can only label tokens");
737 if ( parser
->token
== INT
)
739 ScanAST
*p
= new_scanast(atoi(parser
->lexer
->text
));
740 parser
->token
= stringscan_gettok(parser
->lexer
);
741 p
->label_num
= label
;
744 if ( parser
->token
== PERIOD
)
746 ScanAST
*p
= new_scanast(0); /* token of 0 is wildcard */
747 parser
->token
= stringscan_gettok(parser
->lexer
);
748 p
->label_num
= label
;
751 sprintf(ebuf
, "mismatch token in ast_scan(): %s", scan_token_str(parser
->token
));
752 sorcerer_panic(ebuf
);
753 return NULL
; /* MR20 make -Wall happy */
758 stringparser_init(StringParser
*parser
, StringLexer
*input
)
760 stringparser_init(parser
, input
)
761 StringParser
*parser
;
765 parser
->lexer
= input
;
766 parser
->token
= stringscan_gettok(parser
->lexer
);
767 parser
->num_labels
= 0;
772 stringlexer_init(StringLexer
*scanner
, char *input
)
774 stringlexer_init(scanner
, input
)
775 StringLexer
*scanner
;
779 scanner
->text
[0]='\0';
780 scanner
->input
= input
;
782 stringscan_advance(scanner
);
787 stringscan_advance(StringLexer
*scanner
)
789 stringscan_advance(scanner
)
790 StringLexer
*scanner
;
793 if ( *(scanner
->p
) == '\0' ) scanner
->c
= StringScanEOF
;
794 scanner
->c
= *(scanner
->p
)++;
799 stringscan_gettok(StringLexer
*scanner
)
801 stringscan_gettok(scanner
)
802 StringLexer
*scanner
;
805 char *index
= &scanner
->text
[0];
806 static char ebuf
[100];
808 while ( isspace(scanner
->c
) ) { stringscan_advance(scanner
); }
809 if ( isdigit(scanner
->c
) )
812 while ( isdigit(scanner
->c
) ) {
813 *index
++ = scanner
->c
;
814 stringscan_advance(scanner
);
819 switch ( scanner
->c
)
821 case '#' : stringscan_advance(scanner
); return POUND
;
822 case '(' : stringscan_advance(scanner
); return LPAREN
;
823 case ')' : stringscan_advance(scanner
); return RPAREN
;
824 case '%' : stringscan_advance(scanner
); return PERCENT
;
825 case ':' : stringscan_advance(scanner
); return COLON
;
826 case '.' : stringscan_advance(scanner
); return PERIOD
;
827 case '\0' : return StringScanEOF
;
828 case StringScanEOF
: return StringScanEOF
;
830 sprintf(ebuf
, "invalid char in ast_scan: '%c'", scanner
->c
);
831 sorcerer_panic(ebuf
);
832 return 0; /* MR20 Make -Wall happy */