]> pd.if.org Git - pccts/blob - antlr/build.c
auto commit for import
[pccts] / antlr / build.c
1 /*
2  * build.c -- functions associated with building syntax diagrams.
3  *
4  * $Id: build.c,v 1.3 95/06/15 18:07:00 parrt Exp $
5  * $Revision: 1.3 $
6  *
7  * SOFTWARE RIGHTS
8  *
9  * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
10  * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
11  * company may do whatever they wish with source code distributed with
12  * PCCTS or the code generated by PCCTS, including the incorporation of
13  * PCCTS, or its output, into commerical software.
14  * 
15  * We encourage users to develop software with PCCTS.  However, we do ask
16  * that credit is given to us for developing PCCTS.  By "credit",
17  * we mean that if you incorporate our source code into one of your
18  * programs (commercial product, research project, or otherwise) that you
19  * acknowledge this fact somewhere in the documentation, research report,
20  * etc...  If you like PCCTS and have developed a nice tool with the
21  * output, please mention that you developed it using PCCTS.  In
22  * addition, we ask that this header remain intact in our source code.
23  * As long as these guidelines are kept, we expect to continue enhancing
24  * this system and expect to make other tools available as they are
25  * completed.
26  *
27  * ANTLR 1.33
28  * Terence Parr
29  * Parr Research Corporation
30  * with Purdue University and AHPCRC, University of Minnesota
31  * 1989-1995
32  */
33 #include <stdio.h>
34 #ifdef __cplusplus
35 #ifndef __STDC__
36 #define __STDC__
37 #endif
38 #endif
39 #include "set.h"
40 #include "syn.h"
41 #include "hash.h"
42 #include "generic.h"
43 #include "dlgdef.h"
44
45 #define SetBlk(g, t, approx) {                                                                  \
46                         ((Junction *)g.left)->jtype = t;                                        \
47                         ((Junction *)g.left)->approx = approx;                          \
48                         ((Junction *)g.left)->end = (Junction *) g.right;       \
49                         ((Junction *)g.right)->jtype = EndBlk;}
50
51 /* Add the parameter string 'parm' to the parms field of a block-type junction
52  * g.left points to the sentinel node on a block.  i.e. g.left->p1 points to
53  * the actual junction with its jtype == some block-type.
54  */
55 void
56 #ifdef __STDC__
57 addParm( Node *p, char *parm )
58 #else
59 addParm( p, parm )
60 Node *p;
61 char *parm;
62 #endif
63 {
64         char *q = (char *) malloc( strlen(parm) + 1 );
65         require(p!=NULL, "addParm: NULL object\n");
66         require(q!=NULL, "addParm: unable to alloc parameter\n");
67
68         strcpy(q, parm);
69         if ( p->ntype == nRuleRef )
70         {
71                 ((RuleRefNode *)p)->parms = q;
72         }
73         else if ( p->ntype == nJunction )
74         {
75                 ((Junction *)p)->parm = q;      /* only one parameter allowed on subrules */
76         }
77         else fatal_internal("addParm: invalid node for adding parm");
78 }
79
80 /*
81  * Build an action node for the syntax diagram
82  *
83  * buildAction(ACTION) ::= --o-->ACTION-->o--
84  *
85  * Where o is a junction node.
86  */
87 Graph
88 #ifdef __STDC__
89 buildAction( char *action, int file, int line, int is_predicate )
90 #else
91 buildAction( action, file, line, is_predicate )
92 char *action;
93 int file;
94 int line;
95 int is_predicate;
96 #endif
97 {
98         Junction *j1, *j2;
99         Graph g;
100         ActionNode *a;
101         require(action!=NULL, "buildAction: invalid action");
102         
103         j1 = newJunction();
104         j2 = newJunction();
105         a = newActionNode();
106         a->action = (char *) malloc( strlen(action)+1 );
107         require(a->action!=NULL, "buildAction: cannot alloc space for action\n");
108         strcpy(a->action, action);
109         j1->p1 = (Node *) a;
110         a->next = (Node *) j2;
111         a->is_predicate = is_predicate;
112         g.left = (Node *) j1; g.right = (Node *) j2;
113         a->file = file;
114         a->line = line;
115         a->rname = "not filled in";
116         return g;
117 }
118
119 /*
120  * Build a token node for the syntax diagram
121  *
122  * buildToken(TOKEN) ::= --o-->TOKEN-->o--
123  *
124  * Where o is a junction node.
125  */
126 Graph
127 #ifdef __STDC__
128 buildToken( char *text )
129 #else
130 buildToken( text )
131 char *text;
132 #endif
133 {
134         Junction *j1, *j2;
135         Graph g;
136         TokNode *t;
137         require(text!=NULL, "buildToken: invalid token name");
138         
139         j1 = newJunction();
140         j2 = newJunction();
141         t = newTokNode();
142         t->altstart = CurAltStart;
143         if ( *text == '"' ) {t->label=FALSE; t->token = addTexpr( text );}
144         else {t->label=TRUE; t->token = addTname( text );}
145         j1->p1 = (Node *) t;
146         t->next = (Node *) j2;
147         g.left = (Node *) j1; g.right = (Node *) j2;
148         return g;
149 }
150
151 /*
152  * Build a wild-card node for the syntax diagram
153  *
154  * buildToken(TOKEN) ::= --o-->'.'-->o--
155  *
156  * Where o is a junction node.
157  */
158 Graph
159 #ifdef __STDC__
160 buildWildCard( char *text )
161 #else
162 buildWildCard( text )
163 char *text;
164 #endif
165 {
166         Junction *j1, *j2;
167         Graph g;
168         TokNode *t;
169         TCnode *w;
170         TermEntry *p;
171         require(text!=NULL, "buildWildCard: invalid token name");
172         
173         j1 = newJunction();
174         j2 = newJunction();
175         t = newTokNode();
176
177         /* If the ref a wild card, make a token class for it */
178         if ( Tnum(WildCardString) == 0 )
179         {
180                 w = newTCnode;
181                 w->tok = addTname( WildCardString );
182                 set_orel(w->tok, &imag_tokens);
183                 set_orel(w->tok, &tokclasses);
184                 WildCardToken = w->tok;
185                 require((p=(TermEntry *)hash_get(Tname, WildCardString)) != NULL,
186                                 "hash table mechanism is broken");
187                 p->classname = 1;       /* entry is class name, not token */
188                 p->tclass = w;          /* save ptr to this tclass def */
189                 list_add(&tclasses, (char *)w);
190         }
191         else {
192                 p=(TermEntry *)hash_get(Tname, WildCardString);
193                 require( p!= NULL, "hash table mechanism is broken");
194                 w = p->tclass;
195         }
196
197         t->token = w->tok;
198         t->wild_card = 1;
199         t->tclass = w;
200
201         t->altstart = CurAltStart;
202         j1->p1 = (Node *) t;
203         t->next = (Node *) j2;
204         g.left = (Node *) j1; g.right = (Node *) j2;
205         return g;
206 }
207
208 void
209 #ifdef __STDC__
210 setUpperRange(TokNode *t, char *text)
211 #else
212 setUpperRange(t, text)
213 TokNode *t;
214 char *text;
215 #endif
216 {
217         require(t!=NULL, "setUpperRange: NULL token node");
218         require(text!=NULL, "setUpperRange: NULL token string");
219
220         if ( *text == '"' ) {t->upper_range = addTexpr( text );}
221         else {t->upper_range = addTname( text );}
222 }
223
224 /*
225  * Build a rule reference node of the syntax diagram
226  *
227  * buildRuleRef(RULE) ::= --o-->RULE-->o--
228  *
229  * Where o is a junction node.
230  *
231  * If rule 'text' has been defined already, don't alloc new space to store string.
232  * Set r->text to point to old copy in string table.
233  */
234 Graph
235 #ifdef __STDC__
236 buildRuleRef( char *text )
237 #else
238 buildRuleRef( text )
239 char *text;
240 #endif
241 {
242         Junction *j1, *j2;
243         Graph g;
244         RuleRefNode *r;
245         RuleEntry *p;
246         require(text!=NULL, "buildRuleRef: invalid rule name");
247         
248         j1 = newJunction();
249         j2 = newJunction();
250         r = newRNode();
251         r->altstart = CurAltStart;
252         r->assign = NULL;
253         if ( (p=(RuleEntry *)hash_get(Rname, text)) != NULL ) r->text = p->str;
254         else r->text = mystrdup( text );
255         j1->p1  = (Node *) r;
256         r->next = (Node *) j2;
257         g.left = (Node *) j1; g.right = (Node *) j2;
258         return g;
259 }
260
261 /*
262  * Or two subgraphs into one graph via:
263  *
264  * Or(G1, G2) ::= --o-G1-o--
265  *                  |    ^
266  *                                      v    |
267  *                  o-G2-o
268  *
269  * Set the altnum of junction starting G2 to 1 + altnum of junction starting G1.
270  * If, however, the G1 altnum is 0, make it 1 and then
271  * make G2 altnum = G1 altnum + 1.
272  */
273 Graph
274 #ifdef __STDC__
275 Or( Graph g1, Graph g2 )
276 #else
277 Or( g1, g2 )
278 Graph g1;
279 Graph g2;
280 #endif
281 {
282         Graph g;
283         require(g1.left != NULL, "Or: invalid graph");
284         require(g2.left != NULL && g2.right != NULL, "Or: invalid graph");
285
286         ((Junction *)g1.left)->p2 = g2.left;
287         ((Junction *)g2.right)->p1 = g1.right;
288         /* set altnums */
289         if ( ((Junction *)g1.left)->altnum == 0 ) ((Junction *)g1.left)->altnum = 1;
290         ((Junction *)g2.left)->altnum = ((Junction *)g1.left)->altnum + 1;
291         g.left = g2.left;
292         g.right = g1.right;
293         return g;
294 }
295
296 /*
297  * Catenate two subgraphs
298  *
299  * Cat(G1, G2) ::= --o-G1-o-->o-G2-o--
300  * Cat(NULL,G2)::= --o-G2-o--
301  * Cat(G1,NULL)::= --o-G1-o--
302  */
303 Graph
304 #ifdef __STDC__
305 Cat( Graph g1, Graph g2 )
306 #else
307 Cat( g1, g2 )
308 Graph g1;
309 Graph g2;
310 #endif
311 {
312         Graph g;
313         
314         if ( g1.left == NULL && g1.right == NULL ) return g2;
315         if ( g2.left == NULL && g2.right == NULL ) return g1;
316         ((Junction *)g1.right)->p1 = g2.left;
317         g.left = g1.left;
318         g.right = g2.right;
319         return g;
320 }
321
322 /*
323  * Make a subgraph an optional block
324  *
325  * makeOpt(G) ::= --o-->o-G-o-->o--
326  *                      |           ^
327  *                                              v           |
328  *                                          o-------o
329  *
330  * Note that this constructs {A|B|...|Z} as if (A|B|...|Z|) was found.
331  *
332  * The node on the far right is added so that every block owns its own
333  * EndBlk node.
334  */
335 Graph
336 #ifdef __STDC__
337 makeOpt( Graph g1, int approx )
338 #else
339 makeOpt( g1, approx )
340 Graph g1;
341 int approx;
342 #endif
343 {
344         Junction *j1,*j2,*p;
345         Graph g;
346         require(g1.left != NULL && g1.right != NULL, "makeOpt: invalid graph");
347
348         j1 = newJunction();
349         j2 = newJunction();
350         ((Junction *)g1.right)->p1 = (Node *) j2;       /* add node to G at end */
351         g = emptyAlt();
352         if ( ((Junction *)g1.left)->altnum == 0 ) ((Junction *)g1.left)->altnum = 1;
353         ((Junction *)g.left)->altnum = ((Junction *)g1.left)->altnum + 1;
354         for(p=(Junction *)g1.left; p->p2!=NULL; p=(Junction *)p->p2)
355                 {;}                                                                             /* find last alt */
356         p->p2 = g.left;                                                         /* add optional alternative */
357         ((Junction *)g.right)->p1 = (Node *)j2;         /* opt alt points to EndBlk */
358         g1.right = (Node *)j2;
359         SetBlk(g1, aOptBlk, approx);
360         j1->p1 = g1.left;                                                       /* add generic node in front */
361         g.left = (Node *) j1;
362         g.right = g1.right;
363
364         return g;
365 }
366
367 /*
368  * Make a graph into subblock
369  *
370  * makeBlk(G) ::= --o-->o-G-o-->o--
371  *
372  * The node on the far right is added so that every block owns its own
373  * EndBlk node.
374  */
375 Graph
376 #ifdef __STDC__
377 makeBlk( Graph g1, int approx )
378 #else
379 makeBlk( g1, approx )
380 Graph g1;
381 int approx;
382 #endif
383 {
384         Junction *j,*j2;
385         Graph g;
386         require(g1.left != NULL && g1.right != NULL, "makeBlk: invalid graph");
387
388         j = newJunction();
389         j2 = newJunction();
390         ((Junction *)g1.right)->p1 = (Node *) j2;       /* add node to G at end */
391         g1.right = (Node *)j2;
392         SetBlk(g1, aSubBlk, approx);
393         j->p1 = g1.left;                                                        /* add node in front */
394         g.left = (Node *) j;
395         g.right = g1.right;
396
397         return g;
398 }
399
400 /*
401  * Make a subgraph into a loop (closure) block -- (...)*
402  *
403  * makeLoop(G) ::=       |---|
404  *                                           v   |
405  *                         --o-->o-->o-G-o-->o--
406  *                   |           ^
407  *                   v           |
408  *                                       o-----------o
409  *
410  * After making loop, always place generic node out front.  It becomes
411  * the start of enclosing block.  The aLoopBlk is the target of the loop.
412  *
413  * Loop blks have TWO EndBlk nodes--the far right and the node that loops back
414  * to the aLoopBlk node.  Node with which we can branch past loop == aLoopBegin and
415  * one which is loop target == aLoopBlk.
416  * The branch-past (initial) aLoopBegin node has end
417  * pointing to the last EndBlk node.  The loop-target node has end==NULL.
418  *
419  * Loop blocks have a set of locks (from 1..CLL_k) on the aLoopBlk node.
420  */
421 Graph
422 #ifdef __STDC__
423 makeLoop( Graph g1, int approx )
424 #else
425 makeLoop( g1, approx )
426 Graph g1;
427 int approx;
428 #endif
429 {
430         Junction *back, *front, *begin;
431         Graph g;
432         require(g1.left != NULL && g1.right != NULL, "makeLoop: invalid graph");
433
434         back = newJunction();
435         front = newJunction();
436         begin = newJunction();
437         g = emptyAlt();
438         ((Junction *)g1.right)->p2 = g1.left;           /* add loop branch to G */
439         ((Junction *)g1.right)->p1 = (Node *) back;     /* add node to G at end */
440         ((Junction *)g1.right)->jtype = EndBlk;         /* mark 1st EndBlk node */
441         ((Junction *)g1.left)->jtype = aLoopBlk;        /* mark 2nd aLoopBlk node */
442         ((Junction *)g1.left)->end = (Junction *) g1.right;
443         ((Junction *)g1.left)->lock = makelocks();
444         ((Junction *)g1.left)->pred_lock = makelocks();
445         g1.right = (Node *) back;
446         begin->p1 = (Node *) g1.left;
447         g1.left = (Node *) begin;
448         begin->p2 = (Node *) g.left;                            /* make bypass arc */
449         ((Junction *)g.right)->p1 = (Node *) back;
450         SetBlk(g1, aLoopBegin, approx);
451         front->p1 = g1.left;                                            /* add node to front */
452         g1.left = (Node *) front;
453
454         return g1;
455 }
456
457 /*
458  * Make a subgraph into a plus block -- (...)+ -- 1 or more times
459  *
460  * makePlus(G) ::=       |---|
461  *                                       v   |
462  *                         --o-->o-G-o-->o--
463  *
464  * After making loop, always place generic node out front.  It becomes
465  * the start of enclosing block.  The aPlusBlk is the target of the loop.
466  *
467  * Plus blks have TWO EndBlk nodes--the far right and the node that loops back
468  * to the aPlusBlk node.
469  *
470  * Plus blocks have a set of locks (from 1..CLL_k) on the aPlusBlk node.
471  */
472 Graph
473 #ifdef __STDC__
474 makePlus( Graph g1, int approx )
475 #else
476 makePlus( g1, approx )
477 Graph g1;
478 int approx;
479 #endif
480 {
481         int has_empty_alt_already = 0;
482         Graph g;
483         Junction *j2, *j3, *first_alt;
484         Junction *last_alt, *p;
485         require(g1.left != NULL && g1.right != NULL, "makePlus: invalid graph");
486
487         first_alt = (Junction *)g1.left;
488         j2 = newJunction();
489         j3 = newJunction();
490         if ( ((Junction *)g1.left)->altnum == 0 ) ((Junction *)g1.left)->altnum = 1;
491         ((Junction *)g1.right)->p2 = g1.left;           /* add loop branch to G */
492         ((Junction *)g1.right)->p1 = (Node *) j2;       /* add node to G at end */
493         ((Junction *)g1.right)->jtype = EndBlk;         /* mark 1st EndBlk node */
494         g1.right = (Node *) j2;
495         SetBlk(g1, aPlusBlk, approx);
496         ((Junction *)g1.left)->lock = makelocks();
497         ((Junction *)g1.left)->pred_lock = makelocks();
498         j3->p1 = g1.left;                                                       /* add node to front */
499         g1.left = (Node *) j3;
500
501         /* add an optional branch which is the "exit" branch of loop */
502         /* FIRST, check to ensure that there does not already exist
503          * an optional path.
504          */
505         /* find last alt */
506         for(p=first_alt; p!=NULL; p=(Junction *)p->p2)
507         {
508                 if ( p->p1->ntype == nJunction &&
509                          p->p1!=NULL &&
510                          ((Junction *)p->p1)->jtype==Generic &&
511                          ((Junction *)p->p1)->p1!=NULL &&
512                          ((Junction *)((Junction *)p->p1)->p1)->jtype==EndBlk )
513                 {
514                         has_empty_alt_already = 1;
515                 }
516                 last_alt = p;
517         }
518         if ( !has_empty_alt_already )
519         {
520                 require(last_alt!=NULL, "last_alt==NULL; bad (..)+");
521                 g = emptyAlt();
522                 last_alt->p2 = g.left;
523                 ((Junction *)g.right)->p1 = (Node *) j2;
524
525                 /* make sure lookahead computation ignores this alt for
526                 * FIRST("(..)+"); but it's still used for computing the FIRST
527                 * of each alternative.
528                 */
529                 ((Junction *)g.left)->ignore = 1;
530         }
531
532         return g1;
533 }
534
535 /*
536  * Return an optional path:  --o-->o--
537  */
538 Graph
539 #ifdef __STDC__
540 emptyAlt( void )
541 #else
542 emptyAlt( )
543 #endif
544 {
545         Junction *j1, *j2;
546         Graph g;
547
548         j1 = newJunction();
549         j2 = newJunction();
550         j1->p1 = (Node *) j2;
551         g.left = (Node *) j1;
552         g.right = (Node *) j2;
553         
554         return g;
555 }
556
557 /* N o d e  A l l o c a t i o n */
558
559 TokNode *
560 #ifdef __STDC__
561 newTokNode( void )
562 #else
563 newTokNode( )
564 #endif
565 {
566         static TokNode *FreeList = NULL;
567         TokNode *p, *newblk;
568
569         if ( FreeList == NULL )
570         {
571                 newblk = (TokNode *)calloc(TokenBlockAllocSize, sizeof(TokNode));
572                 if ( newblk == NULL )
573                         fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule));
574                 for (p=newblk; p<&(newblk[TokenBlockAllocSize]); p++)
575                 {
576                         p->next = (Node *)FreeList;     /* add all new token nodes to FreeList */
577                         FreeList = p;
578                 }
579         }
580         p = FreeList;
581         FreeList = (TokNode *)FreeList->next;/* remove a TokNode node */
582         p->next = NULL;                                         /* NULL the ptr we used */
583
584         p->ntype = nToken;
585         p->rname = CurRule;
586         p->file = CurFile;
587         p->line = zzline;
588         p->altstart = NULL;
589
590         return p;
591 }
592
593 RuleRefNode *
594 #ifdef __STDC__
595 newRNode( void )
596 #else
597 newRNode( )
598 #endif
599 {
600         static RuleRefNode *FreeList = NULL;
601         RuleRefNode *p, *newblk;
602
603         if ( FreeList == NULL )
604         {
605                 newblk = (RuleRefNode *)calloc(RRefBlockAllocSize, sizeof(RuleRefNode));
606                 if ( newblk == NULL )
607                         fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule));
608                 for (p=newblk; p<&(newblk[RRefBlockAllocSize]); p++)
609                 {
610                         p->next = (Node *)FreeList;     /* add all new rref nodes to FreeList */
611                         FreeList = p;
612                 }
613         }
614         p = FreeList;
615         FreeList = (RuleRefNode *)FreeList->next;/* remove a Junction node */
616         p->next = NULL;                                         /* NULL the ptr we used */
617
618         p->ntype = nRuleRef;
619         p->rname = CurRule;
620         p->file = CurFile;
621         p->line = zzline;
622         p->astnode = ASTinclude;
623         p->altstart = NULL;
624         
625         return p;
626 }
627
628 Junction *
629 #ifdef __STDC__
630 newJunction( void )
631 #else
632 newJunction( )
633 #endif
634 {
635         static Junction *FreeList = NULL;
636         Junction *p, *newblk;
637
638         if ( FreeList == NULL )
639         {
640                 newblk = (Junction *)calloc(JunctionBlockAllocSize, sizeof(Junction));
641                 if ( newblk == NULL )
642                         fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule));
643                 for (p=newblk; p<&(newblk[JunctionBlockAllocSize]); p++)
644                 {
645                         p->p1 = (Node *)FreeList;       /* add all new Junction nodes to FreeList */
646                         FreeList = p;
647                 }
648         }
649         p = FreeList;
650         FreeList = (Junction *)FreeList->p1;/* remove a Junction node */
651         p->p1 = NULL;                                           /* NULL the ptr we used */
652
653         p->ntype = nJunction;   p->visited = 0;
654         p->jtype = Generic;
655         p->rname = CurRule;
656         p->file = CurFile;
657         p->line = zzline;
658         p->exception_label = NULL;
659         p->fset = (set *) calloc(CLL_k+1, sizeof(set));
660         require(p->fset!=NULL, "cannot allocate fset in newJunction");
661
662         return p;
663 }
664
665 ActionNode *
666 #ifdef __STDC__
667 newActionNode( void )
668 #else
669 newActionNode( )
670 #endif
671 {
672         static ActionNode *FreeList = NULL;
673         ActionNode *p, *newblk;
674
675         if ( FreeList == NULL )
676         {
677                 newblk = (ActionNode *)calloc(ActionBlockAllocSize, sizeof(ActionNode));
678                 if ( newblk == NULL )
679                         fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule));
680                 for (p=newblk; p<&(newblk[ActionBlockAllocSize]); p++)
681                 {
682                         p->next = (Node *)FreeList;     /* add all new Action nodes to FreeList */
683                         FreeList = p;
684                 }
685         }
686         p = FreeList;
687         FreeList = (ActionNode *)FreeList->next;/* remove an Action node */
688         p->ntype = nAction;
689         p->next = NULL;                                         /* NULL the ptr we used */
690         p->done = 0;
691         p->pred_fail = NULL;
692         p->guardpred = NULL;
693
694         return p;
695 }
696
697 /*
698  * allocate the array of locks (1..CLL_k) used to inhibit infinite recursion.
699  * Infinite recursion can occur in (..)* blocks, FIRST calcs and FOLLOW calcs.
700  * Therefore, we need locks on aLoopBlk, RuleBlk, EndRule nodes.
701  *
702  * if ( lock[k]==TRUE ) then we have been here before looking for k tokens
703  * of lookahead.
704  */
705 char *
706 #ifdef __STDC__
707 makelocks( void )
708 #else
709 makelocks( )
710 #endif
711 {
712         char *p = (char *) calloc(CLL_k+1, sizeof(char));
713         require(p!=NULL, "cannot allocate lock array");
714         
715         return p;
716 }