lalr1.cc: check (and fix) %printer exception safety
authorAkim Demaille <akim@lrde.epita.fr>
Tue, 25 Sep 2012 09:41:22 +0000 (11:41 +0200)
committerAkim Demaille <akim@lrde.epita.fr>
Sat, 6 Oct 2012 17:53:45 +0000 (19:53 +0200)
* 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
tests/c++.at

index 2ec1d0d..3b8c921 100644 (file)
@@ -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]);
index e4a7911..9a60bfd 100644 (file)
@@ -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 $$; } <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
 
 %%
@@ -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