From: Paul Eggert Date: Tue, 6 Dec 2005 19:38:25 +0000 (+0000) Subject: * data/glr.c (yyprocessOneStack): Synchronize the shift for all X-Git-Tag: v2.3b~563 X-Git-Url: https://git.saurik.com/bison.git/commitdiff_plain/69ce078b8cf61eb5087b91538d79a1143ce77c46 * 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. --- diff --git a/ChangeLog b/ChangeLog index e5235097..fe8bf313 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2005-12-06 "Joel E. Denny" + + * 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 * NEWS: Document the following change. diff --git a/data/glr.c b/data/glr.c index de3b9bba..f72e8bbb 100644 --- a/data/glr.c +++ b/data/glr.c @@ -507,8 +507,8 @@ static const ]b4_int_type_for([b4_stos])[ yystos[] = # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) #endif ]],[ #ifndef YYLLOC_DEFAULT @@ -566,7 +566,7 @@ do { \ { \ YYFPRINTF (stderr, "%s ", Title); \ yysymprint (stderr, \ - Type, Value]b4_location_if([, Location])[]b4_user_args[); \ + Type, Value]b4_location_if([, Location])[]b4_user_args[); \ YYFPRINTF (stderr, "\n"); \ } \ } while (/*CONSTCOND*/ 0) @@ -867,7 +867,7 @@ yyuserAction (yyRuleNum yyn, int yyrhslen, yyGLRStackItem* yyvsp, YYSTYPE* yyvalp, YYLTYPE* YYOPTIONAL_LOC (yylocp), yyGLRStack* yystack - ]b4_user_formals[) + ]b4_user_formals[) { yybool yynormal __attribute__ ((__unused__)) = (yystack->yysplitPoint == NULL); @@ -962,15 +962,15 @@ yydestroyGLRState (char const *yymsg, yyGLRState *yys]b4_user_formals[) #endif if (yys->yysemantics.yyfirstVal) - { - yySemanticOption *yyoption = yys->yysemantics.yyfirstVal; - yyGLRState *yyrh; - int yyn; - for (yyrh = yyoption->yystate, yyn = yyrhsLength (yyoption->yyrule); - yyn > 0; - yyrh = yyrh->yypred, yyn -= 1) - yydestroyGLRState (yymsg, yyrh]b4_user_args[); - } + { + yySemanticOption *yyoption = yys->yysemantics.yyfirstVal; + yyGLRState *yyrh; + int yyn; + for (yyrh = yyoption->yystate, yyn = yyrhsLength (yyoption->yyrule); + yyn > 0; + yyrh = yyrh->yypred, yyn -= 1) + yydestroyGLRState (yymsg, yyrh]b4_user_args[); + } } } @@ -1016,7 +1016,7 @@ yydefaultAction (yyStateNum yystate) */ static inline void yygetLRActions (yyStateNum yystate, int yytoken, - int* yyaction, const short int** yyconflicts) + int* yyaction, const short int** yyconflicts) { int yyindex = yypact[yystate] + yytoken; if (yyindex < 0 || YYLAST < yyindex || yycheck[yyindex] != yytoken) @@ -1340,7 +1340,7 @@ yydoAction (yyGLRStack* yystack, size_t yyk, yyRuleNum yyrule, = yystack->yytops.yystates[yyk];]b4_location_if([[ if (yynrhs == 0) /* Set default location. */ - yyrhsVals[YYMAXRHS + YYMAXLEFT - 1].yystate.yyloc = yys->yyloc;]])[ + yyrhsVals[YYMAXRHS + YYMAXLEFT - 1].yystate.yyloc = yys->yyloc;]])[ for (yyi = 0; yyi < yynrhs; yyi += 1) { yys = yys->yypred; @@ -1387,9 +1387,9 @@ yy_reduce_print (yyGLRStack* yystack, size_t yyk, yyRuleNum yyrule, { fprintf (stderr, " $%d = ", yyi + 1); yysymprint (stderr, yyrhs[yyprhs[yyrule] + yyi], - &]b4_rhs_value(yynrhs, yyi + 1)[ - ]b4_location_if([, &]b4_rhs_location(yynrhs, yyi + 1))[]dnl - b4_user_args[); + &]b4_rhs_value(yynrhs, yyi + 1)[ + ]b4_location_if([, &]b4_rhs_location(yynrhs, yyi + 1))[]dnl + b4_user_args[); fprintf (stderr, "\n"); } } @@ -1408,7 +1408,7 @@ yy_reduce_print (yyGLRStack* yystack, size_t yyk, yyRuleNum yyrule, */ static inline YYRESULTTAG yyglrReduce (yyGLRStack* yystack, size_t yyk, yyRuleNum yyrule, - yybool yyforceEval]b4_user_formals[) + yybool yyforceEval]b4_user_formals[) { size_t yyposn = yystack->yytops.yystates[yyk]->yyposn; @@ -1623,7 +1623,7 @@ yyresolveStates (yyGLRState* yys, int yyn, yyGLRStack* yystack]b4_user_formals[) static YYRESULTTAG yyresolveAction (yySemanticOption* yyopt, yyGLRStack* yystack, - YYSTYPE* yyvalp, YYLTYPE* yylocp]b4_user_formals[) + YYSTYPE* yyvalp, YYLTYPE* yylocp]b4_user_formals[) { yyGLRStackItem yyrhsVals[YYMAXRHS + YYMAXLEFT + 1]; int yynrhs; @@ -1748,7 +1748,7 @@ yyresolveValue (yySemanticOption* yyoptionList, yyGLRStack* yystack, break; default: /* This cannot happen so it is not worth a YYASSERT (yyfalse), - but some compilers complain if the default case is + but some compilers complain if the default case is omitted. */ break; } @@ -1827,7 +1827,7 @@ yycompressStack (yyGLRStack* yystack) static YYRESULTTAG yyprocessOneStack (yyGLRStack* yystack, size_t yyk, - size_t yyposn, YYSTYPE* yylvalp, YYLTYPE* yyllocp + size_t yyposn, YYSTYPE* yylvalp, YYLTYPE* yyllocp ]b4_pure_formals[) { int yyaction; @@ -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; - } + break; else if (yyisErrorAction (yyaction)) { YYDPRINTF ((stderr, "Stack %lu dies.\n", @@ -2187,7 +2178,7 @@ b4_syncline([@oline@], [@ofile@])])dnl const short int* yyconflicts; yyStateNum yystate = yystack.yytops.yystates[0]->yylrState; - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) goto yyacceptlab; if (yyisDefaultedState (yystate)) @@ -2208,7 +2199,7 @@ b4_syncline([@oline@], [@ofile@])])dnl YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, yylvalp, yyllocp); + YY_SYMBOL_PRINT ("Next token is", yytoken, yylvalp, yyllocp); } yygetLRActions (yystate, yytoken, &yyaction, &yyconflicts); if (*yyconflicts != 0) @@ -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); @@ -2289,7 +2325,7 @@ b4_syncline([@oline@], [@ofile@])])dnl yyreturn: if (yytoken != YYEOF && yytoken != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", - yytoken, yylvalp]b4_location_if([, yyllocp])[]b4_user_args[); + yytoken, yylvalp]b4_location_if([, yyllocp])[]b4_user_args[); /* If the stack is well-formed, pop the stack until it is empty, destroying its entries as we go. But free the stack regardless @@ -2298,15 +2334,24 @@ b4_syncline([@oline@], [@ofile@])])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); } @@ -2390,7 +2435,7 @@ b4_epilogue m4_if(b4_defines_flag, 0, [], [@output @output_header_name@ b4_copyright([Skeleton parser for GLR parsing with Bison], - [2002, 2003, 2004, 2005])[ + [2002, 2003, 2004, 2005])[ /* As a special exception, when this parser skeleton is copied by Bison into a Bison output file, you may use that output file diff --git a/tests/glr-regression.at b/tests/glr-regression.at index 14893155..e3bdd26b 100644 --- a/tests/glr-regression.at +++ b/tests/glr-regression.at @@ -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-regr8.y]], 0, [], ]) 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 ## +## . ## +## ------------------------------------------------------------------------- ## + +AT_SETUP([No users destructors if stack 0 deleted]) + +AT_DATA_GRAMMAR([glr-regr9.y], +[[ +%{ + #include + #include + 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 '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