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.
This commit is contained in:
Akim Demaille
2012-09-25 11:41:22 +02:00
parent a26424642b
commit 25a6ad2f10
2 changed files with 44 additions and 17 deletions

View File

@@ -227,6 +227,7 @@ b4_user_stype
/// \brief Reclaim the memory associated to a symbol. /// \brief Reclaim the memory associated to a symbol.
/// \param yymsg Why this token is reclaimed. /// \param yymsg Why this token is reclaimed.
/// If null, do not display the symbol, just free it.
/// \param yytype The symbol type. /// \param yytype The symbol type.
/// \param yyvaluep Its semantic value. /// \param yyvaluep Its semantic value.
/// \param yylocationp Its location. /// \param yylocationp Its location.
@@ -446,7 +447,8 @@ do { \
YYUSE (yymsg); YYUSE (yymsg);
YYUSE (yyvaluep); YYUSE (yyvaluep);
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); if (yymsg)
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
switch (yytype) switch (yytype)
{ {
@@ -841,20 +843,22 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[;
} }
catch (...) 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_) if (yychar != yyempty_)
{ {
/* Make sure we have latest lookahead translation. See /* Make sure we have latest lookahead translation. See
comments at user semantic actions for why this is comments at user semantic actions for why this is
necessary. */ necessary. */
yytoken = yytranslate_ (yychar); yytoken = yytranslate_ (yychar);
yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval, yydestruct_ (YY_NULL, yytoken, &yylval, &yylloc);
&yylloc);
} }
while (1 < yystate_stack_.height ()) while (1 < yystate_stack_.height ())
{ {
yydestruct_ ("Cleanup: popping", yydestruct_ (YY_NULL,
yystos_[yystate_stack_[0]], yystos_[yystate_stack_[0]],
&yysemantic_stack_[0], &yysemantic_stack_[0],
&yylocation_stack_[0]); &yylocation_stack_[0]);

View File

@@ -203,11 +203,14 @@ AT_DATA_GRAMMAR([[input.yy]],
int debug = 0; int debug = 0;
/// A class that counts its number of instances.
struct Object struct Object
{ {
static size_t counter; static size_t counter;
int val;
Object () Object (int v)
: val (v)
{ {
++counter; ++counter;
if (debug) if (debug)
@@ -245,9 +248,14 @@ AT_DATA_GRAMMAR([[input.yy]],
} }
%destructor { delete $$; } <obj>; %destructor { delete $$; } <obj>;
%printer { yyo << "counter == " << $$->counter; } <obj>; %printer
{
yyo << "counter == " << $$->counter;
if ($$->val == 'p')
throw std::runtime_error ("printer");
} <obj>;
%token <obj> 'a' 's' %token <obj> 'a' 'p' 's'
%type <obj> list item %type <obj> list item
%% %%
@@ -256,14 +264,12 @@ start: list { delete $1; };
list: list:
item { $$ = $1; } 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: item:
'a' 'a' { std::swap ($$, $1); }
{ | 'p' { std::swap ($$, $1); }
std::swap ($$, $1);
}
| 's' | 's'
{ {
std::swap ($$, $1); std::swap ($$, $1);
@@ -284,7 +290,7 @@ yylex (yy::parser::semantic_type *lvalp)
case 'l': case 'l':
throw std::runtime_error ("yylex"); throw std::runtime_error ("yylex");
default: default:
lvalp->obj = new Object; lvalp->obj = new Object (res);
// Fall through. // Fall through.
case 0: case 0:
return res; return res;
@@ -296,10 +302,22 @@ yylex (yy::parser::semantic_type *lvalp)
int int
main (int argc, const char *argv[]) main (int argc, const char *argv[])
{ {
assert (argc == 2); switch (argc)
input = argv[1]; {
case 2:
input = argv[1];
break;
case 3:
assert (!strcmp (argv[1], "--debug"));
debug = 1;
input = argv[2];
break;
default:
abort ();
}
yy::parser parser; yy::parser parser;
debug = !!getenv ("YYDEBUG"); debug |= !!getenv ("YYDEBUG");
parser.set_debug_level (debug); parser.set_debug_level (debug);
int res = 2; int res = 2;
try try
@@ -333,6 +351,11 @@ AT_PARSER_CHECK([[./input i]], [[2]], [[]],
[[exception caught: initial-action [[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_BISON_OPTION_POPDEFS
AT_CLEANUP AT_CLEANUP