| /* |
| * PCCTSAST.C |
| * |
| * SOFTWARE RIGHTS |
| * |
| * We reserve no LEGAL rights to SORCERER -- SORCERER is in the public |
| * domain. An individual or company may do whatever they wish with |
| * source code distributed with SORCERER or the code generated by |
| * SORCERER, including the incorporation of SORCERER, or its output, into |
| * commerical software. |
| * |
| * We encourage users to develop software with SORCERER. However, we do |
| * ask that credit is given to us for developing SORCERER. By "credit", |
| * we mean that if you incorporate our source code into one of your |
| * programs (commercial product, research project, or otherwise) that you |
| * acknowledge this fact somewhere in the documentation, research report, |
| * etc... If you like SORCERER and have developed a nice tool with the |
| * output, please mention that you developed it using SORCERER. In |
| * addition, we ask that this header remain intact in our source code. |
| * As long as these guidelines are kept, we expect to continue enhancing |
| * this system and expect to make other tools available as they are |
| * completed. |
| * |
| * SORCERER 1.00B14 and ANTLR 1.33 |
| * Terence Parr |
| * Parr Research Corporation |
| * AHPCRC, University of Minnesota |
| * 1992-1995 |
| */ |
| |
| #define ANTLR_SUPPORT_CODE |
| |
| #include "PCCTSAST.h" |
| #include <stdarg.h> |
| #include <ctype.h> |
| //#include "SList.h" |
| |
| /* String Scanning/Parsing Stuff */ |
| |
| char *PCCTS_AST::scan_token_tbl[] = { |
| "invalid", /* 0 */ |
| "LPAREN", /* 1 */ |
| "RPAREN", /* 2 */ |
| "PERCENT", /* 3 */ |
| "INT", /* 4 */ |
| "COLON", /* 5 */ |
| "POUND", /* 6 */ |
| "PERIOD", /* 7 */ |
| }; |
| |
| void PCCTS_AST:: |
| addChild(PCCTS_AST *t) |
| { |
| if ( t==NULL ) return; |
| PCCTS_AST *s = down(); |
| if ( s!=NULL ) |
| { |
| while ( s->right()!=NULL ) s = s->right(); |
| s->setRight(t); |
| } |
| else |
| this->setDown(t); |
| } |
| |
| void PCCTS_AST:: |
| lisp(FILE *f) |
| { |
| if ( down() != NULL ) fprintf(f," ("); |
| lisp_action(f); |
| if ( down()!=NULL ) down()->lisp(f); |
| if ( down() != NULL ) fprintf(f," )"); |
| if ( right()!=NULL ) right()->lisp(f); |
| } |
| |
| /* build a tree (root child1 child2 ... NULL) |
| * If root is NULL, simply make the children siblings and return ptr |
| * to 1st sibling (child1). If root is not single node, return NULL. |
| * |
| * Siblings that are actually sibling lists themselves are handled |
| * correctly. For example #( NULL, #( NULL, A, B, C), D) results |
| * in the tree ( NULL A B C D ). |
| * |
| * Requires at least two parameters with the last one being NULL. If |
| * both are NULL, return NULL. |
| * |
| * The down() and right() down/right pointers are used to make the tree. |
| */ |
| PCCTS_AST *PCCTS_AST:: |
| make(PCCTS_AST *rt, ...) |
| { |
| va_list ap; |
| register PCCTS_AST *child, *sibling=NULL, *tail, *w; |
| PCCTS_AST *root; |
| |
| va_start(ap, rt); |
| root = rt; |
| |
| if ( root != NULL ) |
| if ( root->down() != NULL ) return NULL; |
| child = va_arg(ap, PCCTS_AST *); |
| while ( child != NULL ) |
| { |
| /* find end of child */ |
| for (w=child; w->right()!=NULL; w=w->right()) {;} |
| if ( sibling == NULL ) {sibling = child; tail = w;} |
| else {tail->setRight(child); tail = w;} |
| child = va_arg(ap, PCCTS_AST *); |
| } |
| if ( root==NULL ) root = sibling; |
| else root->setDown(sibling); |
| va_end(ap); |
| return root; |
| } |
| |
| /* The following push and pop routines are only used by ast_find_all() */ |
| |
| void PCCTS_AST:: |
| _push(PCCTS_AST **st, int *sp, PCCTS_AST *e) |
| { |
| (*sp)--; |
| require((*sp)>=0, "stack overflow"); |
| st[(*sp)] = e; |
| } |
| |
| PCCTS_AST *PCCTS_AST:: |
| _pop(PCCTS_AST **st, int *sp) |
| { |
| PCCTS_AST *e = st[*sp]; |
| (*sp)++; |
| require((*sp)<=MaxTreeStackDepth, "stack underflow"); |
| return e; |
| } |
| |
| /* Find all occurrences of u in t. |
| * 'cursor' must be initialized to 't'. It eventually |
| * returns NULL when no more occurrences of 'u' are found. |
| */ |
| PCCTS_AST *PCCTS_AST:: |
| ast_find_all(PCCTS_AST *u, PCCTS_AST **cursor) |
| { |
| PCCTS_AST *sib; |
| static PCCTS_AST *template_stack[MaxTreeStackDepth]; |
| static int tsp = MaxTreeStackDepth; |
| static int nesting = 0; |
| |
| if ( *cursor == NULL ) return NULL; |
| if ( *cursor!=this ) sib = *cursor; |
| else { |
| /* else, first time--start at top of template 't' */ |
| tsp = MaxTreeStackDepth; |
| sib = this; |
| /* bottom of stack is always a NULL--"cookie" indicates "done" */ |
| _push(template_stack, &tsp, NULL); |
| } |
| |
| keep_looking: |
| if ( sib==NULL ) /* hit end of sibling list */ |
| { |
| sib = _pop(template_stack, &tsp); |
| if ( sib == NULL ) { *cursor = NULL; return NULL; } |
| } |
| |
| if ( sib->type() != u->type() ) |
| { |
| /* look for another match */ |
| if ( sib->down()!=NULL ) |
| { |
| if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right()); |
| sib=sib->down(); |
| goto keep_looking; |
| } |
| /* nothing below to try, try next sibling */ |
| sib=sib->right(); |
| goto keep_looking; |
| } |
| |
| /* found a matching root node, try to match what's below */ |
| if ( match_partial(sib, u) ) |
| { |
| /* record sibling cursor so we can pick up next from there */ |
| if ( sib->down()!=NULL ) |
| { |
| if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right()); |
| *cursor = sib->down(); |
| } |
| else if ( sib->right()!=NULL ) *cursor = sib->right(); |
| else *cursor = _pop(template_stack, &tsp); |
| return sib; |
| } |
| |
| /* no match, keep searching */ |
| if ( sib->down()!=NULL ) |
| { |
| if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right()); |
| sib=sib->down(); |
| } |
| else sib = sib->right(); /* else, try to right if zip below */ |
| goto keep_looking; |
| } |
| |
| /* are two trees exactly alike? */ |
| int PCCTS_AST:: |
| match(PCCTS_AST *u) |
| { |
| PCCTS_AST *t = this; |
| PCCTS_AST *sib; |
| |
| if ( u==NULL ) return 0; |
| |
| for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right()) |
| { |
| if ( sib->type() != u->type() ) return 0; |
| if ( sib->down()!=NULL ) |
| if ( !sib->down()->match(u->down()) ) return 0; |
| } |
| return 1; |
| } |
| |
| /* Is 'u' a subtree of 't' beginning at the root? */ |
| int PCCTS_AST:: |
| match_partial(PCCTS_AST *t, PCCTS_AST *u) |
| { |
| PCCTS_AST *sib; |
| |
| if ( u==NULL ) return 1; |
| if ( t==NULL ) if ( u!=NULL ) return 0; else return 1; |
| |
| for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right()) |
| { |
| if ( sib->type() != u->type() ) return 0; |
| if ( sib->down()!=NULL ) |
| if ( !match_partial(sib->down(), u->down()) ) return 0; |
| } |
| return 1; |
| } |
| |
| /* Walk the template tree 't' (matching against 'this'), filling in the |
| * 'labels' array, and setting 'n' according to how many labels were matched. |
| */ |
| int PCCTS_AST:: |
| scanmatch(ScanAST *t, PCCTS_AST **labels[], int *n) |
| { |
| ScanAST *sib; |
| PCCTS_AST *u = this; |
| |
| if ( u==NULL ) return 0; |
| |
| for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right()) |
| { |
| /* make sure tokens match; token of '0' means wildcard match */ |
| if ( sib->type() != u->type() && sib->type()!=0 ) return 0; |
| /* we have a matched token here; set label pointers if exists */ |
| if ( sib->label_num>0 ) |
| { |
| require(labels!=NULL, "label found in template, but no array of labels"); |
| (*n)++; |
| *(labels[sib->label_num-1]) = u; |
| } |
| /* match what's below if something there and current node is not wildcard */ |
| if ( sib->down()!=NULL && sib->type()!=0 ) |
| { |
| if ( sib->down()==NULL ) if ( u->down()!=NULL ) return 0; else return 1; |
| if ( !u->down()->scanmatch(sib->down(), labels, n) ) return 0; |
| } |
| } |
| return 1; |
| } |
| |
| void PCCTS_AST:: |
| insert_after(PCCTS_AST *b) |
| { |
| PCCTS_AST *end; |
| if ( b==NULL ) return; |
| /* find end of b's child list */ |
| for (end=b; end->right()!=NULL; end=end->right()) {;} |
| end->setRight(this->right()); |
| this->setRight(b); |
| } |
| |
| void PCCTS_AST:: |
| append(PCCTS_AST *b) |
| { |
| PCCTS_AST *end; |
| require(b!=NULL, "append: NULL input tree"); |
| /* find end of child list */ |
| for (end=this; end->right()!=NULL; end=end->right()) {;} |
| end->setRight(b); |
| } |
| |
| PCCTS_AST *PCCTS_AST:: |
| tail() |
| { |
| PCCTS_AST *end; |
| /* find end of child list */ |
| for (end=this; end->right()!=NULL; end=end->right()) {;} |
| return end; |
| } |
| |
| PCCTS_AST *PCCTS_AST:: |
| bottom() |
| { |
| PCCTS_AST *end; |
| /* find end of child list */ |
| for (end=this; end->down()!=NULL; end=end->down()) {;} |
| return end; |
| } |
| |
| PCCTS_AST *PCCTS_AST:: |
| cut_between(PCCTS_AST *a, PCCTS_AST *b) |
| { |
| PCCTS_AST *end, *ret; |
| if (a==NULL||b==NULL) return NULL; |
| /* find node pointing to b */ |
| for (end=a; end->right()!=NULL&&end->right()!=b; end=end->right()) |
| {;} |
| if (end->right()==NULL) return NULL; //ast_cut_between: a,b not connected |
| end->setRight(NULL); /* don't want it point to 'b' anymore */ |
| ret = a->right(); |
| a->setRight(b); |
| return ret; |
| } |
| |
| #ifdef NOT_YET |
| SList *PCCTS_AST:: |
| to_slist() |
| { |
| SList *list = new SList; |
| PCCTS_AST *p; |
| |
| for (p=this; p!=NULL; p=p->right()) |
| { |
| list->add(p); |
| } |
| return list; |
| } |
| #endif |
| |
| void PCCTS_AST:: |
| tfree() |
| { |
| PCCTS_AST *t = this; |
| if ( t->down()!=NULL ) t->down()->tfree(); |
| if ( t->right()!=NULL ) t->right()->tfree(); |
| delete t; |
| } |
| |
| int PCCTS_AST:: |
| nsiblings() |
| { |
| PCCTS_AST *t = this; |
| int n=0; |
| |
| while ( t!=NULL ) |
| { |
| n++; |
| t = t->right(); |
| } |
| return n; |
| } |
| |
| PCCTS_AST *PCCTS_AST:: |
| sibling_index(int i) |
| { |
| PCCTS_AST *t = this; |
| int j=1; |
| require(i>0, "sibling_index: i<=0"); |
| |
| while ( t!=NULL ) |
| { |
| if ( j==i ) return t; |
| j++; |
| t = t->right(); |
| } |
| return NULL; |
| } |
| |
| /* Assume this is a root node of a tree-- |
| * duplicate that node and what's below; ignore siblings of root node. |
| */ |
| PCCTS_AST *PCCTS_AST:: |
| deepCopy() |
| { |
| PCCTS_AST *u = this->shallowCopy(); |
| if ( down()!=NULL ) u->setDown(down()->deepCopy()); |
| return u; |
| } |
| |
| /* Copy all nodes including siblings of root. */ |
| PCCTS_AST *PCCTS_AST:: |
| deepCopyBushy() |
| { |
| PCCTS_AST *u = this->shallowCopy(); |
| /* copy the rest of the tree */ |
| if ( down()!=NULL ) u->setDown(down()->deepCopy()); |
| if ( right()!=NULL ) u->setRight(right()->deepCopy()); |
| return u; |
| } |
| |
| void PCCTS_AST:: |
| scanast_free(ScanAST *t) |
| { |
| if ( t == NULL ) return; |
| scanast_free( t->down() ); |
| scanast_free( t->right() ); |
| free( (char *) t ); // MR1 |
| } |
| |
| /* |
| * scan |
| * |
| * This function is like scanf(): it attempts to match a template |
| * against an input tree. A variable number of tree pointers |
| * may be set according to the '%i' labels in the template string. |
| * For example: |
| * |
| * t->ast_scan("#( 6 #(5 %1:4 %2:3) #(1 %3:3 %4:3) )", |
| * &w, &x, &y, &z); |
| * |
| * Naturally, you'd want this converted from |
| * |
| * t->ast_scan("#( RangeOp #(Minus %1:IConst %2:Var) #(Plus %3:Var %4Var) )", |
| * &w, &x, &y, &z); |
| * |
| * by SORCERER. |
| * |
| * This function call must be done withing a SORCERER file because SORCERER |
| * must convert the token references to the associated token number. |
| * |
| * This functions parses the template and creates trees which are then |
| * matched against the input tree. The labels are set as they are |
| * encountered; hence, partial matches may leave some pointers set |
| * and some NULL. This routines initializes all argument pointers to NULL |
| * at the beginning. |
| * |
| * This function returns the number of labels matched. |
| */ |
| int PCCTS_AST:: |
| ast_scan(char *templ, ...) |
| { |
| va_list ap; |
| ScanAST *tmpl; |
| int n, i, found=0; |
| PCCTS_AST ***label_ptrs=NULL; |
| |
| va_start(ap, templ); |
| |
| /* make a ScanAST tree out of the template */ |
| tmpl = stringparser_parse_scanast(templ, &n); |
| |
| /* make an array out of the labels */ |
| if ( n>0 ) |
| { |
| label_ptrs = (PCCTS_AST ***) calloc(n, sizeof(PCCTS_AST **)); |
| require(label_ptrs!=NULL, "scan: out of memory"); |
| for (i=1; i<=n; i++) |
| { |
| label_ptrs[i-1] = va_arg(ap, PCCTS_AST **); |
| *(label_ptrs[i-1]) = NULL; |
| } |
| } |
| |
| /* match the input tree against the template */ |
| scanmatch(tmpl, label_ptrs, &found); |
| |
| scanast_free(tmpl); |
| free( (char *) label_ptrs); // MR1 |
| |
| return found; |
| } |
| |
| ScanAST *PCCTS_AST:: |
| new_scanast(int tok) |
| { |
| ScanAST *p = (ScanAST *) calloc(1, sizeof(ScanAST)); |
| // |
| // 7-Apr-97 133MR1 |
| // |
| if ( p == NULL ) { // MR1 |
| fprintf(stderr, "out of mem\n"); // MR1 |
| exit(PCCTS_EXIT_FAILURE); // MR1 |
| }; // MR1 |
| p->_token = tok; |
| return p; |
| } |
| |
| ScanAST *PCCTS_AST:: |
| stringparser_parse_scanast(char *templ, int *num_labels) |
| { |
| StringLexer lex; |
| StringParser parser; |
| ScanAST *t; |
| |
| stringlexer_init(&lex, templ); |
| stringparser_init(&parser, &lex); |
| t = stringparser_parse_tree(&parser); |
| *num_labels = parser.num_labels; |
| return t; |
| } |
| |
| void PCCTS_AST:: |
| stringparser_match(StringParser *parser, int token) |
| { |
| if ( parser->token != token ) panic("bad tree in scan()"); |
| } |
| |
| /* |
| * Match a tree of the form: |
| * (root child1 child2 ... childn) |
| * or, |
| * node |
| * |
| * where the elements are integers or labeled integers. |
| */ |
| ScanAST *PCCTS_AST:: |
| stringparser_parse_tree(StringParser *parser) |
| { |
| ScanAST *t=NULL, *root, *child, *last; |
| |
| if ( parser->token != __POUND ) |
| { |
| return stringparser_parse_element(parser); |
| } |
| stringparser_match(parser,__POUND); |
| parser->token = stringscan_gettok(parser->lexer); |
| stringparser_match(parser,__LPAREN); |
| parser->token = stringscan_gettok(parser->lexer); |
| root = stringparser_parse_element(parser); |
| while ( parser->token != __RPAREN ) |
| { |
| child = stringparser_parse_element(parser); |
| if ( t==NULL ) { t = child; last = t; } |
| else { last->_right = child; last = child; } |
| } |
| stringparser_match(parser,__RPAREN); |
| parser->token = stringscan_gettok(parser->lexer); |
| root->_down = t; |
| return root; |
| } |
| |
| ScanAST *PCCTS_AST:: |
| stringparser_parse_element(StringParser *parser) |
| { |
| static char ebuf[100]; |
| int label = 0; |
| |
| if ( parser->token == __POUND ) |
| { |
| return stringparser_parse_tree(parser); |
| } |
| if ( parser->token == __PERCENT ) |
| { |
| parser->token = stringscan_gettok(parser->lexer); |
| stringparser_match(parser,__INT); |
| label = atoi(parser->lexer->text); |
| parser->num_labels++; |
| if ( label==0 ) panic("%%0 is an invalid label"); |
| parser->token = stringscan_gettok(parser->lexer); |
| stringparser_match(parser,__COLON); |
| parser->token = stringscan_gettok(parser->lexer); |
| /* can label tokens and wildcards */ |
| if ( parser->token != __INT && parser->token != __PERIOD ) |
| panic("can only label tokens"); |
| } |
| if ( parser->token == __INT ) |
| { |
| ScanAST *p = new_scanast(atoi(parser->lexer->text)); |
| parser->token = stringscan_gettok(parser->lexer); |
| p->label_num = label; |
| return p; |
| } |
| if ( parser->token == __PERIOD ) |
| { |
| ScanAST *p = new_scanast(0); /* token of 0 is wildcard */ |
| parser->token = stringscan_gettok(parser->lexer); |
| p->label_num = label; |
| return p; |
| } |
| sprintf(ebuf, "mismatch token in scan(): %s", scan_token_str(parser->token)); |
| panic(ebuf); |
| return NULL; |
| } |
| |
| void PCCTS_AST:: |
| stringparser_init(StringParser *parser, StringLexer *input) |
| { |
| parser->lexer = input; |
| parser->token = stringscan_gettok(parser->lexer); |
| parser->num_labels = 0; |
| } |
| |
| void PCCTS_AST:: |
| stringlexer_init(StringLexer *scanner, char *input) |
| { |
| scanner->text[0]='\0'; |
| scanner->input = input; |
| scanner->p = input; |
| stringscan_advance(scanner); |
| } |
| |
| void PCCTS_AST:: |
| stringscan_advance(StringLexer *scanner) |
| { |
| if ( *(scanner->p) == '\0' ) scanner->c = __StringScanEOF; |
| scanner->c = *(scanner->p)++; |
| } |
| |
| int PCCTS_AST:: |
| stringscan_gettok(StringLexer *scanner) |
| { |
| char *index = &scanner->text[0]; |
| static char ebuf[100]; |
| |
| while ( isspace(scanner->c) ) { stringscan_advance(scanner); } |
| if ( isdigit(scanner->c) ) |
| { |
| int tok = __INT; |
| while ( isdigit(scanner->c) ) { |
| *index++ = scanner->c; |
| stringscan_advance(scanner); |
| } |
| *index = '\0'; |
| return tok; |
| } |
| switch ( scanner->c ) |
| { |
| case '#' : stringscan_advance(scanner); return __POUND; |
| case '(' : stringscan_advance(scanner); return __LPAREN; |
| case ')' : stringscan_advance(scanner); return __RPAREN; |
| case '%' : stringscan_advance(scanner); return __PERCENT; |
| case ':' : stringscan_advance(scanner); return __COLON; |
| case '.' : stringscan_advance(scanner); return __PERIOD; |
| case '\0' : return __StringScanEOF; |
| case __StringScanEOF : return __StringScanEOF; |
| default : |
| sprintf(ebuf, "invalid char in scan: '%c'", scanner->c); |
| panic(ebuf); |
| } |
| return __StringScanEOF; // never reached |
| } |
| |
| char *PCCTS_AST:: |
| scan_token_str(int t) |
| { |
| if ( VALID_SCAN_TOKEN(t) ) return scan_token_tbl[t]; |
| else if ( t==__StringScanEOF ) return "<end-of-string>"; |
| else return "<invalid-token>"; |
| } |