[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: incorrect yychar for unambiguous GLR
From: |
Joel E. Denny |
Subject: |
Re: incorrect yychar for unambiguous GLR |
Date: |
Fri, 6 Jan 2006 15:48:18 -0500 (EST) |
On Tue, 19 Jul 2005, Joel E. Denny wrote:
> Should yychar be reliable in semantic actions when declaring %glr-parser?
I've installed this patch, which fixes the GLR lookahead bugs I've
encountered and adds some related test cases. Although my original post
was mainly about deterministic operation, this patch also addresses
nondeterministic operation.
This is a complex patch. More pairs of eyes would be helpful.
Joel
2006-01-06 Joel E. Denny <address@hidden>
* data/glr.c (yyGLRStateSet): Add yybool* yylookaheadStatuses member to
use during nondeterministic operation to track which stacks have
actually needed the current lookahead.
(yyinitStateSet, yyfreeStateSet, yyremoveDeletes, yysplitStack):
Allocate, deallocate, resize, and otherwise shuffle space for
yylookaheadStatuses in parallel with yystates member of yyGLRStateSet.
(yysplitStack, yyprocessOneStack, yyparse): Set lookahead status
appropriately during nondeterministic operation.
(yySemanticOption): Add int yyrawchar, YYSTYPE yyval, and YYLTYPE yyloc
members to store the current lookahead to be used by the deferred
user action.
(yyaddDeferredAction): Add size_t yyk parameter specifying the stack
from which the RHS is taken. Set the lookahead members of the new
yySemanticOption according to the lookahead status for stack yyk.
(yyglrShiftDefer, yyglrReduce): Pass yyk parameter on to
yyaddDeferredAction.
(yyresolveAction): Set yychar, yylval, and yylloc to the lookahead
members of yySemanticOption before invoking yyuserAction, and then set
them back to their current values afterward.
(yyparse): Set yychar = YYEMPTY where yytoken = YYEMPTY.
(yyreportAmbiguity): Add /*ARGSUSED*/ to pacify lint.
* tests/glr-regression.at: Remove `.' from the ends of recent test case
titles for consistency.
(Leaked merged semantic value if user action cuts parse): In order to
suppress lint warnings, use arguments in merge function, and assign
char value < 128 in main.
(Incorrect lookahead during deterministic GLR): New test case.
(Incorrect lookahead during nondeterministic GLR): New test case.
Index: data/glr.c
===================================================================
RCS file: /sources/bison/bison/data/glr.c,v
retrieving revision 1.155
diff -p -u -r1.155 glr.c
--- data/glr.c 6 Jan 2006 20:09:31 -0000 1.155
+++ data/glr.c 6 Jan 2006 20:25:55 -0000
@@ -761,6 +761,11 @@ struct yyGLRState {
struct yyGLRStateSet {
yyGLRState** yystates;
+ /** During nondeterministic operation, yylookaheadStatuses tracks which
+ * stacks have actually needed the current lookahead. During deterministic
+ * operation, yylookaheadStatuses[0] is not maintained since it would merely
+ * duplicate yychar != YYEMPTY. */
+ yybool* yylookaheadStatuses;
size_t yysize, yycapacity;
};
@@ -771,6 +776,10 @@ struct yySemanticOption {
yyRuleNum yyrule;
/** The last RHS state in the list of states to be reduced. */
yyGLRState* yystate;
+ /** The lookahead for this reduction. */
+ int yyrawchar;
+ YYSTYPE yyval;
+ YYLTYPE yyloc;
/** Next sibling in chain of options. To facilitate merging,
* options are chained in decreasing order by address. */
yySemanticOption* yynext;
@@ -1092,14 +1101,24 @@ yynewGLRStackItem (yyGLRStack* yystackp,
return yynewItem;
}
+/** Stack #K = the stack from which RHS is taken. This might not be the stack
+ * containing STATE, to which the deferred action is added. */
static void
-yyaddDeferredAction (yyGLRStack* yystackp, yyGLRState* yystate,
+yyaddDeferredAction (yyGLRStack* yystackp, size_t yyk, yyGLRState* yystate,
yyGLRState* rhs, yyRuleNum yyrule)
{
yySemanticOption* yynewOption =
&yynewGLRStackItem (yystackp, yyfalse)->yyoption;
yynewOption->yystate = rhs;
yynewOption->yyrule = yyrule;
+ if (yystackp->yytops.yylookaheadStatuses[yyk])
+ {
+ yynewOption->yyrawchar = yychar;
+ yynewOption->yyval = yylval;
+ yynewOption->yyloc = yylloc;
+ }
+ else
+ yynewOption->yyrawchar = YYEMPTY;
yynewOption->yynext = yystate->yysemantics.yyfirstVal;
yystate->yysemantics.yyfirstVal = yynewOption;
@@ -1118,12 +1137,20 @@ yyinitStateSet (yyGLRStateSet* yyset)
if (! yyset->yystates)
return yyfalse;
yyset->yystates[0] = NULL;
+ yyset->yylookaheadStatuses =
+ (yybool*) YYMALLOC (16 * sizeof yyset->yylookaheadStatuses[0]);
+ if (! yyset->yylookaheadStatuses)
+ {
+ YYFREE (yyset->yystates);
+ return yyfalse;
+ }
return yytrue;
}
static void yyfreeStateSet (yyGLRStateSet* yyset)
{
YYFREE (yyset->yystates);
+ YYFREE (yyset->yylookaheadStatuses);
}
/** Initialize STACK to a single empty stack, with total maximum
@@ -1270,6 +1297,13 @@ yyremoveDeletes (yyGLRStack* yystackp)
else
{
yystackp->yytops.yystates[yyj] = yystackp->yytops.yystates[yyi];
+ /* In the current implementation, it's unnecessary to copy
+ yystackp->yytops.yylookaheadStatuses[yyi] since, after
+ yyremoveDeletes returns, the parser immediately either enters
+ deterministic operation or shifts a token. However, it doesn't
+ hurt, and the code might evolve to need it. */
+ yystackp->yytops.yylookaheadStatuses[yyj] =
+ yystackp->yytops.yylookaheadStatuses[yyi];
if (yyj != yyi)
{
YYDPRINTF ((stderr, "Rename stack %lu -> %lu.\n",
@@ -1318,7 +1352,7 @@ yyglrShiftDefer (yyGLRStack* yystackp, s
yystackp->yytops.yystates[yyk] = yynewState;
/* Invokes YY_RESERVE_GLRSTACK. */
- yyaddDeferredAction (yystackp, yynewState, rhs, yyrule);
+ yyaddDeferredAction (yystackp, yyk, yynewState, rhs, yyrule);
}
/** Pop the symbols consumed by reduction #RULE from the top of stack
@@ -1470,7 +1504,7 @@ yyglrReduce (yyGLRStack* yystackp, size_
{
if (yyp->yylrState == yynewLRState && yyp->yypred == yys)
{
- yyaddDeferredAction (yystackp, yyp, yys0, yyrule);
+ yyaddDeferredAction (yystackp, yyk, yyp, yys0, yyrule);
yymarkStackDeleted (yystackp, yyk);
YYDPRINTF ((stderr, "Merging stack %lu into stack %lu.\n",
(unsigned long int) yyk,
@@ -1497,6 +1531,7 @@ yysplitStack (yyGLRStack* yystackp, size
if (yystackp->yytops.yysize >= yystackp->yytops.yycapacity)
{
yyGLRState** yynewStates;
+ yybool* yynewLookaheadStatuses;
if (! ((yystackp->yytops.yycapacity
<= (YYSIZEMAX / (2 * sizeof yynewStates[0])))
&& (yynewStates =
@@ -1505,9 +1540,17 @@ yysplitStack (yyGLRStack* yystackp, size
* sizeof yynewStates[0])))))
yyMemoryExhausted (yystackp);
yystackp->yytops.yystates = yynewStates;
+ if (! (yynewLookaheadStatuses =
+ (yybool*) YYREALLOC (yystackp->yytops.yylookaheadStatuses,
+ ((yystackp->yytops.yycapacity)
+ * sizeof yynewLookaheadStatuses[0]))))
+ yyMemoryExhausted (yystackp);
+ yystackp->yytops.yylookaheadStatuses = yynewLookaheadStatuses;
}
yystackp->yytops.yystates[yystackp->yytops.yysize]
= yystackp->yytops.yystates[yyk];
+ yystackp->yytops.yylookaheadStatuses[yystackp->yytops.yysize]
+ = yystackp->yytops.yylookaheadStatuses[yyk];
yystackp->yytops.yysize += 1;
return yystackp->yytops.yysize-1;
}
@@ -1647,6 +1690,10 @@ yyresolveAction (yySemanticOption* yyopt
{
yyGLRStackItem yyrhsVals[YYMAXRHS + YYMAXLEFT + 1];
int yynrhs;
+ int yychar_current;
+ YYSTYPE yylval_current;
+ YYLTYPE yylloc_current;
+ YYRESULTTAG yyresult;
yynrhs = yyrhsLength (yyopt->yyrule);
YYCHK (yyresolveStates (yyopt->yystate, yynrhs, yystackp]b4_user_args[));
@@ -1654,9 +1701,19 @@ yyresolveAction (yySemanticOption* yyopt
if (yynrhs == 0)
/* Set default location. */
yyrhsVals[YYMAXRHS + YYMAXLEFT - 1].yystate.yyloc =
yyopt->yystate->yyloc;]])[
- return yyuserAction (yyopt->yyrule, yynrhs,
- yyrhsVals + YYMAXRHS + YYMAXLEFT - 1,
- yyvalp, yylocp, yystackp]b4_user_args[);
+ yychar_current = yychar;
+ yylval_current = yylval;
+ yylloc_current = yylloc;
+ yychar = yyopt->yyrawchar;
+ yylval = yyopt->yyval;
+ yylloc = yyopt->yyloc;
+ yyresult = yyuserAction (yyopt->yyrule, yynrhs,
+ yyrhsVals + YYMAXRHS + YYMAXLEFT - 1,
+ yyvalp, yylocp, yystackp]b4_user_args[);
+ yychar = yychar_current;
+ yylval = yylval_current;
+ yylloc = yylloc_current;
+ return yyresult;
}
#if YYDEBUG
@@ -1710,7 +1767,7 @@ yyreportTree (yySemanticOption* yyx, int
static void yyreportAmbiguity (yySemanticOption* yyx0, yySemanticOption* yyx1,
yyGLRStack* yystackp]b4_pure_formals[)
__attribute__ ((__noreturn__));
-static void
+/*ARGSUSED*/ static void
yyreportAmbiguity (yySemanticOption* yyx0, yySemanticOption* yyx1,
yyGLRStack* yystackp]b4_pure_formals[)
{
@@ -1885,6 +1942,7 @@ yyprocessOneStack (yyGLRStack* yystackp,
}
else
{
+ yystackp->yytops.yylookaheadStatuses[yyk] = yytrue;
if (*yytokenp == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
@@ -2147,6 +2205,7 @@ yyrecoverSyntaxError (yyGLRStack* yystac
YYDPRINTF ((stderr, "Starting parse\n"));
+ yychar = YYEMPTY;
yytoken = YYEMPTY;
yylval = yyval_default;
]b4_location_if([
@@ -2221,7 +2280,10 @@ b4_syncline(address@hidden@], address@hidden@])])dnl
{
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
if (yytoken != YYEOF)
- yytoken = YYEMPTY;
+ {
+ yychar = YYEMPTY;
+ yytoken = YYEMPTY;
+ }
yyposn += 1;
yyglrShift (&yystack, 0, yyaction, yyposn, &yylval, &yylloc);
if (0 < yystack.yyerrState)
@@ -2244,6 +2306,9 @@ b4_syncline(address@hidden@], address@hidden@])])dnl
size_t yys;
size_t yyn = yystack.yytops.yysize;
+ for (yys = 0; yys < yyn; yys += 1)
+ yystackp->yytops.yylookaheadStatuses[yys] = yychar != YYEMPTY;
+
/* yyprocessOneStack returns one of three things:
- An error flag. If the caller is yyprocessOneStack, it
@@ -2274,6 +2339,7 @@ b4_syncline(address@hidden@], address@hidden@])])dnl
before the loop to make sure the user destructor for yylval isn't
called twice. */
yytoken_to_shift = yytoken;
+ yychar = YYEMPTY;
yytoken = YYEMPTY;
yyposn += 1;
for (yys = 0; yys < yyn; yys += 1)
Index: tests/glr-regression.at
===================================================================
RCS file: /sources/bison/bison/tests/glr-regression.at,v
retrieving revision 1.24
diff -p -u -r1.24 glr-regression.at
--- tests/glr-regression.at 6 Jan 2006 01:07:37 -0000 1.24
+++ tests/glr-regression.at 6 Jan 2006 20:25:55 -0000
@@ -816,7 +816,7 @@ AT_CLEANUP
## Corrupted semantic options if user action cuts parse. ##
## ------------------------------------------------------------------------- ##
-AT_SETUP([Corrupted semantic options if user action cuts parse.])
+AT_SETUP([Corrupted semantic options if user action cuts parse])
AT_DATA_GRAMMAR([glr-regr10.y],
[[
@@ -858,7 +858,7 @@ main (void)
{
int index;
for (index = 0; index < GARBAGE_SIZE; index+=1)
- garbage[index] = 132;
+ garbage[index] = 108;
return yyparse ();
}
]])
@@ -877,7 +877,7 @@ AT_CLEANUP
## Undesirable destructors if user action cuts parse. ##
## ------------------------------------------------------------------------- ##
-AT_SETUP([Undesirable destructors if user action cuts parse.])
+AT_SETUP([Undesirable destructors if user action cuts parse])
AT_DATA_GRAMMAR([glr-regr11.y],
[[
@@ -943,7 +943,7 @@ AT_CLEANUP
## Leaked merged semantic value if user action cuts parse. ##
## ------------------------------------------------------------------------- ##
-AT_SETUP([Leaked merged semantic value if user action cuts parse.])
+AT_SETUP([Leaked merged semantic value if user action cuts parse])
AT_DATA_GRAMMAR([glr-regr12.y],
[[
@@ -974,7 +974,8 @@ static int
merge (YYSTYPE s1, YYSTYPE s2)
{
/* Not invoked. */
- return 0;
+ char dummy = s1.dummy + s2.dummy;
+ return dummy;
}
static void
@@ -1010,3 +1011,350 @@ AT_COMPILE([glr-regr12])
AT_CHECK([[./glr-regr12]], 0, [], [])
AT_CLEANUP
+
+
+## ------------------------------------------------------------------------- ##
+## Incorrect lookahead during deterministic GLR. See ##
+## <http://lists.gnu.org/archive/html/help-bison/2005-07/msg00017.html>. ##
+## ------------------------------------------------------------------------- ##
+
+AT_SETUP([Incorrect lookahead during deterministic GLR])
+
+AT_DATA_GRAMMAR([glr-regr13.y],
+[[
+/* Tests:
+ - Defaulted state with initial yychar: yychar == YYEMPTY.
+ - Nondefaulted state: yychar != YYEMPTY.
+ - Defaulted state after lookahead: yychar != YYEMPTY.
+ - Defaulted state after shift: yychar == YYEMPTY. */
+
+%{
+ #include <stdio.h>
+ static void yyerror (char const *);
+ static int yylex (void);
+ static void print_look_ahead (char const *);
+ #define USE(value)
+%}
+
+%union { char value; }
+%type <value> 'a' 'b'
+%glr-parser
+%locations
+
+%%
+
+start:
+ defstate_init defstate_shift 'b' {
+ USE ($3);
+ print_look_ahead ("start <- defstate_init defstate_shift 'b'");
+ }
+ ;
+defstate_init:
+ {
+ print_look_ahead ("defstate_init <- empty string");
+ }
+ ;
+defstate_shift:
+ nondefstate defstate_look 'a' {
+ USE ($3);
+ print_look_ahead ("defstate_shift <- nondefstate defstate_look 'a'");
+ }
+ ;
+defstate_look:
+ {
+ print_look_ahead ("defstate_look <- empty string");
+ }
+ ;
+nondefstate:
+ {
+ print_look_ahead ("nondefstate <- empty string");
+ }
+ | 'b' {
+ USE ($1);
+ print_look_ahead ("nondefstate <- 'b'");
+ }
+ ;
+
+%%
+
+static void
+yyerror (char const *msg)
+{
+ fprintf (stderr, "%s\n", msg);
+}
+
+static int
+yylex (void)
+{
+ static char const *input = "ab";
+ static int index = 0;
+ yylloc.first_line = yylloc.last_line = 1;
+ yylloc.first_column = yylloc.last_column = index+1;
+ yylval.value = input[index] + 'A' - 'a';
+ return input[index++];
+}
+
+static void
+print_look_ahead (char const *reduction)
+{
+ printf ("%s:\n yychar=", reduction);
+ if (yychar == YYEMPTY)
+ printf ("YYEMPTY");
+ else if (yychar == YYEOF)
+ printf ("YYEOF");
+ else
+ {
+ printf ("'%c', yylval='", yychar);
+ if (yylval.value > ' ')
+ printf ("%c", yylval.value);
+ printf ("', yylloc=(%d,%d),(%d,%d)",
+ yylloc.first_line, yylloc.first_column,
+ yylloc.last_line, yylloc.last_column);
+ }
+ printf ("\n");
+}
+
+int
+main (void)
+{
+ yychar = '#'; /* Not a token in the grammar. */
+ yylval.value = '!';
+ return yyparse ();
+}
+]])
+
+AT_CHECK([[bison -t -o glr-regr13.c glr-regr13.y]], 0, [], [])
+AT_COMPILE([glr-regr13])
+
+AT_CHECK([[./glr-regr13]], 0,
+[defstate_init <- empty string:
+ yychar=YYEMPTY
+nondefstate <- empty string:
+ yychar='a', yylval='A', yylloc=(1,1),(1,1)
+defstate_look <- empty string:
+ yychar='a', yylval='A', yylloc=(1,1),(1,1)
+defstate_shift <- nondefstate defstate_look 'a':
+ yychar=YYEMPTY
+start <- defstate_init defstate_shift 'b':
+ yychar=YYEMPTY
+], [])
+
+AT_CLEANUP
+
+
+## ------------------------------------------------------------------------- ##
+## Incorrect lookahead during nondeterministic GLR. ##
+## ------------------------------------------------------------------------- ##
+
+AT_SETUP([Incorrect lookahead during nondeterministic GLR])
+
+AT_DATA_GRAMMAR([glr-regr14.y],
+[[
+/* Tests:
+ - Conflicting actions (split-off parse, which copies lookahead status,
+ which is necessarily yytrue) and nonconflicting actions (non-split-off
+ parse) for nondefaulted state: yychar != YYEMPTY.
+ - Merged deferred actions (lookahead status and RHS from different stack
+ than the target state) and nonmerged deferred actions (same stack).
+ - Defaulted state after lookahead: yychar != YYEMPTY.
+ - Defaulted state after shift: yychar == YYEMPTY.
+ - yychar != YYEMPTY but lookahead status is yyfalse (a previous stack has
+ seen the lookahead but current stack has not).
+ - Exceeding stack capacity (stack explosion), and thus reallocating
+ lookahead status array.
+ Note that it does not seem possible to see the initial yychar value during
+ nondeterministic operation since:
+ - In order to preserve the initial yychar, only defaulted states may be
+ entered.
+ - If only defaulted states are entered, there are no conflicts, so
+ nondeterministic operation does not start. */
+
+%union { char value; }
+
+%{
+ #include <stdio.h>
+ static void yyerror (char const *);
+ static int yylex (void);
+ static void print_look_ahead (char const *);
+ static char merge (union YYSTYPE, union YYSTYPE);
+ #define USE(value)
+%}
+
+%type <value> 'a' 'b' 'c' 'd' stack_explosion
+%glr-parser
+%locations
+
+%%
+
+start:
+ merge 'c' stack_explosion {
+ USE ($2); USE ($3);
+ print_look_ahead ("start <- merge 'c' stack_explosion");
+ }
+ ;
+
+/* When merging the 2 deferred actions, the lookahead statuses are
+ different. */
+merge:
+ nonconflict1 'a' 'b' nonconflict2 %dprec 1 {
+ USE ($2); USE ($3);
+ print_look_ahead ("merge <- nonconflict1 'a' 'b' nonconflict2");
+ }
+ | conflict defstate_look 'a' nonconflict2 'b' defstate_shift %dprec 2 {
+ USE ($3); USE ($5);
+ print_look_ahead ("merge <- conflict defstate_look 'a' nonconflict2 'b'"
+ " defstate_shift");
+ }
+ ;
+
+nonconflict1:
+ {
+ print_look_ahead ("nonconflict1 <- empty string");
+ }
+ ;
+nonconflict2:
+ {
+ print_look_ahead ("nonconflict2 <- empty string");
+ }
+ | 'a' {
+ USE ($1);
+ print_look_ahead ("nonconflict2 <- 'a'");
+ }
+ ;
+conflict:
+ {
+ print_look_ahead ("conflict <- empty string");
+ }
+ ;
+defstate_look:
+ {
+ print_look_ahead ("defstate_look <- empty string");
+ }
+ ;
+
+/* yychar != YYEMPTY but lookahead status is yyfalse. */
+defstate_shift:
+ {
+ print_look_ahead ("defstate_shift <- empty string");
+ }
+ ;
+
+stack_explosion:
+ { $$ = '\0'; }
+ | alt1 stack_explosion %merge<merge> { $$ = $2; }
+ | alt2 stack_explosion %merge<merge> { $$ = $2; }
+ | alt3 stack_explosion %merge<merge> { $$ = $2; }
+ ;
+alt1:
+ 'd' no_look {
+ USE ($1);
+ if (yychar != 'd' && yychar != YYEOF)
+ {
+ fprintf (stderr, "Incorrect lookahead during stack explosion.\n");
+ }
+ }
+ ;
+alt2:
+ 'd' no_look {
+ USE ($1);
+ if (yychar != 'd' && yychar != YYEOF)
+ {
+ fprintf (stderr, "Incorrect lookahead during stack explosion.\n");
+ }
+ }
+ ;
+alt3:
+ 'd' no_look {
+ USE ($1);
+ if (yychar != 'd' && yychar != YYEOF)
+ {
+ fprintf (stderr, "Incorrect lookahead during stack explosion.\n");
+ }
+ }
+ ;
+no_look:
+ {
+ if (yychar != YYEMPTY)
+ {
+ fprintf (stderr,
+ "Found lookahead where shouldn't during stack explosion.\n");
+ }
+ }
+ ;
+
+%%
+
+static void
+yyerror (char const *msg)
+{
+ fprintf (stderr, "%s\n", msg);
+}
+
+static int
+yylex (void)
+{
+ static char const *input = "abcdddd";
+ static int index = 0;
+ yylloc.first_line = yylloc.last_line = 1;
+ yylloc.first_column = yylloc.last_column = index+1;
+ yylval.value = input[index] + 'A' - 'a';
+ return input[index++];
+}
+
+static void
+print_look_ahead (char const *reduction)
+{
+ printf ("%s:\n yychar=", reduction);
+ if (yychar == YYEMPTY)
+ printf ("YYEMPTY");
+ else if (yychar == YYEOF)
+ printf ("YYEOF");
+ else
+ {
+ printf ("'%c', yylval='", yychar);
+ if (yylval.value > ' ')
+ printf ("%c", yylval.value);
+ printf ("', yylloc=(%d,%d),(%d,%d)",
+ yylloc.first_line, yylloc.first_column,
+ yylloc.last_line, yylloc.last_column);
+ }
+ printf ("\n");
+}
+
+static char
+merge (union YYSTYPE s1, union YYSTYPE s2)
+{
+ char dummy = s1.value + s2.value;
+ return dummy;
+}
+
+int
+main (void)
+{
+ yychar = '#'; /* Not a token in the grammar. */
+ yylval.value = '!';
+ return yyparse ();
+}
+]])
+
+AT_CHECK([[bison -t -o glr-regr14.c glr-regr14.y]], 0, [],
+[glr-regr14.y: conflicts: 3 reduce/reduce
+])
+AT_COMPILE([glr-regr14])
+
+AT_CHECK([[./glr-regr14]], 0,
+[conflict <- empty string:
+ yychar='a', yylval='A', yylloc=(1,1),(1,1)
+defstate_look <- empty string:
+ yychar='a', yylval='A', yylloc=(1,1),(1,1)
+nonconflict2 <- empty string:
+ yychar='b', yylval='B', yylloc=(1,2),(1,2)
+defstate_shift <- empty string:
+ yychar=YYEMPTY
+merge <- conflict defstate_look 'a' nonconflict2 'b' defstate_shift:
+ yychar=YYEMPTY
+start <- merge 'c' stack_explosion:
+ yychar=YYEOF
+], [])
+
+AT_CLEANUP
- Re: incorrect yychar for unambiguous GLR,
Joel E. Denny <=
- Re: incorrect yychar for unambiguous GLR, Joel E. Denny, 2006/01/10
- Re: incorrect yychar for unambiguous GLR, Paul Hilfinger, 2006/01/10
- Re: incorrect yychar for unambiguous GLR, Joel E. Denny, 2006/01/11
- Re: incorrect yychar for unambiguous GLR, Paul Hilfinger, 2006/01/11
- Re: incorrect yychar for unambiguous GLR, Joel E. Denny, 2006/01/11
- Re: incorrect yychar for unambiguous GLR, Joel E. Denny, 2006/01/11
- Re: incorrect yychar for unambiguous GLR, Paul Eggert, 2006/01/12
- Re: incorrect yychar for unambiguous GLR, Joel E. Denny, 2006/01/30
Re: incorrect yychar for unambiguous GLR, Paul Eggert, 2006/01/11