bison-patches
[Top][All Lists]
Advanced

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

RFC: Freeing discarded objects


From: Akim Demaille
Subject: RFC: Freeing discarded objects
Date: 17 Jun 2002 10:43:16 +0200
User-agent: Gnus/5.0808 (Gnus v5.8.8) XEmacs/21.4 (Honest Recruiter)

It is now significantly easier to add new features, such as
%destructor.  Here is my proposal.  It seems to demonstrate that it is
wrong to try to transform the $$ etc. while scanning the code in
braces.  So it means importing either writing a string scanner for
Flex, which seems overkill, or importing back some old routines to
scan by hand, which seems very easy.

Nevertheless, I would really appreciate comments on this.  In
particular, I tried to stick to the Yacc traditional order à la %type:
the important thing is at the beginning, then a list of symbols
behind.  Does it sound right to you?

Index: ChangeLog
from  Akim Demaille  <address@hidden>

        * data/m4sugar/m4sugar.m4 (m4_map): Recognize when the list of
        arguments is really empty, not only equal to `[]'.
        * src/symtab.h, src/symtab.c (symbol_t): `destructor' is a new
        member.
        (symbol_destructor_set): New.
        * src/output.c (symbol_destructors_output): New.
        * src/reader.h (brace_code_t, current_braced_code): New.
        * src/scan-gram.l (BRACED_CODE): Use it to branch on...
        (handle_dollar): Rename as...
        (handle_action_dollar): this.
        (handle_destructor_dollar): New.
        * src/parse-gram.y (PERCENT_DESTRUCTOR): New.
        (grammar_declaration): Use it.
        * data/bison.simple (yystos): Is always defined.
        (yydestructor): New.
        * tests/actions.at (Destructors): New.
        * tests/calc.at (_AT_CHECK_CALC_ERROR): Don't rely on egrep.

Index: data/bison.simple
===================================================================
RCS file: /cvsroot/bison/bison/data/bison.simple,v
retrieving revision 1.32
diff -u -u -r1.32 bison.simple
--- data/bison.simple 14 Jun 2002 17:29:17 -0000 1.32
+++ data/bison.simple 17 Jun 2002 08:42:03 -0000
@@ -68,6 +68,10 @@
                                 [[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]], [_])])
 
 
+## ------------------------- ##
+## Assigning token numbers.  ##
+## ------------------------- ##
+
 # b4_token_define(TOKEN-NAME, TOKEN-NUMBER)
 # -----------------------------------------
 # Output the definition of this token as #define.
@@ -432,14 +436,12 @@
   b4_check
 };
 
-#if YYDEBUG
 /* YYSTOS[[STATE-NUM]] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const b4_uint_type(b4_stos_max) yystos[[]] =
 {
   b4_stos
 };
-#endif
 
 #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
 # define YYSIZE_T __SIZE_TYPE__
@@ -649,6 +651,7 @@
 int yyparse (void);
 # endif
 #endif
+static void yydestructor (int symbol_type, YYSTYPE symbol_value);
 
 /* YY_DECL_VARIABLES -- depending whether we use a pure parser,
    variables are global, or local to YYPARSE.  */
@@ -1123,6 +1126,7 @@
        YYABORT;
       YYDPRINTF ((stderr, "Discarding token %d (%s).\n",
                  yychar, yytname[yychar1]));
+      yydestructor (yychar1, yylval);
       yychar = YYEMPTY;
     }
 
@@ -1169,6 +1173,7 @@
        }
 #endif
 
+      yydestructor (yystos[yystate], *yyvsp);
       yyvsp--;
       yystate = *--yyssp;
 #if YYLSP_NEEDED
@@ -1230,6 +1235,39 @@
 #endif
   return yyresult;
 ]}
+
+/* Release the memory associated to SYMBOL-NUMBER. */
+m4_divert_push([KILL])# M4 code.
+# b4_eval
+# -------
+# FIXME: This is really wrong, we no longer guarantee we don't evaluate
+# the user's input.  This demonstrates that decoding actions (BRACED_CODE)
+# ought to be done when output, not when read.
+m4_define([b4_eval],
+[$*])
+
+# b4_symbol_destructor(SYMBOL-NUMBER, DESTRUCTOR, TYPE-NAME)
+# ----------------------------------------------------------
+m4_define([b4_symbol_destructor],
+[m4_pushdef([b4_dollar_dollar], [symbol_value.$3])dnl
+      case $1:
+        b4_eval($2);
+        break;
+m4_popdef([b4_dollar_dollar])])
+
+m4_divert_pop([KILL])dnl# End of M4 code.
+static void
+yydestructor (int symbol_type, YYSTYPE symbol_value)
+{
+  switch (symbol_type)
+    {
+m4_map([b4_symbol_destructor], m4_defn([b4_symbol_destructors]))dnl
+      default:
+        YYDPRINTF ((stderr, "yydestructor: unknown symbol type: %s\n",
+                   yytname[[symbol_type]]));
+        break;
+    }
+}
 
 b4_epilogue
 m4_if(b4_defines_flag, 0, [],
Index: data/m4sugar/m4sugar.m4
===================================================================
RCS file: /cvsroot/bison/bison/data/m4sugar/m4sugar.m4,v
retrieving revision 1.3
diff -u -u -r1.3 m4sugar.m4
--- data/m4sugar/m4sugar.m4 3 May 2002 08:26:55 -0000 1.3
+++ data/m4sugar/m4sugar.m4 17 Jun 2002 08:42:03 -0000
@@ -432,7 +432,8 @@
 # of LIST (which can be lists themselves, for multiple arguments MACROs).
 m4_define([m4_fst], [$1])
 m4_define([m4_map],
-[m4_if([$2], [[]], [],
+[m4_if([$2], [], [],
+       [$2], [[]], [],
        [$1(m4_fst($2))[]dnl
 m4_map([$1], m4_cdr($2))])])
 
Index: src/output.c
===================================================================
RCS file: /cvsroot/bison/bison/src/output.c,v
retrieving revision 1.164
diff -u -u -r1.164 output.c
--- src/output.c 17 Jun 2002 07:05:12 -0000 1.164
+++ src/output.c 17 Jun 2002 08:42:03 -0000
@@ -606,6 +606,33 @@
 }
 
 
+/*----------------------------------------.
+| Output the symbol destructors to OOUT.  |
+`----------------------------------------*/
+
+static void
+symbol_destructors_output (FILE *out)
+{
+  int i;
+  int first = 1;
+
+  fputs ("m4_define([b4_symbol_destructors], \n[", out);
+  for (i = 0; i < nsyms; ++i)
+    if (symbols[i]->destructor)
+      {
+       symbol_t *symbol = symbols[i];
+
+       /* Symbol-number, destructor. */
+       fprintf (out, "%s[[[%d]], [[%s]], [[%s]]]",
+                first ? "" : ",\n",
+                symbol->number, symbol->destructor, symbol->type_name);
+
+       first = 0;
+      }
+  fputs ("])\n\n", out);
+}
+
+
 static void
 save_column (int symbol, int default_state)
 {
@@ -1019,6 +1046,7 @@
 
   actions_output (out);
   token_definitions_output (out);
+  symbol_destructors_output (out);
 
   muscles_m4_output (out);
 
Index: src/parse-gram.y
===================================================================
RCS file: /cvsroot/bison/bison/src/parse-gram.y,v
retrieving revision 1.11
diff -u -u -r1.11 parse-gram.y
--- src/parse-gram.y 17 Jun 2002 07:05:12 -0000 1.11
+++ src/parse-gram.y 17 Jun 2002 08:42:03 -0000
@@ -82,6 +82,7 @@
 location_t current_lhs_location;
 associativity current_assoc;
 int current_prec = 0;
+braced_code_t current_braced_code = action_braced_code;
 %}
 
 
@@ -100,13 +101,14 @@
 %token STRING CHARACTER
 %token INT
 
-%token PERCENT_TOKEN "%token"
-%token PERCENT_NTERM "%nterm"
-%token PERCENT_TYPE  "%type"
-%token PERCENT_UNION "%union"
-%token PERCENT_LEFT     "%left"
-%token PERCENT_RIGHT    "%right"
-%token PERCENT_NONASSOC "%nonassoc"
+%token PERCENT_TOKEN       "%token"
+%token PERCENT_NTERM       "%nterm"
+%token PERCENT_TYPE        "%type"
+%token PERCENT_DESTRUCTOR  "%destructor"
+%token PERCENT_UNION       "%union"
+%token PERCENT_LEFT        "%left"
+%token PERCENT_RIGHT       "%right"
+%token PERCENT_NONASSOC    "%nonassoc"
 
 %token PERCENT_EXPECT "%expect"
 %token PERCENT_START "%start"
@@ -199,6 +201,16 @@
       typed = 1;
       MUSCLE_INSERT_INT ("stype_line", @2.first_line);
       muscle_insert ("stype", $2);
+    }
+| "%destructor"
+    { current_braced_code = destructor_braced_code; }
+  BRACED_CODE symbols.1
+    {
+      symbol_list_t *list;
+      for (list = $4; list; list = list->next)
+       symbol_destructor_set (list->sym, list->location, $3);
+      symbol_list_free ($4);
+      current_braced_code = action_braced_code;
     }
 ;
 
Index: src/reader.h
===================================================================
RCS file: /cvsroot/bison/bison/src/reader.h,v
retrieving revision 1.21
diff -u -u -r1.21 reader.h
--- src/reader.h 17 Jun 2002 07:04:49 -0000 1.21
+++ src/reader.h 17 Jun 2002 08:42:03 -0000
@@ -48,7 +48,16 @@
                 location_t *loc, const char *msg);
 int gram_parse (void *control);
 
-extern int typed;
+/* The sort of braced code we are in.  */
+typedef enum braced_code_e
+  {
+    action_braced_code,
+    destructor_braced_code
+  } braced_code_t;
+/* FIXME: This is really a dirty hack which demonstrates that we
+   should probably not try to parse the actions now.  */
+extern braced_code_t current_braced_code;
+
 
 /* From reader.c. */
 void grammar_start_symbol_set PARAMS ((symbol_t *s, location_t l));
@@ -65,5 +74,6 @@
                                                 location_t l));
 extern symbol_list_t *current_rule;
 void reader PARAMS ((void));
+extern int typed;
 
 #endif /* !READER_H_ */
Index: src/scan-gram.l
===================================================================
RCS file: /cvsroot/bison/bison/src/scan-gram.l,v
retrieving revision 1.10
diff -u -u -r1.10 scan-gram.l
--- src/scan-gram.l 17 Jun 2002 07:05:12 -0000 1.10
+++ src/scan-gram.l 17 Jun 2002 08:42:03 -0000
@@ -80,7 +80,8 @@
 static int braces_level = 0;
 static int percent_percent_count = 0;
 
-static void handle_dollar PARAMS ((char *cp, location_t location));
+static void handle_action_dollar PARAMS ((char *cp, location_t location));
+static void handle_destructor_dollar PARAMS ((char *cp, location_t location));
 static void handle_at PARAMS ((char *cp));
 
 %}
@@ -122,6 +123,7 @@
   "%debug"                return PERCENT_DEBUG;
   "%define"               return PERCENT_DEFINE;
   "%defines"              return PERCENT_DEFINES;
+  "%destructor"           return PERCENT_DESTRUCTOR;
   "%error"[-_]"verbose"   return PERCENT_ERROR_VERBOSE;
   "%expect"               return PERCENT_EXPECT;
   "%file-prefix"          return PERCENT_FILE_PREFIX;
@@ -441,8 +443,19 @@
 
   "{"                  YY_OBS_GROW; braces_level++;
 
-  "$"("<"[^>]+">")?(-?[0-9]+|"$") { handle_dollar (yytext, *yylloc); }
-  "@"(-?[0-9]+|"$")            { handle_at (yytext); }
+  "$"("<"[^>]+">")?(-?[0-9]+|"$") {
+    switch (current_braced_code)
+      {
+      case action_braced_code:
+       handle_action_dollar (yytext, *yylloc);
+       break;
+
+      case destructor_braced_code:
+       handle_destructor_dollar (yytext, *yylloc);
+       break;
+      }
+  }
+  "@"(-?[0-9]+|"$")               { handle_at (yytext); }
 
   address@hidden/\'\"\{\}\n\r]+ YY_OBS_GROW;
   {eols}       YY_OBS_GROW; YY_LINES;
@@ -520,7 +533,7 @@
 `------------------------------------------------------------------*/
 
 static void
-handle_dollar (char *cp, location_t location)
+handle_action_dollar (char *cp, location_t location)
 {
   const char *type_name = NULL;
 
@@ -578,7 +591,32 @@
     {
       char buf[] = "$c";
       buf[1] = *cp;
-      complain (_("%s is invalid"), quote (buf));
+      complain_at (location, _("%s is invalid"), quote (buf));
+    }
+}
+
+
+/*---------------------------------------------------------------.
+| CP is pointing to $$ in a destructor.  This should probably be |
+| done once the grammar completely parsed, instead of during its |
+| parsing, since that means %type must be specified before       |
+| %destructor.                                                   |
+`---------------------------------------------------------------*/
+
+static void
+handle_destructor_dollar (char *cp, location_t location)
+{
+  ++cp;
+  if (*cp == '$')
+    {
+      /* FIXME: We should find something more robust.  */
+      obstack_sgrow (&string_obstack, "b4_dollar_dollar");
+    }
+  else
+    {
+      char buf[] = "$c";
+      buf[1] = *cp;
+      complain_at (location, _("%s is invalid"), quote (buf));
     }
 }
 
Index: src/symlist.c
===================================================================
RCS file: /cvsroot/bison/bison/src/symlist.c,v
retrieving revision 1.2
diff -u -u -r1.2 symlist.c
--- src/symlist.c 17 Jun 2002 07:05:12 -0000 1.2
+++ src/symlist.c 17 Jun 2002 08:42:03 -0000
@@ -19,6 +19,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "system.h"
+#include "complain.h"
 #include "symlist.h"
 
 
Index: src/symtab.c
===================================================================
RCS file: /cvsroot/bison/bison/src/symtab.c,v
retrieving revision 1.34
diff -u -u -r1.34 symtab.c
--- src/symtab.c 17 Jun 2002 07:05:12 -0000 1.34
+++ src/symtab.c 17 Jun 2002 08:42:03 -0000
@@ -48,6 +48,7 @@
 
   res->tag = xstrdup (tag);
   res->type_name = NULL;
+  res->destructor = NULL;
   res->location = location;
   res->number = NUMBER_UNDEFINED;
   res->prec = 0;
@@ -110,6 +111,25 @@
        complain_at (location,
                     _("type redeclaration for %s"), symbol_tag_get (symbol));
       symbol->type_name = type_name;
+    }
+}
+
+
+/*-------------------------------------------------------------------.
+| Set the DESTRUCTOR associated to SYMBOL.  Does nothing if passed 0 |
+| as DESTRUCTOR.                                                      |
+`-------------------------------------------------------------------*/
+
+void
+symbol_destructor_set (symbol_t *symbol, location_t location, char *destructor)
+{
+  if (destructor)
+    {
+      if (symbol->destructor)
+       complain_at (location,
+                    _("destructor redeclaration for %s"),
+                    symbol_tag_get (symbol));
+      symbol->destructor = destructor;
     }
 }
 
Index: src/symtab.h
===================================================================
RCS file: /cvsroot/bison/bison/src/symtab.h,v
retrieving revision 1.34
diff -u -u -r1.34 symtab.h
--- src/symtab.h 17 Jun 2002 07:04:24 -0000 1.34
+++ src/symtab.h 17 Jun 2002 08:42:03 -0000
@@ -57,8 +57,9 @@
   /* The key, name of the symbol.  */
   char *tag;
 
-  /* Its %type.  */
+  /* Its %type and associated destructor.  */
   char *type_name;
+  char *destructor;
 
   /* The location of its first occurence.  */
   location_t location;
@@ -109,6 +110,10 @@
    TYPE_NAME.  */
 void symbol_type_set PARAMS ((symbol_t *symbol, location_t location,
                              char *type_name));
+
+/* Set the DESTRUCTOR associated to SYMBOL.  */
+void symbol_destructor_set PARAMS ((symbol_t *symbol, location_t location,
+                                   char *destructor));
 
 /* Set the PRECEDENCE associated to SYMBOL.  Ensures that SYMBOL is a
    terminal.  Does nothing if invoked with UNDEF_ASSOC as ASSOC.  */
Index: tests/actions.at
===================================================================
RCS file: /cvsroot/bison/bison/tests/actions.at,v
retrieving revision 1.5
diff -u -u -r1.5 actions.at
--- tests/actions.at 12 Jun 2002 15:14:59 -0000 1.5
+++ tests/actions.at 17 Jun 2002 08:42:03 -0000
@@ -88,8 +88,6 @@
 
 AT_SETUP([Exotic Dollars])
 
-# Make sure complex $n work.
-
 AT_DATA([[input.y]],
 [[%{
 # include <stdio.h>
@@ -149,6 +147,136 @@
 AT_CHECK([$CC $CFLAGS $CPPFLAGS input.c -o input], 0, [], [ignore])
 AT_CHECK([./input], 0,
 [[15
+]])
+
+AT_CLEANUP
+
+
+
+## ------------- ##
+## Destructors.  ##
+## ------------- ##
+
+AT_SETUP([Destructors])
+
+# Make sure complex $n work.
+
+AT_DATA([[input.y]],
+[[%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define YYERROR_VERBOSE 1
+#define YYDEBUG 1
+/* #define YYPRINT yyprint */
+
+static int yylex (void);
+static void yyerror (const char *msg);
+static void yyprint (FILE *out, int toknum, int tokval);
+%}
+
+%union
+{
+  int ival;
+}
+%type <ival> thing 'x'
+%destructor { printf ("Freeing thing %d\n", $$); } thing
+%destructor { printf ("Freeing 'x' %d\n", $$); } 'x'
+
+%%
+input:
+  /* Nothing. */
+| input line
+;
+
+line:
+  thing thing thing ';'
+    { printf ("input: thing(%d) thing(%d) thing(%d) ';'\n", $1, $2, $3); }
+| thing thing ';'
+    { printf ("input: thing(%d) thing(%d) ';'\n", $1, $2); }
+| thing ';'
+    { printf ("input: thing(%d) ';'\n", $1); }
+| error ';'
+    { printf ("input: error ';'\n"); }
+;
+
+thing:
+  'x'  { printf ("thing: 'x' (%d)\n", $1); $$ = $1; }
+;
+%%
+static int
+yylex (void)
+{
+  static const int input[] =
+    {
+      'x', 'x', 'x', 'x', 'x', 'x', ';',
+      'x', 'x', ';',
+      'x', ';',
+      'x', 'y', ';'
+    };
+  static int counter = 0;
+
+  if (counter < (sizeof(input) / sizeof (input[0])))
+    {
+       yylval.ival = counter;
+       return input[counter++];
+    }
+  else
+    return EOF;
+}
+
+static void
+yyerror (const char *msg)
+{
+  fprintf (stdout, "%s\n", msg);
+}
+
+static void
+yyprint (FILE *out, int toknum, int tokval)
+{
+  if (0 < toknum && toknum < 256)
+    fprintf (out, " = %d", tokval);
+}
+
+int
+main (void)
+{
+  yydebug = !!getenv ("YYDEBUG");
+  if (yyparse ())
+    {
+      fprintf (stdout, "Parsing FAILED.\n");
+      exit (1);
+    }
+  fprintf (stdout, "Successful parse.\n");
+  return 0;
+}
+]])
+
+AT_CHECK([bison input.y -d -v -o input.c])
+AT_CHECK([$CC $CFLAGS $CPPFLAGS input.c -o input], 0, [], [ignore])
+AT_CHECK([./input], 0,
+[[thing: 'x' (0)
+thing: 'x' (1)
+thing: 'x' (2)
+parse error, unexpected 'x', expecting ';'
+Freeing thing 2
+Freeing thing 1
+Freeing thing 0
+Freeing 'x' 3
+Freeing 'x' 4
+Freeing 'x' 5
+input: error ';'
+thing: 'x' (7)
+thing: 'x' (8)
+input: thing(7) thing(8) ';'
+thing: 'x' (10)
+input: thing(10) ';'
+thing: 'x' (12)
+parse error, unexpected $undefined., expecting 'x' or ';'
+Freeing thing 12
+input: error ';'
+Successful parse.
 ]])
 
 AT_CLEANUP
Index: tests/calc.at
===================================================================
RCS file: /cvsroot/bison/bison/tests/calc.at,v
retrieving revision 1.23
diff -u -u -r1.23 calc.at
--- tests/calc.at 11 Jun 2002 20:16:05 -0000 1.23
+++ tests/calc.at 17 Jun 2002 08:42:03 -0000
@@ -354,7 +354,16 @@
 # Normalize the observed and expected error messages, depending upon the
 # options.
 # 1. Remove the traces from observed.
-egrep -v '^((Start|Enter|Read|Reduc|Shift)ing|state|Error:|Next|Discarding) ' 
stderr >at-stderr
+sed '/^Starting/d
+/^Entering/d
+/^Reading/d
+/^Reducing/d
+/^Shifting/d
+/^state/d
+/^Error:/d
+/^Next/d
+/^Discarding/d
+/^yydestructor:/d' stderr >at-stderr
 mv at-stderr stderr
 # 2. Create the reference error message.
 AT_DATA([[expout]],
@@ -406,18 +415,18 @@
 (2^2)^3 = 64], [486])
 
 # Some parse errors.
-_AT_CHECK_CALC_ERROR([$1], [0 0], [11],
+_AT_CHECK_CALC_ERROR([$1], [0 0], [12],
                      [1.3-1.4: parse error, unexpected "number"])
-_AT_CHECK_CALC_ERROR([$1], [1//2], [15],
+_AT_CHECK_CALC_ERROR([$1], [1//2], [17],
                      [1.3-1.4: parse error, unexpected '/', expecting "number" 
or '-' or '('])
 _AT_CHECK_CALC_ERROR([$1], [error], [4],
                      [1.1-1.2: parse error, unexpected $undefined., expecting 
"number" or '-' or '\n' or '('])
-_AT_CHECK_CALC_ERROR([$1], [1 = 2 = 3], [22],
+_AT_CHECK_CALC_ERROR([$1], [1 = 2 = 3], [25],
                      [1.7-1.8: parse error, unexpected '='])
 _AT_CHECK_CALC_ERROR([$1],
                      [
 +1],
-                     [14],
+                     [15],
                      [2.1-2.2: parse error, unexpected '+'])
 # Exercise error messages with EOF: work on an empty file.
 _AT_CHECK_CALC_ERROR([$1],
@@ -430,7 +439,7 @@
 # associated to `error'.
 _AT_CHECK_CALC_ERROR([$1],
                      [(1 ++ 2) + (0 0) = 1],
-                     [82],
+                     [91],
 [1.5-1.6: parse error, unexpected '+', expecting "number" or '-' or '('
 1.15-1.16: parse error, unexpected "number"
 calc: error: 0 != 1])




reply via email to

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