From 868d2d96387042d8aba99fe427e76d186a7a4759 Mon Sep 17 00:00:00 2001 From: "Joel E. Denny" Date: Sat, 29 Jul 2006 04:11:33 +0000 Subject: [PATCH] Clean up handling of %destructor for the end token (token 0). Discussed starting at and . Make the skeletons consistent in how they pop the end token and invoke its %destructor. * data/glr.c (yyrecoverSyntaxError, yyparse): Don't pop the start state, which has token number 0, since this would invoke the %destructor for the end token. * data/lalr1.cc (yy::parser::parse): Don't check for the final state until after shifting the end token, or else it won't be popped. * data/yacc.c (yyparse): Likewise. * data/glr.c (yyparse): Clear the lookahead after shifting it even when it's the end token. Upon termination, destroy an unshifted lookahead even when it's the end token. * data/lalr1.cc (yy::parser::parse): Likewise. * data/yacc.c (yyparse): Likewise. * src/reader.c (packgram): Don't check rule 0. This suppresses unused value warnings for the end token when the user gives the end token a %destructor. * tests/actions.at (Printers and Destructors): Test all the above. --- ChangeLog | 29 ++++++++++++++++++++++++++ data/glr.c | 11 +++++----- data/lalr1.cc | 19 ++++++++--------- data/yacc.c | 16 ++++++--------- src/reader.c | 6 +++++- tests/actions.at | 53 ++++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 101 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6880017d..d603301c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2006-07-29 Joel E. Denny + + Clean up handling of %destructor for the end token (token 0). + Discussed starting at + + and + . + + Make the skeletons consistent in how they pop the end token and invoke + its %destructor. + * data/glr.c (yyrecoverSyntaxError, yyparse): Don't pop the start + state, which has token number 0, since this would invoke the + %destructor for the end token. + * data/lalr1.cc (yy::parser::parse): Don't check for the final state + until after shifting the end token, or else it won't be popped. + * data/yacc.c (yyparse): Likewise. + + * data/glr.c (yyparse): Clear the lookahead after shifting it even when + it's the end token. Upon termination, destroy an unshifted lookahead + even when it's the end token. + * data/lalr1.cc (yy::parser::parse): Likewise. + * data/yacc.c (yyparse): Likewise. + + * src/reader.c (packgram): Don't check rule 0. This suppresses unused + value warnings for the end token when the user gives the end token a + %destructor. + + * tests/actions.at (Printers and Destructors): Test all the above. + 2006-07-24 Paul Eggert Update to latest gnulib and gettext versions. diff --git a/data/glr.c b/data/glr.c index 836df503..7c3d998d 100644 --- a/data/glr.c +++ b/data/glr.c @@ -2261,7 +2261,8 @@ yyrecoverSyntaxError (yyGLRStack* yystackp]b4_user_formals[) } } ]b4_locations_if([[ yystackp->yyerror_range[1].yystate.yyloc = yys->yyloc;]])[ - yydestroyGLRState ("Error: popping", yys]b4_user_args[); + if (yys->yypred != NULL) + yydestroyGLRState ("Error: popping", yys]b4_user_args[); yystackp->yytops.yystates[0] = yys->yypred; yystackp->yynextFree -= 1; yystackp->yyspaceLeft += 1; @@ -2373,8 +2374,7 @@ m4_popdef([b4_at_dollar])])dnl if (yyisShiftAction (yyaction)) { YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - if (yychar != YYEOF) - yychar = YYEMPTY; + yychar = YYEMPTY; yyposn += 1; yyglrShift (&yystack, 0, yyaction, yyposn, &yylval, &yylloc); if (0 < yystack.yyerrState) @@ -2490,7 +2490,7 @@ m4_popdef([b4_at_dollar])])dnl goto yyreturn; yyreturn: - if (yychar != YYEOF && yychar != YYEMPTY) + if (yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", YYTRANSLATE (yychar), &yylval]b4_locations_if([, &yylloc])[]b4_user_args[); @@ -2512,7 +2512,8 @@ m4_popdef([b4_at_dollar])])dnl { yyGLRState *yys = yystates[yyk]; ]b4_locations_if([[ yystack.yyerror_range[1].yystate.yyloc = yys->yyloc;]] -)[ yydestroyGLRState ("Cleanup: popping", yys]b4_user_args[); +)[ if (yys->yypred != NULL) + yydestroyGLRState ("Cleanup: popping", yys]b4_user_args[); yystates[yyk] = yys->yypred; yystack.yynextFree -= 1; yystack.yyspaceLeft += 1; diff --git a/data/lalr1.cc b/data/lalr1.cc index 25b9160c..377659e5 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -567,6 +567,11 @@ m4_popdef([b4_at_dollar])])dnl yynewstate: yystate_stack_.push (yystate); YYCDEBUG << "Entering state " << yystate << std::endl; + + /* Accept? */ + if (yystate == yyfinal_) + goto yyacceptlab; + goto yybackup; /* Backup. */ @@ -616,16 +621,11 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; goto yyreduce; } - /* Accept? */ - if (yyn == yyfinal_) - goto yyacceptlab; - /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - /* Discard the token being shifted unless it is eof. */ - if (yychar != yyeof_) - yychar = yyempty_; + /* Discard the token being shifted. */ + yychar = yyempty_; yysemantic_stack_.push (yylval); yylocation_stack_.push (yylloc); @@ -780,9 +780,6 @@ b4_error_verbose_if([, yytoken])[)); YY_STACK_PRINT (); } - if (yyn == yyfinal_) - goto yyacceptlab; - yyerror_range[1] = yylloc; // Using YYLLOC is tempting, but would change the location of // the lookahead. YYLOC is available though. @@ -808,7 +805,7 @@ b4_error_verbose_if([, yytoken])[)); goto yyreturn; yyreturn: - if (yychar != yyeof_ && yychar != yyempty_) + if (yychar != yyempty_) yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc); /* Do not reclaim the symbols of the rule which action triggered diff --git a/data/yacc.c b/data/yacc.c index cdc69203..74a014f1 100644 --- a/data/yacc.c +++ b/data/yacc.c @@ -1164,6 +1164,9 @@ m4_ifdef([b4_at_dollar_used], [[ yylsp[0] = yylloc; YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + if (yystate == YYFINAL) + YYACCEPT; + goto yybackup; /*-----------. @@ -1213,9 +1216,6 @@ yybackup: goto yyreduce; } - if (yyn == YYFINAL) - YYACCEPT; - /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) @@ -1224,9 +1224,8 @@ yybackup: /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - /* Discard the shifted token unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; + /* Discard the shifted token. */ + yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; @@ -1418,9 +1417,6 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } - if (yyn == YYFINAL) - YYACCEPT; - *++yyvsp = yylval; ]b4_locations_if([[ yyerror_range[1] = yylloc; @@ -1461,7 +1457,7 @@ yyexhaustedlab: #endif yyreturn: - if (yychar != YYEOF && yychar != YYEMPTY) + if (yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval]b4_locations_if([, &yylloc])[]b4_user_args[); /* Do not reclaim the symbols of the rule which action triggered diff --git a/src/reader.c b/src/reader.c index 800ecc22..928be1b8 100644 --- a/src/reader.c +++ b/src/reader.c @@ -488,7 +488,11 @@ packgram (void) rule. Thus, the midrule actions have already been scanned in order to set `used' flags for this rule's rhs, so grammar_rule_check will work properly. */ - grammar_rule_check (p); + /* Don't check the generated rule 0. It has no action, so some rhs + symbols may appear unused, but the parsing algorithm ensures that + %destructor's are invoked appropriately. */ + if (p != grammar) + grammar_rule_check (p); for (p = p->next; p && p->sym; p = p->next) { diff --git a/tests/actions.at b/tests/actions.at index 6267b74e..2a2bce75 100644 --- a/tests/actions.at +++ b/tests/actions.at @@ -197,8 +197,9 @@ AT_LALR1_CC_IF([typedef yy::location YYLTYPE; ]AT_LALR1_CC_IF([], [static void yyerror (const char *msg);]) [} -]m4_ifval([$6], [%type '(' 'x' 'y' ')' ';' thing line input])[ +]m4_ifval([$6], [%type '(' 'x' 'y' ')' ';' thing line input END])[ +/* FIXME: This %printer isn't actually tested. */ %printer { ]AT_LALR1_CC_IF([debug_stream () << $$;], @@ -226,6 +227,11 @@ AT_LALR1_CC_IF([typedef yy::location YYLTYPE; { printf ("Freeing token 'y' (%d@%d-%d)\n", $$, RANGE (@$)); } 'y' +%token END 0 +%destructor + { printf ("Freeing token END (%d@%d-%d)\n", $$, RANGE (@$)); } + END + %% /* This grammar is made to exercise error recovery. @@ -241,7 +247,7 @@ input: printf ("input (%d@%d-%d): /* Nothing */\n", $$, RANGE (@$)); } | line input /* Right recursive to load the stack so that popping at - EOF can be exercised. */ + END can be exercised. */ { $$ = 2; printf ("input (%d@%d-%d): line (%d@%d-%d) input (%d@%d-%d)\n", @@ -308,7 +314,7 @@ yylex (]AT_LEX_FORMALS[) if (source[c]) printf ("sending: '%c'", source[c]); else - printf ("sending: EOF"); + printf ("sending: END"); printf (" (%d@%d-%d)\n", c, RANGE (]AT_LOC[)); return source[c]; } @@ -372,9 +378,10 @@ sending: 'x' (1@10-19) thing (1@10-19): 'x' (1@10-19) sending: ')' (2@20-29) line (0@0-29): '(' (0@0-9) thing (1@10-19) ')' (2@20-29) -sending: EOF (3@30-39) +sending: END (3@30-39) input (0@29-29): /* Nothing */ input (2@0-29): line (0@0-29) input (0@29-29) +Freeing token END (3@30-39) Freeing nterm input (2@0-29) Successful parse. ]]) @@ -391,9 +398,10 @@ sending: 'y' (1@10-19) Freeing token 'y' (1@10-19) sending: ')' (2@20-29) line (-1@0-29): '(' (0@0-9) error (@10-19) ')' (2@20-29) -sending: EOF (3@30-39) +sending: END (3@30-39) input (0@29-29): /* Nothing */ input (2@0-29): line (-1@0-29) input (0@29-29) +Freeing token END (3@30-39) Freeing nterm input (2@0-29) Successful parse. ]]) @@ -445,12 +453,45 @@ input (0@129-129): /* Nothing */ input (2@100-129): line (10@100-129) input (0@129-129) input (2@70-129): line (7@70-99) input (2@100-129) input (2@0-129): line (-1@0-69) input (2@70-129) -130-139: syntax error, unexpected 'y', expecting $end +130-139: syntax error, unexpected 'y', expecting END Freeing nterm input (2@0-129) Freeing token 'y' (13@130-139) Parsing FAILED. ]]) + +# Syntax error caught by the parser where lookahead = END +# -------------------------------------------------------- +# Load the stack and provoke an error that cannot be caught by the +# grammar, to check that the stack is cleared. And make sure the +# lookahead is freed. +# +# '(', 'x', ')', +# '(', 'x', ')', +# 'x' +AT_PARSER_CHECK([./input '(x)(x)x'], 1, +[[sending: '(' (0@0-9) +sending: 'x' (1@10-19) +thing (1@10-19): 'x' (1@10-19) +sending: ')' (2@20-29) +line (0@0-29): '(' (0@0-9) thing (1@10-19) ')' (2@20-29) +sending: '(' (3@30-39) +sending: 'x' (4@40-49) +thing (4@40-49): 'x' (4@40-49) +sending: ')' (5@50-59) +line (3@30-59): '(' (3@30-39) thing (4@40-49) ')' (5@50-59) +sending: 'x' (6@60-69) +thing (6@60-69): 'x' (6@60-69) +sending: END (7@70-79) +70-79: syntax error, unexpected END, expecting 'x' +Freeing nterm thing (6@60-69) +Freeing nterm line (3@30-59) +Freeing nterm line (0@0-29) +Freeing token END (7@70-79) +Parsing FAILED. +]]) + + # Check destruction upon stack overflow # ------------------------------------- # Upon stack overflow, all symbols on the stack should be destroyed. -- 2.45.2