mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-28 13:43:02 +00:00
* 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:
10
ChangeLog
10
ChangeLog
@@ -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>
|
||||
|
||||
* NEWS: Document the following change.
|
||||
|
||||
71
data/glr.c
71
data/glr.c
@@ -1880,16 +1880,7 @@ yyprocessOneStack (yyGLRStack* yystack, size_t yyk,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
else if (yyisErrorAction (yyaction))
|
||||
{
|
||||
YYDPRINTF ((stderr, "Stack %lu dies.\n",
|
||||
@@ -2236,14 +2227,59 @@ b4_syncline([@oline@], [@ofile@])])dnl
|
||||
|
||||
while (yytrue)
|
||||
{
|
||||
yySymbol yytoken_to_shift;
|
||||
size_t yys;
|
||||
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)
|
||||
YYCHK1 (yyprocessOneStack (&yystack, yys, yyposn,
|
||||
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;
|
||||
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)
|
||||
{
|
||||
yyundeleteLastStack (&yystack);
|
||||
@@ -2298,15 +2334,24 @@ b4_syncline([@oline@], [@ofile@])])dnl
|
||||
{
|
||||
yyGLRState** yystates = yystack.yytops.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;]]
|
||||
)[ yydestroyGLRState ("Cleanup: popping", yys]b4_user_args[);
|
||||
yystates[0] = yys->yypred;
|
||||
yystates[yyk] = yys->yypred;
|
||||
yystack.yynextFree -= 1;
|
||||
yystack.yyspaceLeft += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
yyfreeGLRStack (&yystack);
|
||||
}
|
||||
|
||||
|
||||
@@ -633,8 +633,6 @@ AT_CHECK([[./glr-regr7]], 2, [],
|
||||
[memory exhausted
|
||||
])
|
||||
|
||||
AT_XFAIL_IF(:)
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
@@ -695,7 +693,7 @@ void yyerror(const char *msg)
|
||||
|
||||
static int lexIndex;
|
||||
|
||||
int yylex()
|
||||
int yylex (void)
|
||||
{
|
||||
lexIndex += 1;
|
||||
switch (lexIndex)
|
||||
@@ -733,3 +731,84 @@ AT_CHECK([[./glr-regr8]], 0,
|
||||
[])
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user