mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-28 12:25:19 +01:00
814 lines
21 KiB
C
814 lines
21 KiB
C
|
/*
|
||
|
* build.c -- functions associated with building syntax diagrams.
|
||
|
*
|
||
|
* SOFTWARE RIGHTS
|
||
|
*
|
||
|
* We reserve no LEGAL rights to the Purdue Compiler Construction Tool
|
||
|
* Set (PCCTS) -- PCCTS is in the public domain. An individual or
|
||
|
* company may do whatever they wish with source code distributed with
|
||
|
* PCCTS or the code generated by PCCTS, including the incorporation of
|
||
|
* PCCTS, or its output, into commerical software.
|
||
|
*
|
||
|
* We encourage users to develop software with PCCTS. However, we do ask
|
||
|
* that credit is given to us for developing PCCTS. 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 PCCTS and have developed a nice tool with the
|
||
|
* output, please mention that you developed it using PCCTS. 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.
|
||
|
*
|
||
|
* ANTLR 1.33
|
||
|
* Terence Parr
|
||
|
* Parr Research Corporation
|
||
|
* with Purdue University and AHPCRC, University of Minnesota
|
||
|
* 1989-2001
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <ctype.h>
|
||
|
#include "pcctscfg.h"
|
||
|
#include "set.h"
|
||
|
#include "syn.h"
|
||
|
#include "hash.h"
|
||
|
#include "generic.h"
|
||
|
#include "dlgdef.h"
|
||
|
|
||
|
#define SetBlk(g, t, approx, first_set_symbol) { \
|
||
|
((Junction *)g.left)->jtype = t; \
|
||
|
((Junction *)g.left)->approx = approx; \
|
||
|
((Junction *)g.left)->pFirstSetSymbol = first_set_symbol; \
|
||
|
((Junction *)g.left)->end = (Junction *) g.right; \
|
||
|
((Junction *)g.right)->jtype = EndBlk;}
|
||
|
|
||
|
/* Add the parameter string 'parm' to the parms field of a block-type junction
|
||
|
* g.left points to the sentinel node on a block. i.e. g.left->p1 points to
|
||
|
* the actual junction with its jtype == some block-type.
|
||
|
*/
|
||
|
void
|
||
|
#ifdef __USE_PROTOS
|
||
|
addParm( Node *p, char *parm )
|
||
|
#else
|
||
|
addParm( p, parm )
|
||
|
Node *p;
|
||
|
char *parm;
|
||
|
#endif
|
||
|
{
|
||
|
char *q = (char *) malloc( strlen(parm) + 1 );
|
||
|
require(p!=NULL, "addParm: NULL object\n");
|
||
|
require(q!=NULL, "addParm: unable to alloc parameter\n");
|
||
|
|
||
|
strcpy(q, parm);
|
||
|
if ( p->ntype == nRuleRef )
|
||
|
{
|
||
|
((RuleRefNode *)p)->parms = q;
|
||
|
}
|
||
|
else if ( p->ntype == nJunction )
|
||
|
{
|
||
|
((Junction *)p)->parm = q; /* only one parameter allowed on subrules */
|
||
|
}
|
||
|
else fatal_internal("addParm: invalid node for adding parm");
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Build an action node for the syntax diagram
|
||
|
*
|
||
|
* buildAction(ACTION) ::= --o-->ACTION-->o--
|
||
|
*
|
||
|
* Where o is a junction node.
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
buildAction( char *action, int file, int line, int is_predicate )
|
||
|
#else
|
||
|
buildAction( action, file, line, is_predicate )
|
||
|
char *action;
|
||
|
int file;
|
||
|
int line;
|
||
|
int is_predicate;
|
||
|
#endif
|
||
|
{
|
||
|
Junction *j1, *j2;
|
||
|
Graph g;
|
||
|
ActionNode *a;
|
||
|
require(action!=NULL, "buildAction: invalid action");
|
||
|
|
||
|
j1 = newJunction();
|
||
|
j2 = newJunction();
|
||
|
a = newActionNode();
|
||
|
a->action = (char *) malloc( strlen(action)+1 );
|
||
|
require(a->action!=NULL, "buildAction: cannot alloc space for action\n");
|
||
|
strcpy(a->action, action);
|
||
|
j1->p1 = (Node *) a;
|
||
|
a->next = (Node *) j2;
|
||
|
a->is_predicate = is_predicate;
|
||
|
|
||
|
if (is_predicate) {
|
||
|
PredEntry *predEntry;
|
||
|
char *t;
|
||
|
char *key;
|
||
|
char *u;
|
||
|
int inverted=0;
|
||
|
|
||
|
t=key=(char *)calloc(1,strlen(a->action)+1);
|
||
|
|
||
|
for (u=a->action; *u != '\0' ; u++) {
|
||
|
if (*u != ' ') {
|
||
|
if (t==key && *u=='!') {
|
||
|
inverted=!inverted;
|
||
|
} else {
|
||
|
*t++=*u;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
*t='\0';
|
||
|
|
||
|
|
||
|
predEntry=(PredEntry *)hash_get(Pname,key);
|
||
|
a->predEntry=predEntry;
|
||
|
if (predEntry != NULL) a->inverted=inverted;
|
||
|
} else {
|
||
|
/* MR12c */ char *strStart=a->action;
|
||
|
/* MR12c */ char *strEnd;
|
||
|
/* MR12c */ strEnd=strStart+strlen(strStart)-1;
|
||
|
/* MR12c */ for ( ; strEnd >= strStart && isspace(*strEnd); strEnd--) *strEnd=0;
|
||
|
/* MR12c */ while (*strStart != '\0' && isspace(*strStart)) strStart++;
|
||
|
/* MR12c */ if (ci_strequ(strStart,"nohoist")) {
|
||
|
/* MR12c */ a->noHoist=1;
|
||
|
/* MR12c */ }
|
||
|
}
|
||
|
|
||
|
g.left = (Node *) j1; g.right = (Node *) j2;
|
||
|
a->file = file;
|
||
|
a->line = line;
|
||
|
a->rname = CurRule; /* MR10 */
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Build a token node for the syntax diagram
|
||
|
*
|
||
|
* buildToken(TOKEN) ::= --o-->TOKEN-->o--
|
||
|
*
|
||
|
* Where o is a junction node.
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
buildToken( char *text )
|
||
|
#else
|
||
|
buildToken( text )
|
||
|
char *text;
|
||
|
#endif
|
||
|
{
|
||
|
Junction *j1, *j2;
|
||
|
Graph g;
|
||
|
TokNode *t;
|
||
|
require(text!=NULL, "buildToken: invalid token name");
|
||
|
|
||
|
j1 = newJunction();
|
||
|
j2 = newJunction();
|
||
|
t = newTokNode();
|
||
|
t->altstart = CurAltStart;
|
||
|
if ( *text == '"' ) {t->label=FALSE; t->token = addTexpr( text );}
|
||
|
else {t->label=TRUE; t->token = addTname( text );}
|
||
|
j1->p1 = (Node *) t;
|
||
|
t->next = (Node *) j2;
|
||
|
g.left = (Node *) j1; g.right = (Node *) j2;
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Build a wild-card node for the syntax diagram
|
||
|
*
|
||
|
* buildToken(TOKEN) ::= --o-->'.'-->o--
|
||
|
*
|
||
|
* Where o is a junction node.
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
buildWildCard( char *text )
|
||
|
#else
|
||
|
buildWildCard( text )
|
||
|
char *text;
|
||
|
#endif
|
||
|
{
|
||
|
Junction *j1, *j2;
|
||
|
Graph g;
|
||
|
TokNode *t;
|
||
|
TCnode *w;
|
||
|
TermEntry *p;
|
||
|
require(text!=NULL, "buildWildCard: invalid token name");
|
||
|
|
||
|
j1 = newJunction();
|
||
|
j2 = newJunction();
|
||
|
t = newTokNode();
|
||
|
|
||
|
/* If the ref a wild card, make a token class for it */
|
||
|
if ( Tnum(WildCardString) == 0 )
|
||
|
{
|
||
|
w = newTCnode;
|
||
|
w->tok = addTname( WildCardString );
|
||
|
set_orel(w->tok, &imag_tokens);
|
||
|
set_orel(w->tok, &tokclasses);
|
||
|
WildCardToken = w->tok;
|
||
|
require((p=(TermEntry *)hash_get(Tname, WildCardString)) != NULL,
|
||
|
"hash table mechanism is broken");
|
||
|
p->classname = 1; /* entry is class name, not token */
|
||
|
p->tclass = w; /* save ptr to this tclass def */
|
||
|
list_add(&tclasses, (char *)w);
|
||
|
}
|
||
|
else {
|
||
|
p=(TermEntry *)hash_get(Tname, WildCardString);
|
||
|
require( p!= NULL, "hash table mechanism is broken");
|
||
|
w = p->tclass;
|
||
|
}
|
||
|
|
||
|
t->token = w->tok;
|
||
|
t->wild_card = 1;
|
||
|
t->tclass = w;
|
||
|
|
||
|
t->altstart = CurAltStart;
|
||
|
j1->p1 = (Node *) t;
|
||
|
t->next = (Node *) j2;
|
||
|
g.left = (Node *) j1; g.right = (Node *) j2;
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
#ifdef __USE_PROTOS
|
||
|
setUpperRange(TokNode *t, char *text)
|
||
|
#else
|
||
|
setUpperRange(t, text)
|
||
|
TokNode *t;
|
||
|
char *text;
|
||
|
#endif
|
||
|
{
|
||
|
require(t!=NULL, "setUpperRange: NULL token node");
|
||
|
require(text!=NULL, "setUpperRange: NULL token string");
|
||
|
|
||
|
if ( *text == '"' ) {t->upper_range = addTexpr( text );}
|
||
|
else {t->upper_range = addTname( text );}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Build a rule reference node of the syntax diagram
|
||
|
*
|
||
|
* buildRuleRef(RULE) ::= --o-->RULE-->o--
|
||
|
*
|
||
|
* Where o is a junction node.
|
||
|
*
|
||
|
* If rule 'text' has been defined already, don't alloc new space to store string.
|
||
|
* Set r->text to point to old copy in string table.
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
buildRuleRef( char *text )
|
||
|
#else
|
||
|
buildRuleRef( text )
|
||
|
char *text;
|
||
|
#endif
|
||
|
{
|
||
|
Junction *j1, *j2;
|
||
|
Graph g;
|
||
|
RuleRefNode *r;
|
||
|
RuleEntry *p;
|
||
|
require(text!=NULL, "buildRuleRef: invalid rule name");
|
||
|
|
||
|
j1 = newJunction();
|
||
|
j2 = newJunction();
|
||
|
r = newRNode();
|
||
|
r->altstart = CurAltStart;
|
||
|
r->assign = NULL;
|
||
|
if ( (p=(RuleEntry *)hash_get(Rname, text)) != NULL ) r->text = p->str;
|
||
|
else r->text = mystrdup( text );
|
||
|
j1->p1 = (Node *) r;
|
||
|
r->next = (Node *) j2;
|
||
|
g.left = (Node *) j1; g.right = (Node *) j2;
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Or two subgraphs into one graph via:
|
||
|
*
|
||
|
* Or(G1, G2) ::= --o-G1-o--
|
||
|
* | ^
|
||
|
* v |
|
||
|
* o-G2-o
|
||
|
*
|
||
|
* Set the altnum of junction starting G2 to 1 + altnum of junction starting G1.
|
||
|
* If, however, the G1 altnum is 0, make it 1 and then
|
||
|
* make G2 altnum = G1 altnum + 1.
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
Or( Graph g1, Graph g2 )
|
||
|
#else
|
||
|
Or( g1, g2 )
|
||
|
Graph g1;
|
||
|
Graph g2;
|
||
|
#endif
|
||
|
{
|
||
|
Graph g;
|
||
|
require(g1.left != NULL, "Or: invalid graph");
|
||
|
require(g2.left != NULL && g2.right != NULL, "Or: invalid graph");
|
||
|
|
||
|
((Junction *)g1.left)->p2 = g2.left;
|
||
|
((Junction *)g2.right)->p1 = g1.right;
|
||
|
/* set altnums */
|
||
|
if ( ((Junction *)g1.left)->altnum == 0 ) ((Junction *)g1.left)->altnum = 1;
|
||
|
((Junction *)g2.left)->altnum = ((Junction *)g1.left)->altnum + 1;
|
||
|
g.left = g2.left;
|
||
|
g.right = g1.right;
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Catenate two subgraphs
|
||
|
*
|
||
|
* Cat(G1, G2) ::= --o-G1-o-->o-G2-o--
|
||
|
* Cat(NULL,G2)::= --o-G2-o--
|
||
|
* Cat(G1,NULL)::= --o-G1-o--
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
Cat( Graph g1, Graph g2 )
|
||
|
#else
|
||
|
Cat( g1, g2 )
|
||
|
Graph g1;
|
||
|
Graph g2;
|
||
|
#endif
|
||
|
{
|
||
|
Graph g;
|
||
|
|
||
|
if ( g1.left == NULL && g1.right == NULL ) return g2;
|
||
|
if ( g2.left == NULL && g2.right == NULL ) return g1;
|
||
|
((Junction *)g1.right)->p1 = g2.left;
|
||
|
g.left = g1.left;
|
||
|
g.right = g2.right;
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Make a subgraph an optional block
|
||
|
*
|
||
|
* makeOpt(G) ::= --o-->o-G-o-->o--
|
||
|
* | ^
|
||
|
* v |
|
||
|
* o-------o
|
||
|
*
|
||
|
* Note that this constructs {A|B|...|Z} as if (A|B|...|Z|) was found.
|
||
|
*
|
||
|
* The node on the far right is added so that every block owns its own
|
||
|
* EndBlk node.
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
makeOpt( Graph g1, int approx, char * pFirstSetSymbol )
|
||
|
#else
|
||
|
makeOpt( g1, approx, pFirstSetSymbol )
|
||
|
Graph g1;
|
||
|
int approx;
|
||
|
char * pFirstSetSymbol;
|
||
|
#endif
|
||
|
{
|
||
|
Junction *j1,*j2,*p;
|
||
|
Graph g;
|
||
|
require(g1.left != NULL && g1.right != NULL, "makeOpt: invalid graph");
|
||
|
|
||
|
j1 = newJunction();
|
||
|
j2 = newJunction();
|
||
|
((Junction *)g1.right)->p1 = (Node *) j2; /* add node to G at end */
|
||
|
|
||
|
/* MR21
|
||
|
*
|
||
|
* There is code in genBlk which recognizes the node created
|
||
|
* by emptyAlt() as a special case and bypasses it. We don't
|
||
|
* want this to happen for the optBlk.
|
||
|
*/
|
||
|
|
||
|
g = emptyAlt3(); /* MR21 */
|
||
|
if ( ((Junction *)g1.left)->altnum == 0 ) ((Junction *)g1.left)->altnum = 1;
|
||
|
((Junction *)g.left)->altnum = ((Junction *)g1.left)->altnum + 1;
|
||
|
for(p=(Junction *)g1.left; p->p2!=NULL; p=(Junction *)p->p2)
|
||
|
{;} /* find last alt */
|
||
|
p->p2 = g.left; /* add optional alternative */
|
||
|
((Junction *)g.right)->p1 = (Node *)j2; /* opt alt points to EndBlk */
|
||
|
g1.right = (Node *)j2;
|
||
|
SetBlk(g1, aOptBlk, approx, pFirstSetSymbol);
|
||
|
j1->p1 = g1.left; /* add generic node in front */
|
||
|
g.left = (Node *) j1;
|
||
|
g.right = g1.right;
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Make a graph into subblock
|
||
|
*
|
||
|
* makeBlk(G) ::= --o-->o-G-o-->o--
|
||
|
*
|
||
|
* The node on the far right is added so that every block owns its own
|
||
|
* EndBlk node.
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
makeBlk( Graph g1, int approx, char * pFirstSetSymbol )
|
||
|
#else
|
||
|
makeBlk( g1, approx, pFirstSetSymbol )
|
||
|
Graph g1;
|
||
|
int approx;
|
||
|
char * pFirstSetSymbol;
|
||
|
#endif
|
||
|
{
|
||
|
Junction *j,*j2;
|
||
|
Graph g;
|
||
|
require(g1.left != NULL && g1.right != NULL, "makeBlk: invalid graph");
|
||
|
|
||
|
j = newJunction();
|
||
|
j2 = newJunction();
|
||
|
((Junction *)g1.right)->p1 = (Node *) j2; /* add node to G at end */
|
||
|
g1.right = (Node *)j2;
|
||
|
SetBlk(g1, aSubBlk, approx, pFirstSetSymbol);
|
||
|
j->p1 = g1.left; /* add node in front */
|
||
|
g.left = (Node *) j;
|
||
|
g.right = g1.right;
|
||
|
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Make a subgraph into a loop (closure) block -- (...)*
|
||
|
*
|
||
|
* makeLoop(G) ::= |---|
|
||
|
* v |
|
||
|
* --o-->o-->o-G-o-->o--
|
||
|
* | ^
|
||
|
* v |
|
||
|
* o-----------o
|
||
|
*
|
||
|
* After making loop, always place generic node out front. It becomes
|
||
|
* the start of enclosing block. The aLoopBlk is the target of the loop.
|
||
|
*
|
||
|
* Loop blks have TWO EndBlk nodes--the far right and the node that loops back
|
||
|
* to the aLoopBlk node. Node with which we can branch past loop == aLoopBegin and
|
||
|
* one which is loop target == aLoopBlk.
|
||
|
* The branch-past (initial) aLoopBegin node has end
|
||
|
* pointing to the last EndBlk node. The loop-target node has end==NULL.
|
||
|
*
|
||
|
* Loop blocks have a set of locks (from 1..CLL_k) on the aLoopBlk node.
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
makeLoop( Graph g1, int approx, char * pFirstSetSymbol )
|
||
|
#else
|
||
|
makeLoop( g1, approx, pFirstSetSymbol)
|
||
|
Graph g1;
|
||
|
int approx;
|
||
|
char * pFirstSetSymbol;
|
||
|
#endif
|
||
|
{
|
||
|
Junction *back, *front, *begin;
|
||
|
Graph g;
|
||
|
require(g1.left != NULL && g1.right != NULL, "makeLoop: invalid graph");
|
||
|
|
||
|
back = newJunction();
|
||
|
front = newJunction();
|
||
|
begin = newJunction();
|
||
|
g = emptyAlt3();
|
||
|
((Junction *)g1.right)->p2 = g1.left; /* add loop branch to G */
|
||
|
((Junction *)g1.right)->p1 = (Node *) back; /* add node to G at end */
|
||
|
((Junction *)g1.right)->jtype = EndBlk; /* mark 1st EndBlk node */
|
||
|
((Junction *)g1.left)->jtype = aLoopBlk; /* mark 2nd aLoopBlk node */
|
||
|
((Junction *)g1.left)->end = (Junction *) g1.right;
|
||
|
((Junction *)g1.left)->lock = makelocks();
|
||
|
((Junction *)g1.left)->pred_lock = makelocks();
|
||
|
g1.right = (Node *) back;
|
||
|
begin->p1 = (Node *) g1.left;
|
||
|
g1.left = (Node *) begin;
|
||
|
begin->p2 = (Node *) g.left; /* make bypass arc */
|
||
|
((Junction *)g.right)->p1 = (Node *) back;
|
||
|
SetBlk(g1, aLoopBegin, approx, pFirstSetSymbol);
|
||
|
front->p1 = g1.left; /* add node to front */
|
||
|
g1.left = (Node *) front;
|
||
|
|
||
|
return g1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Make a subgraph into a plus block -- (...)+ -- 1 or more times
|
||
|
*
|
||
|
* makePlus(G) ::= |---|
|
||
|
* v |
|
||
|
* --o-->o-G-o-->o--
|
||
|
*
|
||
|
* After making loop, always place generic node out front. It becomes
|
||
|
* the start of enclosing block. The aPlusBlk is the target of the loop.
|
||
|
*
|
||
|
* Plus blks have TWO EndBlk nodes--the far right and the node that loops back
|
||
|
* to the aPlusBlk node.
|
||
|
*
|
||
|
* Plus blocks have a set of locks (from 1..CLL_k) on the aPlusBlk node.
|
||
|
*/
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
makePlus( Graph g1, int approx, char * pFirstSetSymbol)
|
||
|
#else
|
||
|
makePlus( g1, approx, pFirstSetSymbol)
|
||
|
Graph g1;
|
||
|
int approx;
|
||
|
char * pFirstSetSymbol;
|
||
|
#endif
|
||
|
{
|
||
|
int has_empty_alt_already = 0;
|
||
|
Graph g;
|
||
|
Junction *j2, *j3, *first_alt;
|
||
|
Junction *last_alt=NULL, *p;
|
||
|
require(g1.left != NULL && g1.right != NULL, "makePlus: invalid graph");
|
||
|
|
||
|
first_alt = (Junction *)g1.left;
|
||
|
j2 = newJunction();
|
||
|
j3 = newJunction();
|
||
|
if ( ((Junction *)g1.left)->altnum == 0 ) ((Junction *)g1.left)->altnum = 1;
|
||
|
((Junction *)g1.right)->p2 = g1.left; /* add loop branch to G */
|
||
|
((Junction *)g1.right)->p1 = (Node *) j2; /* add node to G at end */
|
||
|
((Junction *)g1.right)->jtype = EndBlk; /* mark 1st EndBlk node */
|
||
|
g1.right = (Node *) j2;
|
||
|
SetBlk(g1, aPlusBlk, approx, pFirstSetSymbol);
|
||
|
((Junction *)g1.left)->lock = makelocks();
|
||
|
((Junction *)g1.left)->pred_lock = makelocks();
|
||
|
j3->p1 = g1.left; /* add node to front */
|
||
|
g1.left = (Node *) j3;
|
||
|
|
||
|
/* add an optional branch which is the "exit" branch of loop */
|
||
|
/* FIRST, check to ensure that there does not already exist
|
||
|
* an optional path.
|
||
|
*/
|
||
|
/* find last alt */
|
||
|
for(p=first_alt; p!=NULL; p=(Junction *)p->p2)
|
||
|
{
|
||
|
if ( p->p1->ntype == nJunction &&
|
||
|
p->p1!=NULL &&
|
||
|
((Junction *)p->p1)->jtype==Generic &&
|
||
|
((Junction *)p->p1)->p1!=NULL &&
|
||
|
((Junction *)((Junction *)p->p1)->p1)->jtype==EndBlk )
|
||
|
{
|
||
|
has_empty_alt_already = 1;
|
||
|
}
|
||
|
last_alt = p;
|
||
|
}
|
||
|
if ( !has_empty_alt_already )
|
||
|
{
|
||
|
require(last_alt!=NULL, "last_alt==NULL; bad (..)+");
|
||
|
g = emptyAlt();
|
||
|
last_alt->p2 = g.left;
|
||
|
((Junction *)g.right)->p1 = (Node *) j2;
|
||
|
|
||
|
/* make sure lookahead computation ignores this alt for
|
||
|
* FIRST("(..)+"); but it's still used for computing the FIRST
|
||
|
* of each alternative.
|
||
|
*/
|
||
|
((Junction *)g.left)->ignore = 1;
|
||
|
}
|
||
|
|
||
|
return g1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Return an optional path: --o-->o--
|
||
|
*/
|
||
|
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
emptyAlt( void )
|
||
|
#else
|
||
|
emptyAlt( )
|
||
|
#endif
|
||
|
{
|
||
|
Junction *j1, *j2;
|
||
|
Graph g;
|
||
|
|
||
|
j1 = newJunction();
|
||
|
j2 = newJunction();
|
||
|
j1->p1 = (Node *) j2;
|
||
|
g.left = (Node *) j1;
|
||
|
g.right = (Node *) j2;
|
||
|
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
/* MR21
|
||
|
*
|
||
|
* There is code in genBlk which recognizes the node created
|
||
|
* by emptyAlt() as a special case and bypasses it. We don't
|
||
|
* want this to happen for the optBlk.
|
||
|
*/
|
||
|
|
||
|
Graph
|
||
|
#ifdef __USE_PROTOS
|
||
|
emptyAlt3( void )
|
||
|
#else
|
||
|
emptyAlt3( )
|
||
|
#endif
|
||
|
{
|
||
|
Junction *j1, *j2, *j3;
|
||
|
Graph g;
|
||
|
|
||
|
j1 = newJunction();
|
||
|
j2 = newJunction();
|
||
|
j3 = newJunction();
|
||
|
j1->p1 = (Node *) j2;
|
||
|
j2->p1 = (Node *) j3;
|
||
|
g.left = (Node *) j1;
|
||
|
g.right = (Node *) j3;
|
||
|
|
||
|
return g;
|
||
|
}
|
||
|
|
||
|
/* N o d e A l l o c a t i o n */
|
||
|
|
||
|
TokNode *
|
||
|
#ifdef __USE_PROTOS
|
||
|
newTokNode( void )
|
||
|
#else
|
||
|
newTokNode( )
|
||
|
#endif
|
||
|
{
|
||
|
static TokNode *FreeList = NULL;
|
||
|
TokNode *p, *newblk;
|
||
|
|
||
|
if ( FreeList == NULL )
|
||
|
{
|
||
|
newblk = (TokNode *)calloc(TokenBlockAllocSize, sizeof(TokNode));
|
||
|
if ( newblk == NULL )
|
||
|
fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule));
|
||
|
for (p=newblk; p<&(newblk[TokenBlockAllocSize]); p++)
|
||
|
{
|
||
|
p->next = (Node *)FreeList; /* add all new token nodes to FreeList */
|
||
|
FreeList = p;
|
||
|
}
|
||
|
}
|
||
|
p = FreeList;
|
||
|
FreeList = (TokNode *)FreeList->next;/* remove a TokNode node */
|
||
|
p->next = NULL; /* NULL the ptr we used */
|
||
|
memset( (char *) p, 0, sizeof(TokNode)); /* MR10 */
|
||
|
p->ntype = nToken;
|
||
|
p->rname = CurRule;
|
||
|
p->file = CurFile;
|
||
|
p->line = zzline;
|
||
|
p->altstart = NULL;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
RuleRefNode *
|
||
|
#ifdef __USE_PROTOS
|
||
|
newRNode( void )
|
||
|
#else
|
||
|
newRNode( )
|
||
|
#endif
|
||
|
{
|
||
|
static RuleRefNode *FreeList = NULL;
|
||
|
RuleRefNode *p, *newblk;
|
||
|
|
||
|
if ( FreeList == NULL )
|
||
|
{
|
||
|
newblk = (RuleRefNode *)calloc(RRefBlockAllocSize, sizeof(RuleRefNode));
|
||
|
if ( newblk == NULL )
|
||
|
fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule));
|
||
|
for (p=newblk; p<&(newblk[RRefBlockAllocSize]); p++)
|
||
|
{
|
||
|
p->next = (Node *)FreeList; /* add all new rref nodes to FreeList */
|
||
|
FreeList = p;
|
||
|
}
|
||
|
}
|
||
|
p = FreeList;
|
||
|
FreeList = (RuleRefNode *)FreeList->next;/* remove a Junction node */
|
||
|
p->next = NULL; /* NULL the ptr we used */
|
||
|
memset( (char *) p, 0, sizeof(RuleRefNode)); /* MR10 */
|
||
|
p->ntype = nRuleRef;
|
||
|
p->rname = CurRule;
|
||
|
p->file = CurFile;
|
||
|
p->line = zzline;
|
||
|
p->astnode = ASTinclude;
|
||
|
p->altstart = NULL;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
static int junctionSeqNumber=0; /* MR10 */
|
||
|
|
||
|
Junction *
|
||
|
#ifdef __USE_PROTOS
|
||
|
newJunction( void )
|
||
|
#else
|
||
|
newJunction( )
|
||
|
#endif
|
||
|
{
|
||
|
static Junction *FreeList = NULL;
|
||
|
Junction *p, *newblk;
|
||
|
|
||
|
if ( FreeList == NULL )
|
||
|
{
|
||
|
newblk = (Junction *)calloc(JunctionBlockAllocSize, sizeof(Junction));
|
||
|
if ( newblk == NULL )
|
||
|
fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule));
|
||
|
for (p=newblk; p<&(newblk[JunctionBlockAllocSize]); p++)
|
||
|
{
|
||
|
p->p1 = (Node *)FreeList; /* add all new Junction nodes to FreeList */
|
||
|
FreeList = p;
|
||
|
}
|
||
|
}
|
||
|
p = FreeList;
|
||
|
FreeList = (Junction *)FreeList->p1;/* remove a Junction node */
|
||
|
p->p1 = NULL; /* NULL the ptr we used */
|
||
|
memset( (char *) p, 0, sizeof(Junction)); /* MR10 */
|
||
|
p->ntype = nJunction;
|
||
|
p->visited = 0;
|
||
|
p->jtype = Generic;
|
||
|
p->rname = CurRule;
|
||
|
p->file = CurFile;
|
||
|
p->line = zzline;
|
||
|
p->exception_label = NULL;
|
||
|
p->fset = (set *) calloc(CLL_k+1, sizeof(set));
|
||
|
require(p->fset!=NULL, "cannot allocate fset in newJunction");
|
||
|
p->seq=++junctionSeqNumber; /* MR10 */
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
ActionNode *
|
||
|
#ifdef __USE_PROTOS
|
||
|
newActionNode( void )
|
||
|
#else
|
||
|
newActionNode( )
|
||
|
#endif
|
||
|
{
|
||
|
static ActionNode *FreeList = NULL;
|
||
|
ActionNode *p, *newblk;
|
||
|
|
||
|
if ( FreeList == NULL )
|
||
|
{
|
||
|
newblk = (ActionNode *)calloc(ActionBlockAllocSize, sizeof(ActionNode));
|
||
|
if ( newblk == NULL )
|
||
|
fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule));
|
||
|
for (p=newblk; p<&(newblk[ActionBlockAllocSize]); p++)
|
||
|
{
|
||
|
p->next = (Node *)FreeList; /* add all new Action nodes to FreeList */
|
||
|
FreeList = p;
|
||
|
}
|
||
|
}
|
||
|
p = FreeList;
|
||
|
FreeList = (ActionNode *)FreeList->next;/* remove an Action node */
|
||
|
memset( (char *) p, 0, sizeof(ActionNode)); /* MR10 */
|
||
|
p->ntype = nAction;
|
||
|
p->next = NULL; /* NULL the ptr we used */
|
||
|
p->done = 0;
|
||
|
p->pred_fail = NULL;
|
||
|
p->guardpred = NULL;
|
||
|
p->ampersandPred = NULL;
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* allocate the array of locks (1..CLL_k) used to inhibit infinite recursion.
|
||
|
* Infinite recursion can occur in (..)* blocks, FIRST calcs and FOLLOW calcs.
|
||
|
* Therefore, we need locks on aLoopBlk, RuleBlk, EndRule nodes.
|
||
|
*
|
||
|
* if ( lock[k]==TRUE ) then we have been here before looking for k tokens
|
||
|
* of lookahead.
|
||
|
*/
|
||
|
char *
|
||
|
#ifdef __USE_PROTOS
|
||
|
makelocks( void )
|
||
|
#else
|
||
|
makelocks( )
|
||
|
#endif
|
||
|
{
|
||
|
char *p = (char *) calloc(CLL_k+1, sizeof(char));
|
||
|
require(p!=NULL, "cannot allocate lock array");
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
** #ifdef __USE_PROTOS
|
||
|
** void my_memset(char *p,char value,int count)
|
||
|
** #else
|
||
|
** void my_memset(p,value,count)
|
||
|
** char *p;
|
||
|
** char value;
|
||
|
** int count;
|
||
|
** #endif
|
||
|
** {
|
||
|
** int i;
|
||
|
**
|
||
|
** for (i=0; i<count; i++) {
|
||
|
** p[i]=value;
|
||
|
** };
|
||
|
** }
|
||
|
#endif
|