[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: no users destructors if stack 0 deleted
From: |
Paul Eggert |
Subject: |
Re: no users destructors if stack 0 deleted |
Date: |
Tue, 06 Dec 2005 11:41:57 -0800 |
User-agent: |
Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux) |
"Joel E. Denny" <address@hidden> writes:
> The combined diff for the two patches appears below.
That patch was corrupted, unfortunately. I guess your Pine client
munged it? There were some leading spaces in it.
> There was also a new test case for the latter patch:
>
> http://lists.gnu.org/archive/html/bison-patches/2005-09/msg00109.html
It's helpful to bundle all the related items in to the same patch,
along with a ChangeLog entry for it. Something like the following,
which I just now installed. (It reformats the comments a bit, to use
the usual GNU style.)
Thanks again for the fixes, and for persevering to get them installed.
2005-12-06 "Joel E. Denny" <address@hidden>
* 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.
--- data/glr.c.~1.141~ 2005-12-06 11:00:37.000000000 -0800
+++ data/glr.c 2005-12-06 11:15:55.000000000 -0800
@@ -1880,16 +1880,7 @@ yyprocessOneStack (yyGLRStack* yystack,
}
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))
{
YYDPRINTF ((stderr, "Stack %lu dies.\n",
@@ -2236,14 +2227,59 @@ b4_syncline(address@hidden@], address@hidden@])])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(address@hidden@], address@hidden@])])dnl
{
yyGLRState** yystates = yystack.yytops.yystates;
if (yystates)
- while (yystates[0])
- {
- yyGLRState *yys = yystates[0];
-]b4_location_if([[ yystack.yyerror_range[1].yystate.yyloc = yys->yyloc;]]
-)[ yydestroyGLRState ("Cleanup: popping", yys]b4_user_args[);
- yystates[0] = yys->yypred;
- yystack.yynextFree -= 1;
- yystack.yyspaceLeft += 1;
- }
+ {
+ 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[yyk] = yys->yypred;
+ yystack.yynextFree -= 1;
+ yystack.yyspaceLeft += 1;
+ }
+ break;
+ }
+ }
yyfreeGLRStack (&yystack);
}
--- tests/glr-regression.at.~1.19.~ 2005-10-30 17:16:32.000000000 -0800
+++ tests/glr-regression.at 2005-12-06 11:31:32.000000000 -0800
@@ -633,8 +633,6 @@ AT_CHECK([[./glr-regr7]], 2, [],
[memory exhausted
])
-AT_XFAIL_IF(:)
-
AT_CLEANUP
@@ -667,9 +665,9 @@ AT_DATA_GRAMMAR([glr-regr8.y],
PortClause : T_PORT InterfaceDeclaration T_PORT
- { printf("%d/%d - %d/%d - %d/%d\n",
- @1.first_column, @1.last_column,
- @2.first_column, @2.last_column,
+ { printf("%d/%d - %d/%d - %d/%d\n",
+ @1.first_column, @1.last_column,
+ @2.first_column, @2.last_column,
@3.first_column, @3.last_column); }
;
@@ -695,7 +693,7 @@ void yyerror(const char *msg)
static int lexIndex;
-int yylex()
+int yylex (void)
{
lexIndex += 1;
switch (lexIndex)
@@ -714,7 +712,7 @@ int yylex()
}
int
-main (void)
+main (void)
{
yyparse();
return 0;
@@ -726,10 +724,91 @@ AT_CHECK([[bison -o glr-regr8.c glr-regr
])
AT_COMPILE([glr-regr8])
-AT_CHECK([[./glr-regr8]], 0,
+AT_CHECK([[./glr-regr8]], 0,
[empty: 9/9
1/9 - 9/9 - 13/17
],
[])
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