"Joel E. Denny" <[EMAIL PROTECTED]> 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" <[EMAIL PROTECTED]> * 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([EMAIL PROTECTED]@], [EMAIL PROTECTED]@])])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([EMAIL PROTECTED]@], [EMAIL PROTECTED]@])])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
