bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

%destructor support for lalr1.cc


From: Alexandre Duret-Lutz
Subject: %destructor support for lalr1.cc
Date: 30 Dec 2003 13:49:23 +0100
User-agent: Gnus/5.0808 (Gnus v5.8.8) Emacs/21.3.50

I'm using lalr1.cc in a library, so it is important that the
parser does not leak even on errors.  The following patch
implements %destructor in a similar way as in yacc.c.

I've adjusted the test case of %destructor to exercise lalr1.cc
too, and this highlighted an unrelated bug: the location of the
error token was set to the rightmost discarded token instead of
the range of all discarded token.  I've tried to fix that too.

The error location tracking is done differently than in yacc.c,
because I haven't managed to understand how yacc.c does it.  (It
stacks locations of discarded tokens, but I don't understand how
it uses this stack and why.)  Here I just keep track of the
beginning position of the last discarded token (the leftmost
erroneous token) and compute the error location as going from
there to the current location.  I hope that makes sense; these
internals are really over my head.


2003-12-30  Alexandre Duret-Lutz  <address@hidden>

        %destructor support and merge of error locations in lalr1.cc.

        * data/lalr1.cc (b4_cxx_destruct_def): New macro.
        (Parser::stos_): Define unconditionally.
        (Parser::destruct_): New method.  Generate its body with
        b4_yydestruct_generate.
        (Parser::error_start_): New attribute.
        (Parser::parse) <yyerrlab, yyerrlab1>: Call destruct_ on erroneous
        token which are discarded.
        (Parser::parse) <yyerrlab, yyerrorlab, yyerrlab1>: Update
        error_start_ when erroneous token are discarded.
        (Parser::parse) <yyerrlab1>: Compute the location of the error
        token so that it covers all the discarded tokens.
        * tests/actions.at (_AT_CHECK_PRINTER_AND_DESTRUCTOR): Adjust so
        it can be called with `%skeleton "lalr1.cc"', and do that.

Index: data/lalr1.cc
===================================================================
RCS file: /cvsroot/bison/bison/data/lalr1.cc,v
retrieving revision 1.42
diff -u -r1.42 lalr1.cc
--- data/lalr1.cc       27 Aug 2003 07:00:10 -0000      1.42
+++ data/lalr1.cc       30 Dec 2003 10:03:44 -0000
@@ -114,6 +114,14 @@
 m4_define([b4_cc_var_decl],
          [    $1;])
 
+# b4_cxx_destruct_def(IGNORED-ARGUMENTS)
+# --------------------------------------
+# Declare the destruct_ method.
+m4_define([b4_cxx_destruct_def],
+[void
+yy::b4_parser_class_name::destruct_ (int yytype, SemanticType *yyvaluep, 
LocationType *yylocationp)[]dnl
+])
+
 # We do want M4 expansion after # for CPP macros.
 m4_changecom()
 m4_divert(0)dnl
@@ -250,6 +258,7 @@
     static const ]b4_int_type_for([b4_table])[ table_[];
     static const ]b4_int_type(b4_table_ninf, b4_table_ninf)[ table_ninf_;
     static const ]b4_int_type_for([b4_check])[ check_[];
+    static const ]b4_int_type_for([b4_stos])[ stos_[];
     static const ]b4_int_type_for([b4_r1])[ r1_[];
     static const ]b4_int_type_for([b4_r2])[ r2_[];
 
@@ -262,7 +271,6 @@
     static const RhsNumberType rhs_[];
     static const ]b4_int_type_for([b4_prhs])[ prhs_[];
     static const ]b4_int_type_for([b4_rline])[ rline_[];
-    static const ]b4_int_type_for([b4_stos])[ stos_[];
     static const ]b4_int_type_for([b4_toknum])[ token_number_[];
     virtual void reduce_print_ (int yyrule);
     virtual void stack_print_ ();
@@ -270,6 +278,8 @@
 
     /* Even more tables.  */
     static inline TokenNumberType translate_ (int token);
+    static inline void destruct_ (int yytype, SemanticType *yyvaluep,
+                                 LocationType *yylocationp);
 
     /* Constants.  */
     static const int eof_;
@@ -307,6 +317,8 @@
     /* Semantic value and location of lookahead token.  */
     SemanticType value;
     LocationType location;
+    /* Beginning of the last erroneous token popped off.  */
+    Position error_start_;
 
     /* @@$ and $$.  */
     SemanticType yyval;
@@ -349,6 +361,7 @@
 #define YYABORT                goto yyabortlab
 #define YYERROR                goto yyerrorlab
 
+]b4_yydestruct_generate([b4_cxx_destruct_def])[
 
 int
 yy::]b4_parser_class_name[::parse ()
@@ -543,23 +556,27 @@
          if (looka_ == eof_)
             for (;;)
               {
+                 error_start_ = location_stack_[0].begin;
                  state_stack_.pop ();
                  semantic_stack_.pop ();
                  location_stack_.pop ();
                 if (state_stack_.height () == 1)
                   YYABORT;
 //              YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-// FIXME: yydestruct (yystos[*yyssp], yyvsp]b4_location_if([, yylsp])[);
+                 destruct_ (stos_[state_stack_[0]],
+                            &semantic_stack_[0],
+                            &location_stack_[0]);
               }
         }
       else
         {
 #if YYDEBUG
-           YYCDEBUG << "Discarding token " << looka_
-                   << " (" << name_[ilooka_] << ")." << std::endl;
-//       yydestruct (yytoken, &yylval]b4_location_if([, &yylloc])[);
+          YYCDEBUG << "Discarding token " << looka_
+                  << " (" << name_[ilooka_] << ")." << std::endl;
 #endif
-           looka_ = empty_;
+          destruct_ (ilooka_, &value, &location);
+          error_start_ = location.begin;
+          looka_ = empty_;
         }
     }
 
@@ -582,6 +599,7 @@
 
   state_stack_.pop (len_);
   semantic_stack_.pop (len_);
+  error_start_ = location_stack_[len_ - 1].begin;
   location_stack_.pop (len_);
   state_ = state_stack_[0];
   goto yyerrlab1;
@@ -631,6 +649,8 @@
            }
        }
 #endif
+      destruct_ (stos_[state_], &semantic_stack_[0], &location_stack_[0]);
+      error_start_ = location_stack_[0].begin;
 
       state_stack_.pop ();
       semantic_stack_.pop ();
@@ -644,8 +664,13 @@
 
   YYCDEBUG << "Shifting error token, ";
 
-  semantic_stack_.push (value);
-  location_stack_.push (location);
+  {
+    Location errloc;
+    errloc.begin = error_start_;
+    errloc.end = location.end;
+    semantic_stack_.push (value);
+    location_stack_.push (errloc);
+  }
 
   state_ = n_;
   goto yynewstate;
Index: tests/actions.at
===================================================================
RCS file: /cvsroot/bison/bison/tests/actions.at,v
retrieving revision 1.27
diff -u -r1.27 actions.at
--- tests/actions.at    28 Dec 2002 08:38:14 -0000      1.27
+++ tests/actions.at    30 Dec 2003 10:03:49 -0000
@@ -1,5 +1,5 @@
 # Executing Actions.                               -*- Autotest -*-
-# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -314,15 +314,16 @@
 
 # Make sure complex $n work.
 
+AT_BISON_OPTION_PUSHDEFS([$5])
 AT_DATA_GRAMMAR([[input.y]],
 [[$5
 %{
 #include <stdio.h>
 #include <stdlib.h>
-#define RANGE(Location) (Location).first_line, (Location).last_line
-static int yylex (void);
-static void yyerror (const char *msg);
-%}
+]AT_LALR1_CC_IF(
+  [#define RANGE(Location) (Location).begin.line, (Location).end.line],
+  [#define RANGE(Location) (Location).first_line, (Location).last_line])
+[%}
 %error-verbose
 %debug
 %verbose
@@ -331,6 +332,13 @@
 {
   int ival;
 }
+
+%{
+]AT_LALR1_CC_IF([typedef yy::Location YYLTYPE;])
+[static int yylex (]AT_LEX_FORMALS[);
+static void yyerror (const char *msg);
+%}
+
 %type <ival> 'x' ';' thing line input
 
 %printer { fprintf (yyoutput, "address@hidden", $$, RANGE (@$)); }
@@ -406,7 +414,7 @@
 ;
 %%
 static int
-yylex (void)
+yylex (]AT_LEX_FORMALS[)
 {
   static const unsigned int input[] =
     {
@@ -424,13 +432,23 @@
 
   if (counter < (sizeof(input) / sizeof (input[0])))
     {
-       yylval.ival = counter;
+]AT_LALR1_CC_IF(
+[       yylval->ival = counter;
+       /* As in BASIC, line numbers go from 10 to 10.  */
+       yylloc->begin.line = yylloc->begin.column = 10 * counter;
+       yylloc->end.line = yylloc->end.column = yylloc->begin.line + 9;
+       printf ("sending: '%c' (address@hidden)\n",
+               input[[counter]], yylval->ival, RANGE (*yylloc));
+       return (int) input[[counter++]];
+],
+[       yylval.ival = counter;
        /* As in BASIC, line numbers go from 10 to 10.  */
        yylloc.first_line = yylloc.first_column = 10 * counter;
        yylloc.last_line = yylloc.last_column = yylloc.first_line + 9;
        printf ("sending: '%c' (address@hidden)\n",
-               input[counter], yylval.ival, RANGE (yylloc));
-       return (int) input[counter++];
+               input[[counter]], yylval.ival, RANGE (yylloc));
+       return (int) input[[counter++]];
+])[
     }
   else
     {
@@ -439,11 +457,34 @@
     }
 }
 
-static void
+]AT_LALR1_CC_IF(
+[/* Currently, print_ is required in C++. */
+void
+yy::Parser::print_ ()
+{
+  std::cerr << location;
+}
+
+/* A C++ error reporting function. */
+void
+yy::Parser::error_ ()
+{
+  printf ("%d-%d: %s\n", RANGE (location), message.c_str());
+}
+
+static bool yydebug;
+int
+yyparse ()
+{
+  yy::Parser parser (yydebug, yy::Location::Location ());
+  return parser.parse ();
+}
+],
+[static void
 yyerror (const char *msg)
 {
   printf ("%d-%d: %s\n", RANGE (yylloc), msg);
-}
+}])[
 
 int
 main (void)
@@ -460,7 +501,8 @@
 ]])
 
 AT_CHECK([bison -o input.c input.y])
-AT_COMPILE([input])
+AT_LALR1_CC_IF([AT_COMPILE_CXX([input])],
+               [AT_COMPILE([input])])
 AT_PARSER_CHECK([./input], 1,
 [[sending: 'x' (address@hidden)
 thing (address@hidden): 'x' (address@hidden)
@@ -512,6 +554,7 @@
 
 
 AT_CHECK_PRINTER_AND_DESTRUCTOR()
+AT_CHECK_PRINTER_AND_DESTRUCTOR([%locations %defines %skeleton "lalr1.cc"])
 
 # FIXME.  This test case fails.
 #AT_CHECK_PRINTER_AND_DESTRUCTOR([%glr-parser])

-- 
Alexandre Duret-Lutz





reply via email to

[Prev in Thread] Current Thread [Next in Thread]