[Top][All Lists]
[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])
- RFC: Freeing discarded objects,
Akim Demaille <=