📄 gen.c
字号:
{
int max_k;
/* if full LL(k) is sufficient, then don't use approximate (-ck) lookahead
* from CLL_k..LL_k
*/
{
int limit;
if ( j->ftree!=NULL ) limit = LL_k;
else limit = CLL_k;
max_k = genExprSets(j->fset, limit);
}
/* Do tests for real tuples from other productions that conflict with
* artificial tuples generated by compression (using sets of tokens
* rather than k-trees).
*/
if ( j->ftree != NULL )
{
_gen(" && !("); genExprTree(j->ftree, 1); _gen(")");
}
if ( ParseWithPredicates && j->predicate!=NULL )
{
Predicate *p = j->predicate;
warn_about_using_gk_option();
_gen("&&");
j->predicate=genPredTreeMain(p, (Node *)j); /* MR10 */
}
return max_k;
}
static int
#ifdef __USE_PROTOS
genExprSets( set *fset, int limit )
#else
genExprSets( fset, limit )
set *fset;
int limit;
#endif
{
int k = 1;
int max_k = 0;
unsigned *e, *g, firstTime=1;
if (set_nil(fset[1])) {
_gen(" 0 /* MR13 empty set expression - undefined rule ? infinite left recursion ? */ ");
MR_BadExprSets++;
};
if ( GenExprSetsOpt )
{
while ( k <= limit && !set_nil(fset[k]) ) /* MR11 */
{
if ( set_deg(fset[k])==1 ) /* too simple for a set? */
{
int e;
_gen1("(LA(%d)==",k);
e = set_int(fset[k]);
if ( TokenString(e) == NULL ) _gen1("%d)", e)
else _gen1("%s)", TokenString(e));
}
else
{
NewSet();
FillSet( fset[k] );
_gen3("(setwd%d[LA(%d)]&0x%x)", wordnum, k, 1<<setnum);
}
if ( k>max_k ) max_k = k;
if ( k == CLL_k ) break;
k++;
if ( k<=limit && !set_nil(fset[k]) ) _gen(" && "); /* MR11 */
on1line++;
if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
}
return max_k;
}
while ( k<= limit && !set_nil(fset[k]) ) /* MR11 */
{
if ( (e=g=set_pdq(fset[k])) == NULL ) fatal_internal("genExpr: cannot allocate IF expr pdq set");
for (; *e!=nil; e++)
{
if ( !firstTime ) _gen(" || ") else { _gen("("); firstTime = 0; }
on1line++;
if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
_gen1("LA(%d)==",k);
if ( TokenString(*e) == NULL ) _gen1("%d", *e)
else _gen1("%s", TokenString(*e));
}
free( (char *)g );
_gen(")");
if ( k>max_k ) max_k = k;
if ( k == CLL_k ) break;
k++;
if ( k <= limit && !set_nil(fset[k]) ) { firstTime=1; _gen(" && "); } /* MR11 */
on1line++;
if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
}
return max_k;
}
/*
* Generate code for any type of block. If the last alternative in the block is
* empty (not even an action) don't bother doing it. This permits us to handle
* optional and loop blocks as well.
*
* Only do this block, return after completing the block.
* This routine is visible only to this file and cannot answer a TRANS message.
*/
static set
#ifdef __USE_PROTOS
genBlk( Junction *q, int jtype, int *max_k, int *need_right_curly, int * lastAltEmpty /* MR23 */)
#else
genBlk( q, jtype, max_k, need_right_curly, lastAltEmpty /* MR23 */)
Junction *q;
int jtype;
int *max_k;
int *need_right_curly;
int *lastAltEmpty; /* MR23 */
#endif
{
set f;
Junction *alt;
int a_guess_in_block = 0;
require(q!=NULL, "genBlk: invalid node");
require(q->ntype == nJunction, "genBlk: not junction");
*need_right_curly=0;
*lastAltEmpty = 0; /* MR23 */
if ( q->p2 == NULL ) /* only one alternative? Then don't need if */
{
if (first_item_is_guess_block((Junction *)q->p1)!=NULL )
{
if (jtype != aLoopBlk && jtype != aOptBlk && jtype != aPlusBlk) {
warnFL("(...)? as only alternative of block is unnecessary", FileStr[q->file], q->line);
};
gen("zzGUESS\n"); /* guess anyway to make output code consistent */
/* MR10 disable */ /**** gen("if ( !zzrv )\n"); ****/
/* MR10 */ gen("if ( !zzrv ) {\n"); tabs++; (*need_right_curly)++;
};
TRANS(q->p1);
return empty; /* no decision to be made-->no error set */
}
f = First(q, 1, jtype, max_k);
for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
{
if ( alt->p2 == NULL ) /* chk for empty alt */
{
Node *p = alt->p1;
if ( p->ntype == nJunction )
{
/* we have empty alt */
/* MR23
There is a conflict between giving good error information for non-exceptions
and making life easy for those using parser exception handling. Consider:
r: { A } b;
b: B;
with input "C"
Before MR21 the error message would be "expecting B - found C". After MR21
the error message would be "expcect A, B - found C". This was good, but it
caused problems for those using parser exceptions because the reference to
B was generated inside the {...} where B really wasn't part of the block.
In MR23 this has been changed for the case where exceptions are in use to
not generate the extra check in the tail of the {A} block.
*/
/* MR23 */ if (isEmptyAlt( ((Junction *)p)->p1, (Node *)q->end)) {
/* MR23 */ *lastAltEmpty = 1;
/* MR23 */ if (FoundException) {
/* MR23 */ /* code to restore state if a prev alt didn't follow guess */
/* MR23 */ if ( a_guess_in_block && jtype != aPlusBlk) {
/* MR23 */ gen("if ( !zzrv ) zzGUESS_DONE; /* MR28 */\n");
/* MR23 */ }
/* MR23 */ break;
/* MR23 */ };
/* MR28 */ if (jtype == aPlusBlk) {
/* MR28 */ break;
/* MR28 */ }
/* MR23 */ }
}
} /* end of for loop on alt */
/* MR10 */ if (alt->p2 == NULL &&
/* MR10 */ ( q->jtype == aSubBlk || q->jtype == RuleBlk) ) {
/* MR10 */ if (first_item_is_guess_block(alt)) {
/* MR10 */ warnFL("(...)? as last alternative of block is unnecessary",
/* MR10 */ FileStr[alt->file],alt->line);
/* MR10 */ };
/* MR10 */ };
if ( alt != q ) gen("else ")
else
{
if ( DemandLookahead ) {
if ( !GenCC ) {gen1("LOOK(%d);\n", *max_k);}
else gen1("look(%d);\n", *max_k);
}
}
if ( alt!=q )
{
_gen("{\n");
tabs++;
(*need_right_curly)++;
/* code to restore state if a prev alt didn't follow guess */
if ( a_guess_in_block )
gen("if ( !zzrv ) zzGUESS_DONE;\n");
}
if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL )
{
a_guess_in_block = 1;
gen("zzGUESS\n");
}
gen("if ( ");
if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) _gen("!zzrv && ");
genExpr(alt);
_gen(" ) ");
_gen("{\n");
tabs++;
TRANS(alt->p1);
--tabs;
gen("}\n");
/* MR10 */ if (alt->p2 == NULL) {
/* MR10 */ if (first_item_is_guess_block(alt)) {
/* MR10 */ gen("/* MR10 */ else {\n");
/* MR10 */ tabs++;
/* MR10 */ (*need_right_curly)++;
/* MR10 */ /* code to restore state if a prev alt didn't follow guess */
/* MR10 */ gen("/* MR10 */ if ( !zzrv ) zzGUESS_DONE;\n");
/* MR10 */ gen("/* MR10 */ if (0) {} /* last alternative of block is guess block */\n");
/* MR10 */ };
/* MR10 */ };
}
return f;
}
static int
#ifdef __USE_PROTOS
has_guess_block_as_first_item( Junction *q )
#else
has_guess_block_as_first_item( q )
Junction *q;
#endif
{
Junction *alt;
for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
{
if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) return 1;
}
return 0;
}
static int
#ifdef __USE_PROTOS
has_guess_block_as_last_item( Junction *q )
#else
has_guess_block_as_last_item( q )
Junction *q;
#endif
{
Junction *alt;
if (q == NULL) return 0;
for (alt=q; alt->p2 != NULL && !( (Junction *) alt->p2)->ignore; alt= (Junction *) alt->p2 ) {};
return first_item_is_guess_block( (Junction *) alt->p1) != NULL;
}
/* MR30 See description of first_item_is_guess_block for background */
Junction *
#ifdef __USE_PROTOS
first_item_is_guess_block_extra(Junction *q )
#else
first_item_is_guess_block_extra(q)
Junction *q;
#endif
{
while ( q!=NULL &&
( ( q->ntype==nAction ) ||
( q->ntype==nJunction &&
(q->jtype==Generic || q->jtype == aLoopBlk)
)
)
)
{
if ( q->ntype==nJunction ) q = (Junction *)q->p1;
else q = (Junction *) ((ActionNode *)q)->next;
}
if ( q==NULL ) return NULL;
if ( q->ntype!=nJunction ) return NULL;
if ( q->jtype!=aSubBlk ) return NULL;
if ( !q->guess ) return NULL;
return q;
}
/* return NULL if 1st item of alt is NOT (...)? block; else return ptr to aSubBlk node
* of (...)?; This function ignores actions and predicates.
*/
Junction *
#ifdef __USE_PROTOS
first_item_is_guess_block( Junction *q )
#else
first_item_is_guess_block( q )
Junction *q;
#endif
{
Junction * qOriginal = q; /* DEBUG */
/* MR14 Couldn't find aSubBlock which was a guess block when it lay
behind aLoopBlk. The aLoopBlk only appear in conjunction with
aLoopBegin, but the routine didn't know that. I think.
MR14a Added extra parentheses to clarify precedence
MR30 This appears to have been a mistake. The First set was then
computed incorrectly for:
r : ( (A)? B
| C
)*
The routine analysis_point was seeing the guess block when
it was still analyzing the loopBegin block. As a consequence,
when it looked for the analysis_point it was processing the B, but
skipping over the C alternative altogether because it thought
it was looking at a guess block, not realizing there was a loop
block in front of the loopBegin.
loopBegin loopBlk subBlk/guess A G EB G B EB EB EB ER
| | | ^ ^
| | | |
| +-> G C G ----------------------+ |
| |
+--- G G G -------------------------------------+
Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu).
MR30 This is still more complicated. This fix caused ambiguity messages
to be reported for "( (A B)? )* A B" but not for "( (A B)? )+". Why is
there a difference when these are outwardly identical ? It is because the
start of a (...)* block is represented by two nodes: a loopBegin block
followed by a loopBlock whereas the start of a (...)+ block is
represented as a single node: a plusBlock. So if first_item_is_guess_block
is called when the current node is a loopBegin it starts with the
loop block rather than the the sub block which follows the loop block.
However, we can't just skip past the loop block because some routines
depend on the old implementation. So, we provide a new implementation
which does skip the loopBlock. However, which should be called when ?
I'm not sure, but my guess is that first_item_is_guess_block_extra (the
new one) should only be called for the ambiguity routines.
*/
while ( q!=NULL &&
( ( q->ntype==nAction ) ||
( q->ntype==nJunction &&
(q->jtype==Generic /*** || q->jtype == aLoopBlk ***/ ) /*** MR30 Undo MR14 change ***/
)
)
)
{
if ( q->ntype==nJunction ) q = (Junction *)q->p1;
else q = (Junction *) ((ActionNode *)q)->next;
}
if ( q==NULL ) return NULL;
if ( q->ntype!=nJunction ) return NULL;
if ( q->jtype!=aSubBlk ) return NULL;
if ( !q->guess ) return NULL;
return q;
}
/* MR1 */
/* MR1 10-Apr-97 MR1 Routine to stringize failed semantic predicates msgs */
/* MR1 */
#define STRINGIZEBUFSIZE 1024
static char stringizeBuf[STRINGIZEBUFSIZE];
char *
#ifdef __USE_PROTOS
stringize(char * s)
#else
stringize(s)
char *s;
#endif
{
char *p;
char *stop;
p=stringizeBuf;
stop=&stringizeBuf[1015];
if (s != 0) {
while (*s != 0) {
if (p >= stop) {
goto stringizeStop;
} else if (*s == '\n') {
*p++='\\';
*p++='n';
*p++='\\';
*p++=*s++;
} else if (*s == '\\') {
*p++=*s;
*p++=*s++;
} else if (*s == '\"') {
*p++='\\';
*p++=*s++;
while (*s != 0) {
if (p >= stop) {
goto stringizeStop;
} else if (*s == '\n') {
*p++='\\';
*p++=*s++;
} else if (*s == '\\') {
*p++=*s++;
*p++=*s++;
} else if (*s == '\"') {
*p++='\\';
*p++=*s++;
break;
} else {
*p++=*s++;
};
};
} else if (*s == '\'') {
*p++=*s++;
while (*s != 0) {
if (p >= stop) {
goto stringizeStop;
} else if (*s == '\'') {
*p++=*s++;
break;
} else if (*s == '\\') {
*p++=*s++;
*p++=*s++;
} else if (*s == '\"') {
*p++='\\';
*p++=*s++;
break;
} else {
*p++=*s++;
};
};
} else {
*p++=*s++;
};
};
};
goto stringizeExit;
stringizeStop:
*p++='.';
*p++='.';
*p++='.';
stringizeExit:
*p=0;
return stringizeBuf;
}
#ifdef __USE_PROTOS
int isNullAction(char *s)
#else
int isNullAction(s)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -