From 25a6ad2f109cfc8a4683d406054141d1a2210b36 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 25 Sep 2012 11:41:22 +0200 Subject: [PATCH] lalr1.cc: check (and fix) %printer exception safety * tests/c++.at (Exception safety): Let the parser support the --debug option. On 'p', throw an exception from the %printer. * data/lalr1.cc (yyparse): Do not display the values we discard, as it uses %printer, which might have thrown the exception. --- data/lalr1.cc | 14 +++++++++----- tests/c++.at | 47 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/data/lalr1.cc b/data/lalr1.cc index 2ec1d0d7..3b8c9215 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -227,6 +227,7 @@ b4_user_stype /// \brief Reclaim the memory associated to a symbol. /// \param yymsg Why this token is reclaimed. + /// If null, do not display the symbol, just free it. /// \param yytype The symbol type. /// \param yyvaluep Its semantic value. /// \param yylocationp Its location. @@ -446,7 +447,8 @@ do { \ YYUSE (yymsg); YYUSE (yyvaluep); - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + if (yymsg) + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { @@ -841,20 +843,22 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; } catch (...) { - YYCDEBUG << "Exception caught" << std::endl; + YYCDEBUG << "Exception caught: cleaning lookahead and stack" + << std::endl; + // Do not try to display the values of the reclaimed symbols, + // as their printer might throw an exception. if (yychar != yyempty_) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yytranslate_ (yychar); - yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval, - &yylloc); + yydestruct_ (YY_NULL, yytoken, &yylval, &yylloc); } while (1 < yystate_stack_.height ()) { - yydestruct_ ("Cleanup: popping", + yydestruct_ (YY_NULL, yystos_[yystate_stack_[0]], &yysemantic_stack_[0], &yylocation_stack_[0]); diff --git a/tests/c++.at b/tests/c++.at index e4a79115..9a60bfd8 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -203,11 +203,14 @@ AT_DATA_GRAMMAR([[input.yy]], int debug = 0; + /// A class that counts its number of instances. struct Object { static size_t counter; + int val; - Object () + Object (int v) + : val (v) { ++counter; if (debug) @@ -245,9 +248,14 @@ AT_DATA_GRAMMAR([[input.yy]], } %destructor { delete $$; } ; -%printer { yyo << "counter == " << $$->counter; } ; +%printer +{ + yyo << "counter == " << $$->counter; + if ($$->val == 'p') + throw std::runtime_error ("printer"); +} ; -%token 'a' 's' +%token 'a' 'p' 's' %type list item %% @@ -256,14 +264,12 @@ start: list { delete $1; }; list: item { $$ = $1; } -| item list { $$ = $1; delete $2; } /* Right recursion to load the stack. */ +| item list { $$ = $1; delete $2; } // Right recursion to load the stack. ; item: - 'a' - { - std::swap ($$, $1); - } + 'a' { std::swap ($$, $1); } +| 'p' { std::swap ($$, $1); } | 's' { std::swap ($$, $1); @@ -284,7 +290,7 @@ yylex (yy::parser::semantic_type *lvalp) case 'l': throw std::runtime_error ("yylex"); default: - lvalp->obj = new Object; + lvalp->obj = new Object (res); // Fall through. case 0: return res; @@ -296,10 +302,22 @@ yylex (yy::parser::semantic_type *lvalp) int main (int argc, const char *argv[]) { - assert (argc == 2); - input = argv[1]; + switch (argc) + { + case 2: + input = argv[1]; + break; + case 3: + assert (!strcmp (argv[1], "--debug")); + debug = 1; + input = argv[2]; + break; + default: + abort (); + } + yy::parser parser; - debug = !!getenv ("YYDEBUG"); + debug |= !!getenv ("YYDEBUG"); parser.set_debug_level (debug); int res = 2; try @@ -333,6 +351,11 @@ AT_PARSER_CHECK([[./input i]], [[2]], [[]], [[exception caught: initial-action ]]) +AT_PARSER_CHECK([[./input aaaap]]) + +AT_PARSER_CHECK([[./input --debug aaaap]], [[2]], [[]], [[stderr]]) +AT_PARSER_CHECK([[grep '^exception caught: printer$' stderr]], [], [ignore]) + AT_BISON_OPTION_POPDEFS AT_CLEANUP -- 2.45.2