From ae952af2272fd49967349ca7280fec8c3937fb0f Mon Sep 17 00:00:00 2001 From: "Joel E. Denny" Date: Sat, 4 Mar 2006 03:29:03 +0000 Subject: [PATCH] * tests/glr-regression.at (Leaked semantic values when reporting ambiguity): Remove unnecessary union and type declarations. (Leaked lookahead after nondeterministic parse syntax error): New test case. * data/glr.c (yyparse): Check for zero stacks remaining before attempting to shift the lookahead so that you don't lose it. --- ChangeLog | 11 ++++++- data/glr.c | 35 +++++++++++---------- tests/glr-regression.at | 68 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 93 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index b3413819..1dce2553 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2006-03-04 Joel E. Denny + + * tests/glr-regression.at (Leaked semantic values when reporting + ambiguity): Remove unnecessary union and type declarations. + (Leaked lookahead after nondeterministic parse syntax error): New test + case. + * data/glr.c (yyparse): Check for zero stacks remaining before + attempting to shift the lookahead so that you don't lose it. + 2006-03-02 Joel E. Denny Avoid memory leaks by not invoking longjmp in yyreportAmbiguity. @@ -23,7 +32,7 @@ * data/glr.c (yydestroyGLRState): In debugging output, distinguish between an unresolved state (non-empty chain of semantic options) and an incomplete one (signaled by an empty chain). - (yyresolveStates): Document the interface. Move all manipulation of an + (yyresolveStates): Document the interface. Move all manipulation of a successfully or unsuccessfully resolved yyGLRState to... (yyresolveValue): ... here so that yyresolveValue always leaves a yyGLRState with consistent data and thus is easier to understand. diff --git a/data/glr.c b/data/glr.c index aab6779c..13fd2ff2 100644 --- a/data/glr.c +++ b/data/glr.c @@ -2338,9 +2338,8 @@ b4_syncline([@oline@], [@ofile@])])dnl { yySymbol yytoken_to_shift; size_t yys; - size_t yyn = yystack.yytops.yysize; - for (yys = 0; yys < yyn; yys += 1) + for (yys = 0; yys < yystack.yytops.yysize; yys += 1) yystackp->yytops.yylookaheadNeeds[yys] = yychar != YYEMPTY; /* yyprocessOneStack returns one of three things: @@ -2359,13 +2358,23 @@ b4_syncline([@oline@], [@ofile@])])dnl 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 + reductions on all stacks) helps prevent double destructor calls on yylval in the event of memory exhaustion. */ - for (yys = 0; yys < yyn; yys += 1) + for (yys = 0; yys < yystack.yytops.yysize; yys += 1) YYCHK1 (yyprocessOneStack (&yystack, yys, yyposn]b4_lpure_args[)); yyremoveDeletes (&yystack); - yyn = yystack.yytops.yysize; + if (yystack.yytops.yysize == 0) + { + yyundeleteLastStack (&yystack); + if (yystack.yytops.yysize == 0) + yyFail (&yystack][]b4_lpure_args[, YY_("syntax error")); + YYCHK1 (yyresolveStack (&yystack]b4_user_args[)); + YYDPRINTF ((stderr, "Returning to deterministic operation.\n")); +]b4_location_if([[ yystack.yyerror_range[1].yystate.yyloc = yylloc;]])[ + yyreportSyntaxError (&yystack]b4_user_args[); + goto yyuser_error; + } /* 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 @@ -2375,7 +2384,7 @@ b4_syncline([@oline@], [@ofile@])])dnl yytoken_to_shift = YYTRANSLATE (yychar); yychar = YYEMPTY; yyposn += 1; - for (yys = 0; yys < yyn; yys += 1) + for (yys = 0; yys < yystack.yytops.yysize; yys += 1) { int yyaction; const short int* yyconflicts; @@ -2391,18 +2400,8 @@ b4_syncline([@oline@], [@ofile@])])dnl (unsigned long int) yys, yystack.yytops.yystates[yys]->yylrState)); } - if (yystack.yytops.yysize == 0) - { - yyundeleteLastStack (&yystack); - if (yystack.yytops.yysize == 0) - yyFail (&yystack][]b4_lpure_args[, YY_("syntax error")); - YYCHK1 (yyresolveStack (&yystack]b4_user_args[)); - YYDPRINTF ((stderr, "Returning to deterministic operation.\n")); -]b4_location_if([[ yystack.yyerror_range[1].yystate.yyloc = yylloc;]])[ - yyreportSyntaxError (&yystack]b4_user_args[); - goto yyuser_error; - } - else if (yystack.yytops.yysize == 1) + + if (yystack.yytops.yysize == 1) { YYCHK1 (yyresolveStack (&yystack]b4_user_args[)); YYDPRINTF ((stderr, "Returning to deterministic operation.\n")); diff --git a/tests/glr-regression.at b/tests/glr-regression.at index 54c02f56..c9b745bc 100644 --- a/tests/glr-regression.at +++ b/tests/glr-regression.at @@ -1431,8 +1431,6 @@ AT_SETUP([Leaked semantic values when reporting ambiguity]) AT_DATA_GRAMMAR([glr-regr15.y], [[ %glr-parser -%union { int dummy; } -%type parent_rhs_before %destructor { parent_rhs_before_value = 0; } parent_rhs_before %{ @@ -1512,3 +1510,69 @@ AT_CHECK([[./glr-regr15]], 0, [], ]) AT_CLEANUP + + +## ------------------------------------------------------------------------- ## +## Leaked lookahead after nondeterministic parse syntax error. ## +## ------------------------------------------------------------------------- ## + +AT_SETUP([Leaked lookahead after nondeterministic parse syntax error]) +AT_DATA_GRAMMAR([glr-regr16.y], +[[ +%glr-parser +%destructor { lookahead_value = 0; } 'b' + +%{ +# include + static void yyerror (char const *); + static int yylex (void); + static int lookahead_value = 0; +# define USE(val) +%} + +%% + +start: alt1 'a' | alt2 'a' ; +alt1: ; +alt2: ; + +%% + +static void +yyerror (char const *msg) +{ + fprintf (stderr, "%s\n", msg); +} + +static int +yylex (void) +{ + static const char *input = "ab"; + if (*input == 'b') + lookahead_value = 1; + return *input++; +} + +int +main (void) +{ + int exit_status = yyparse () != 1; + if (lookahead_value) + { + fprintf (stderr, "Lookahead destructor not called.\n"); + exit_status = 1; + } + return exit_status; +} +]]) + +AT_CHECK([[bison -o glr-regr16.c glr-regr16.y]], 0, [], +[glr-regr16.y: conflicts: 1 reduce/reduce +]) +AT_COMPILE([glr-regr16]) + +AT_CHECK([[./glr-regr16]], 0, [], +[syntax error +]) + +AT_CLEANUP -- 2.45.2