mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-21 10:13:03 +00:00
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:
@@ -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]);
|
||||||
|
|||||||
47
tests/c++.at
47
tests/c++.at
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user