]> pd.if.org Git - pccts/blobdiff - h/PCCTSAST.cpp
auto commit for import
[pccts] / h / PCCTSAST.cpp
diff --git a/h/PCCTSAST.cpp b/h/PCCTSAST.cpp
new file mode 100755 (executable)
index 0000000..12fd55e
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * 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( t );
+}
+
+/*
+ * 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(label_ptrs);
+
+       return found;
+}
+
+ScanAST *PCCTS_AST::
+new_scanast(int tok)
+{
+    ScanAST *p = (ScanAST *) calloc(1, sizeof(ScanAST));
+    if ( p == NULL ) {fprintf(stderr, "out of mem\n"); exit(EXIT_FAILURE);}
+       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>";
+}