* data/glr.c (yyprocessOneStack): Synchronize the shift for all

stacks, and iterate another stack in order to call user
destructors.
* tests/glr-regression.at (No users destructors if stack 0 deleted):
New test case.
(Duplicated user destructor for lookahead): This test now is expected
to succeed.
This commit is contained in:
Paul Eggert
2005-12-06 19:38:25 +00:00
parent 32b5b719e4
commit 69ce078b8c
3 changed files with 188 additions and 54 deletions

View File

@@ -1,3 +1,13 @@
2005-12-06 "Joel E. Denny" <jdenny@ces.clemson.edu>
* data/glr.c (yyprocessOneStack): Synchronize the shift for all
stacks, and iterate another stack in order to call user
destructors.
* tests/glr-regression.at (No users destructors if stack 0 deleted):
New test case.
(Duplicated user destructor for lookahead): This test now is expected
to succeed.
2005-12-01 Paul Eggert <eggert@cs.ucla.edu> 2005-12-01 Paul Eggert <eggert@cs.ucla.edu>
* NEWS: Document the following change. * NEWS: Document the following change.

View File

@@ -1880,16 +1880,7 @@ yyprocessOneStack (yyGLRStack* yystack, size_t yyk,
} }
if (yyisShiftAction (yyaction)) if (yyisShiftAction (yyaction))
{
YYDPRINTF ((stderr, "On stack %lu, ", (unsigned long int) yyk));
YY_SYMBOL_PRINT ("shifting", *yytokenp, yylvalp, yyllocp);
yyglrShift (yystack, yyk, yyaction, yyposn+1,
*yylvalp, yyllocp);
YYDPRINTF ((stderr, "Stack %lu now in state #%d\n",
(unsigned long int) yyk,
yystack->yytops.yystates[yyk]->yylrState));
break; break;
}
else if (yyisErrorAction (yyaction)) else if (yyisErrorAction (yyaction))
{ {
YYDPRINTF ((stderr, "Stack %lu dies.\n", YYDPRINTF ((stderr, "Stack %lu dies.\n",
@@ -2236,14 +2227,59 @@ b4_syncline([@oline@], [@ofile@])])dnl
while (yytrue) while (yytrue)
{ {
yySymbol yytoken_to_shift;
size_t yys; size_t yys;
size_t yyn = yystack.yytops.yysize; size_t yyn = yystack.yytops.yysize;
/* yyprocessOneStack returns one of three things:
- An error flag. If the caller is yyprocessOneStack, it
immediately returns as well. When the caller is finally
yyparse, it jumps to an error label via YYCHK1.
- yyok, but yyprocessOneStack has invoked yymarkStackDeleted
(&yystack, yys), which sets the top state of yys to NULL. Thus,
yyparse's following invocation of yyremoveDeletes will remove
the stack.
- yyok, when ready to shift a token.
Except in the first case, yyparse will invoke yyremoveDeletes and
then shift the next token onto all remaining stacks. This
synchronization of the shift (that is, after all preceding
reductions on all stacks) helps prevents double destructor calls
on yylval in the event of memory exhaustion. */
for (yys = 0; yys < yyn; yys += 1) for (yys = 0; yys < yyn; yys += 1)
YYCHK1 (yyprocessOneStack (&yystack, yys, yyposn, YYCHK1 (yyprocessOneStack (&yystack, yys, yyposn,
yylvalp, yyllocp]b4_lpure_args[)); yylvalp, yyllocp]b4_lpure_args[));
yyremoveDeletes (&yystack);
yyn = yystack.yytops.yysize;
/* If any yyglrShift call fails, it will fail after shifting. Thus,
a copy of yylval will already be on stack 0 in the event of a
failure in the following loop. Thus, yytoken is set to YYEMPTY
before the loop to make sure the user destructor for yylval isn't
called twice. */
yytoken_to_shift = yytoken;
yytoken = YYEMPTY; yytoken = YYEMPTY;
yyposn += 1; yyposn += 1;
yyremoveDeletes (&yystack); for (yys = 0; yys < yyn; yys += 1)
{
int yyaction;
const short int* yyconflicts;
yyStateNum yystate = yystack.yytops.yystates[yys]->yylrState;
yygetLRActions (yystate, yytoken_to_shift, &yyaction,
&yyconflicts);
/* Note that yyconflicts were handled by yyprocessOneStack. */
YYDPRINTF ((stderr, "On stack %lu, ", (unsigned long int) yys));
YY_SYMBOL_PRINT ("shifting", yytoken_to_shift, yylvalp, yyllocp);
yyglrShift (&yystack, yys, yyaction, yyposn,
*yylvalp, yyllocp);
YYDPRINTF ((stderr, "Stack %lu now in state #%d\n",
(unsigned long int) yys,
yystack.yytops.yystates[yys]->yylrState));
}
if (yystack.yytops.yysize == 0) if (yystack.yytops.yysize == 0)
{ {
yyundeleteLastStack (&yystack); yyundeleteLastStack (&yystack);
@@ -2298,15 +2334,24 @@ b4_syncline([@oline@], [@ofile@])])dnl
{ {
yyGLRState** yystates = yystack.yytops.yystates; yyGLRState** yystates = yystack.yytops.yystates;
if (yystates) if (yystates)
while (yystates[0])
{ {
yyGLRState *yys = yystates[0]; size_t yysize = yystack.yytops.yysize;
size_t yyk;
for (yyk = 0; yyk < yysize; yyk += 1)
if (yystates[yyk])
{
while (yystates[yyk])
{
yyGLRState *yys = yystates[yyk];
]b4_location_if([[ yystack.yyerror_range[1].yystate.yyloc = yys->yyloc;]] ]b4_location_if([[ yystack.yyerror_range[1].yystate.yyloc = yys->yyloc;]]
)[ yydestroyGLRState ("Cleanup: popping", yys]b4_user_args[); )[ yydestroyGLRState ("Cleanup: popping", yys]b4_user_args[);
yystates[0] = yys->yypred; yystates[yyk] = yys->yypred;
yystack.yynextFree -= 1; yystack.yynextFree -= 1;
yystack.yyspaceLeft += 1; yystack.yyspaceLeft += 1;
} }
break;
}
}
yyfreeGLRStack (&yystack); yyfreeGLRStack (&yystack);
} }

View File

@@ -633,8 +633,6 @@ AT_CHECK([[./glr-regr7]], 2, [],
[memory exhausted [memory exhausted
]) ])
AT_XFAIL_IF(:)
AT_CLEANUP AT_CLEANUP
@@ -695,7 +693,7 @@ void yyerror(const char *msg)
static int lexIndex; static int lexIndex;
int yylex() int yylex (void)
{ {
lexIndex += 1; lexIndex += 1;
switch (lexIndex) switch (lexIndex)
@@ -733,3 +731,84 @@ AT_CHECK([[./glr-regr8]], 0,
[]) [])
AT_CLEANUP AT_CLEANUP
## ------------------------------------------------------------------------- ##
## No users destructors if stack 0 deleted ##
## Thanks to Joel E. Denny for this test; see ##
## <http://lists.gnu.org/archive/html/bison-patches/2005-09/msg00109.html>. ##
## ------------------------------------------------------------------------- ##
AT_SETUP([No users destructors if stack 0 deleted])
AT_DATA_GRAMMAR([glr-regr9.y],
[[
%{
#include <stdio.h>
#include <stdlib.h>
static void yyerror (char const *);
static int yylex (void);
#define YYSTACKEXPANDABLE 0
static int tokens = 0;
static int destructors = 0;
%}
%glr-parser
%union { int dummy; }
%type <dummy> 'a'
%destructor {
destructors += 1;
} 'a'
%%
start:
ambig0 'a' { destructors += 2; }
| ambig1 start { destructors += 1; }
| ambig2 start { destructors += 1; }
;
ambig0: 'a' ;
ambig1: 'a' ;
ambig2: 'a' ;
%%
static int
yylex (void)
{
tokens += 1;
return 'a';
}
static void
yyerror (char const *msg)
{
fprintf (stderr, "%s\n", msg);
}
int
main (void)
{
int exit_status;
exit_status = yyparse ();
if (tokens != destructors)
{
fprintf (stderr, "Tokens = %d, Destructors = %d\n", tokens, destructors);
return 1;
}
return !exit_status;
}
]])
AT_CHECK([[bison -o glr-regr9.c glr-regr9.y]], 0, [],
[glr-regr9.y: conflicts: 1 reduce/reduce
])
AT_COMPILE([glr-regr9])
AT_CHECK([[./glr-regr9]], 0, [],
[memory exhausted
])
AT_CLEANUP