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