bison-patches
[Top][All Lists]
Advanced

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

Patch for new %generate-tables directive.


From: David Warme
Subject: Patch for new %generate-tables directive.
Date: Thu, 09 Jun 2011 22:48:00 -0400

Bison fans,

I previously commented about the disappearance of the yyprhs and yyrhs
tables, and the difficulty this poses for the manner in which our
application uses Bison.

Here is a patch for a new feature that I am contributing that will
hopefully offer the best of both worlds.  It provides a new Bison
directive:

        %generate-tables {type} tables

This directive instructs Bison to always generate the specified tables,
with the valid table names being:

        check                   merger          rline
        conflict_list_heads     pact            stos
        conflicting_rules       pgoto           table
        defact                  prhs            tname
        defgoto                 r1              toknum
        dprec                   r2              translate
        immediate               rhs

These names are matched in a case-insensitive fashion, and the user is
permitted to prefix any of these names with "yy".

The {type} field is optional, and consists of arbitrary code inside of
braces.  If present, this forces the given tables to also have the
specified type (thereby overriding Bison's automatic choice of the most
compact integral type that can represent the necessary table values).
This can be useful for applications that use pointers to these tables
and must therefore have some stable type to work with.  For example:

        %generate-tables {short}        yyprhs yyrhs

forces Bison to generate both the yyprhs[] and yyrhs[] tables, and makes
both of these be arrays of "short".

This new directive hopefully offers the best of both worlds for Bison
developers and Bison users:

1. Bison developers have more freedom to suppress tables in the future,
   allowing them to construct parsers that (by default) are smaller and
   faster than ever.

2. Users have the freedom to force these tables back in (and also force
   their type) if their application requires.

In the present Bison git repository (master branch), yyprhs and yyrhs
are the two historically relevant tables that are no longer being
generated.  This patch reinstates the old code that generates these two
tables.  The new skeletons, however, only emit these two tables if
instructed to via %generate-tables.  All other tables are always
generated (modulo glr, YYDEBUG, etc) regardless of whether mentioned in
%generate-tables or not.  The {type} feature affects all of these
tables, however.

The patches include documentation and test suite.

David


David M. Warme, Ph.D.
Principal Computer Scientist
Group W, Inc.
Fairfax, Virginia, USA.

########################################################################

 ChangeLog         |   22 ++++++++++
 NEWS              |   10 ++++
 THANKS            |    1 
 data/bison.m4     |    8 +++
 data/c.m4         |   18 +++++++-
 data/glr.c        |    7 ++-
 data/java.m4      |   18 +++++++-
 data/lalr1.cc     |   24 ++++++++++-
 data/lalr1.java   |   13 ++++--
 data/yacc.c       |    9 +++-
 doc/bison.texinfo |   41 ++++++++++++++++++
 src/forcetable.c  |  117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/forcetable.h  |   37 +++++++++++++++++
 src/local.mk      |    2 
 src/output.c      |   57 ++++++++++++++++++++++++++
 src/parse-gram.y  |   35 +++++++++++++++-
 src/scan-gram.l   |    1 
 tests/input.at    |   47 +++++++++++++++++++++
 18 files changed, 452 insertions(+), 15 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 26446ba..7bc439e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2011-06-08  David M. Warme  <address@hidden>
+
+       * Added %generate-tables directive.  Reinstated generation of prhs
+       and rhs tables (not generated unless user asks for them using new
+       %generate-tables directive).
+       * data/bison.m4: Added b4_user_enabled_table_if.
+       * data/c.m4, data/java.m4: Changed b4_int_type_for to check for
+       _user_specified_table_type.
+       Add b4_integral_parser_table_define_if_enabled.
+       * data/glr.c, data/lalr1.java, data/yacc.c: Conditionally generate
+       prhs and rhs tables.
+       * data/lalr1.cc: Conditionally declare and generate prhs and rhs
+       tables.
+       Add b4_define_integral_parser_table_declare_if_enabled.
+       * src/forcetable.c, src/forcetable.h: Created these new files.
+       * src/local.mk: Added src/forcetable.[ch].
+       * src/output.c: Reinstated generation of b4_prhs and b4_rhs.
+       Added prepare_force_tables() to conditionally define
+       b4_XYZ_table_enabled_by_user, b4_XYZ_user_specified_table_type.
+       * src/parse-gram.y: Added grammar for %generate-tables directive.
+       * src/scan-fram.l: Added %generate-tables token.
+
 2011-05-14  Joel E. Denny  <address@hidden>
 
        Version 2.5.
diff --git a/NEWS b/NEWS
index ec94f4d..ea5fa81 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,16 @@ Bison News
 
 * Changes in version ?.? (????-??-??):
 
+** New %generate-table directive
+
+  The new directive %generate-tables tells Bison to always generate
+  the specified tables.  This is useful for applications that directly
+  access one or more of the parsing tables (e.g., the PRHS and RHS
+  tables which Bison now omits by default).  It also has an option to
+  force the given tables to have a specified type (overriding Bison's
+  automatic choice of the most compact integral type).  This can be
+  useful for applications that require pointers to said tables.
+
 ** Additional yylex/yyparse arguments
 
   The new directive %param declare additional argument to both yylex
diff --git a/THANKS b/THANKS
index 41c4b55..61a0d4d 100644
--- a/THANKS
+++ b/THANKS
@@ -29,6 +29,7 @@ Csaba Raduly              address@hidden
 Dagobert Michelsen        address@hidden
 Daniel Hagerty            address@hidden
 David J. MacKenzie        address@hidden
+David Warme              address@hidden
 Derek M. Jones            address@hidden
 Di-an Jan                 address@hidden
 Dick Streefland           address@hidden
diff --git a/data/bison.m4 b/data/bison.m4
index bbf90aa..cbd4907 100644
--- a/data/bison.m4
+++ b/data/bison.m4
@@ -336,6 +336,14 @@ b4_define_flag_if([nondeterministic])      # Whether 
conflicts should be handled.
 b4_define_flag_if([yacc])              # Whether POSIX Yacc is emulated.
 
 
+# b4_user_enabled_table_if(TABLENAME, IF-ENABLED, IF-DISABLED)
+# --------------------------------------------------------
+# Expand IF-ENABLED, if user specified %generate-tables TABLENAME.
+# Expand IF-DISABLED otherwise.
+m4_define([b4_user_enabled_table_if],
+[m4_ifdef([$1_table_enabled_by_user], [$2], [$3])])
+
+
 ## --------- ##
 ## Symbols.  ##
 ## --------- ##
diff --git a/data/c.m4 b/data/c.m4
index 7a718a1..709279a 100644
--- a/data/c.m4
+++ b/data/c.m4
@@ -152,9 +152,12 @@ m4_define([b4_int_type],
 # b4_int_type_for(NAME)
 # ---------------------
 # Return the smallest int type able to handle numbers ranging from
-# `NAME_min' to `NAME_max' (included).
+# `NAME_min' to `NAME_max' (included).  This type can be forced to
+# anything by defining `NAME_user_specified_table_type'.
 m4_define([b4_int_type_for],
-[b4_int_type($1_min, $1_max)])
+[m4_ifdef([$1_user_specified_table_type],
+         $1_user_specified_table_type,
+         b4_int_type($1_min, $1_max))])
 
 
 # b4_table_value_equals(TABLE, VALUE, LITERAL)
@@ -193,6 +196,17 @@ static const b4_int_type_for([$2]) yy$1[[]] =
 ])
 
 
+# b4_integral_parser_table_define_if_enabled(TABLE-NAME, CONTENT, COMMENT)
+# ------------------------------------------------------------------------
+# Define "yy<TABLE-NAME>" with given CONTENT, but only if this table was
+# specifically enabled by the user via the %generate-tables directive.
+m4_define([b4_integral_parser_table_define_if_enabled],
+[b4_user_enabled_table_if([$2],
+                         [b4_integral_parser_table_define([$1],[$2],[$3])
+
+])])
+
+
 ## ------------------------- ##
 ## Assigning token numbers.  ##
 ## ------------------------- ##
diff --git a/data/glr.c b/data/glr.c
index f22a8f1..6119c76 100644
--- a/data/glr.c
+++ b/data/glr.c
@@ -368,7 +368,12 @@ static const ]b4_int_type_for([b4_translate])[ 
yytranslate[] =
 };
 
 #if YYDEBUG
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+]b4_integral_parser_table_define_if_enabled([prhs], [b4_prhs],
+     [[YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+      YYRHS.]])dnl
+b4_integral_parser_table_define_if_enabled([rhs], [b4_rhs],
+     [[YYRHS -- A `-1'-separated list of the rules' RHS.]])dnl
+[/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const ]b4_int_type_for([b4_rline])[ yyrline[] =
 {
   ]b4_rline[
diff --git a/data/java.m4 b/data/java.m4
index e32380c..7171d4e 100644
--- a/data/java.m4
+++ b/data/java.m4
@@ -108,9 +108,12 @@ m4_define([b4_int_type],
 # b4_int_type_for(NAME)
 # ---------------------
 # Return the smallest int type able to handle numbers ranging from
-# `NAME_min' to `NAME_max' (included).
+# `NAME_min' to `NAME_max' (included).  This type can be forced to
+# anything by defining `NAME_user_specified_table_type'.
 m4_define([b4_int_type_for],
-[b4_int_type($1_min, $1_max)])
+[m4_ifdef([$1_user_specified_table_type],
+         $1_user_specified_table_type,
+         b4_int_type($1_min, $1_max))])
 
 # b4_null
 # -------
@@ -138,6 +141,17 @@ m4_define([b4_integral_parser_table_define],
 [b4_typed_parser_table_define([b4_int_type_for([$2])], [$1], [$2], [$3])])
 
 
+# b4_integral_parser_table_define_if_enabled(TABLE-NAME, CONTENT, COMMENT)
+# ------------------------------------------------------------------------
+# Define "yy<TABLE-NAME>" with given CONTENT, but only if this table was
+# specifically enabled by the user via the %generate-tables directive.
+m4_define([b4_integral_parser_table_define_if_enabled],
+[b4_user_enabled_table_if([$2],
+                         [  b4_integral_parser_table_define([$1],[$2],[$3])
+
+])])
+
+
 ## ------------------------- ##
 ## Assigning token numbers.  ##
 ## ------------------------- ##
diff --git a/data/lalr1.cc b/data/lalr1.cc
index dab5ab9..7ba0d27 100644
--- a/data/lalr1.cc
+++ b/data/lalr1.cc
@@ -38,6 +38,16 @@ m4_define([b4_integral_parser_table_define],
   };dnl
 ])
 
+# b4_integral_parser_table_declare_if_enabled(TABLE-NAME, CONTENT, COMMENT)
+# -------------------------------------------------------------------------
+# Declare "parser::yy<TABLE-NAME_" which contents is CONTENT,
+# but only if this table was specifically enabled by the user via the
+# %generate-tables directive.
+m4_define([b4_integral_parser_table_declare_if_enabled],
+[b4_user_enabled_table_if([$2],
+                         [b4_integral_parser_table_declare([$1],[$2],[$3])
+])])
+
 
 # b4_symbol_value_template(VAL, [TYPE])
 # -------------------------------------
@@ -248,7 +258,12 @@ b4_namespace_close])[
     static std::string yytnamerr_ (const char *n);])[
 
 #if YYDEBUG
-]b4_integral_parser_table_declare([rline], [b4_rline],
+]b4_integral_parser_table_declare_if_enabled([prhs], [b4_prhs],
+     [[YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+YYRHS.]])dnl
+b4_integral_parser_table_declare_if_enabled([rhs], [b4_rhs],
+     [[YYRHS -- A `-1'-separated list of the rules' RHS.]])dnl
+b4_integral_parser_table_declare([rline], [b4_rline],
      [YYRLINE[YYN] -- Source line where rule number YYN was defined.])[
     /// Report on the debug stream that the rule \a r is going to be reduced.
     virtual void yy_reduce_print_ (int r);
@@ -1088,7 +1103,12 @@ b4_error_verbose_if([state_type yystate, int yytoken],
 #endif
 
 #if YYDEBUG
-]b4_integral_parser_table_define([rline], [b4_rline])[
+]b4_integral_parser_table_define_if_enabled([prhs], [b4_prhs],
+     [[YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+      YYRHS.]])dnl
+b4_integral_parser_table_define_if_enabled([rhs], [b4_rhs],
+     [[YYRHS -- A `-1'-separated list of the rules' RHS.]])dnl
+b4_integral_parser_table_define([rline], [b4_rline])[
 
   // Print the state stack on the debug stream.
   void
diff --git a/data/lalr1.java b/data/lalr1.java
index 7a0ace4..6253d2f 100644
--- a/data/lalr1.java
+++ b/data/lalr1.java
@@ -825,15 +825,20 @@ m4_popdef([b4_at_dollar])])dnl
 
   ]b4_parser_tables_define[
   ]b4_integral_parser_table_define([token_number], [b4_toknum],
-     [TOKEN_NUMBER_[YYLEX-NUM] -- Internal symbol number corresponding
-     to YYLEX-NUM.])[
+     [[TOKEN_NUMBER_[YYLEX-NUM] -- Internal symbol number corresponding
+     to YYLEX-NUM.]])[
 
   /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
      First, the terminals, then, starting at \a yyntokens_, nonterminals.  */
   ]b4_typed_parser_table_define([String], [tname], [b4_tname])[
 
-  ]b4_integral_parser_table_define([rline], [b4_rline],
-  [YYRLINE[YYN] -- Source line where rule number YYN was defined.])[
+]b4_integral_parser_table_define_if_enabled([prhs], [b4_prhs],
+     [[YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+  YYRHS.]])dnl
+b4_integral_parser_table_define_if_enabled([rhs], [b4_rhs],
+     [[YYRHS -- A `-1'-separated list of the rules' RHS.]])dnl
+  b4_integral_parser_table_define([rline], [b4_rline],
+  [[YYRLINE[YYN] -- Source line where rule number YYN was defined.]])[
 
   // Report on the debug stream that the rule yyrule is going to be reduced.
   private void yy_reduce_print (int yyrule, YYStack yystack)
diff --git a/data/yacc.c b/data/yacc.c
index 6bacbf8..8827074 100644
--- a/data/yacc.c
+++ b/data/yacc.c
@@ -583,8 +583,13 @@ static const ]b4_int_type_for([b4_translate])[ 
yytranslate[] =
 };
 
 #if YYDEBUG
-]b4_integral_parser_table_define([rline], [b4_rline],
-     [YYRLINE[YYN] -- Source line where rule number YYN was defined.])[
+]b4_integral_parser_table_define_if_enabled([prhs], [b4_prhs],
+     [[YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+YYRHS.]])dnl
+b4_integral_parser_table_define_if_enabled([rhs], [b4_rhs],
+     [[YYRHS -- A `-1'-separated list of the rules' RHS.]])dnl
+b4_integral_parser_table_define([rline], [b4_rline],
+     [[YYRLINE[YYN] -- Source line where rule number YYN was defined.]])[
 #endif
 
 #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
diff --git a/doc/bison.texinfo b/doc/bison.texinfo
index ce86334..f06d7f8 100644
--- a/doc/bison.texinfo
+++ b/doc/bison.texinfo
@@ -5023,6 +5023,42 @@ Specify a prefix to use for all Bison output file names. 
 The names
 are chosen as if the grammar file were named @address@hidden
 @end deffn
 
address@hidden {Directive} %generate-tables @address@hidden@} @var{tables}
+Instruct Bison to always generate each of the specified @var{tables}.  The
address@hidden is optional, and consists of arbitrary code enclosed in braces.
+If @var{type} is specified, then the specified tables are forced to have the
+given type.
+
+Bison normally tries to make the generated parser be as small and fast as
+possible.  For example, it automatically chooses the smallest integer type
+necessary for each table.  In some cases Bison will even eliminate one or
+more tables from the generated parser if it doesn't think these tables are
+needed.
+
+Some applications directly access one or more of the generated parsing
+tables.  Bison isn't smart enough to know this and doesn't take this into
+account when deciding to eliminate tables.  This directive provides a way
+for such applications to tell Bison to always generate the specified set of
+tables.  If desired, the tables can also be forced to be the specified
address@hidden
+
+The @var{tables} must be taken from the following list (case does not
+matter, and these names may optionally be preceded by a @code{yy}
+prefix):
address@hidden address@hidden address@hidden address@hidden
address@hidden @tab @code{check}                        @tab    @code{prhs}
address@hidden @tab @code{conflict_list_heads}  @tab    @code{r1}
address@hidden @tab @code{conflicting_rules}    @tab    @code{r2}
address@hidden @tab @code{defact}               @tab    @code{rhs}
address@hidden @tab @code{defgoto}              @tab    @code{rline}
address@hidden @tab @code{dprec}                        @tab    @code{stos}
address@hidden @tab @code{immediate}            @tab    @code{table}
address@hidden @tab @code{merger}               @tab    @code{tname}
address@hidden @tab @code{pact}                 @tab    @code{toknum}
address@hidden @tab @code{pgoto}                        @tab    @code{translate}
address@hidden multitable
address@hidden deffn
+
 @deffn {Directive} %language "@var{language}"
 Specify the programming language for the generated parser.  Currently
 supported languages include C, C++, and Java.
@@ -11168,6 +11204,11 @@ Bison declaration to set the prefix of the output 
files.  @xref{Decl
 Summary}.
 @end deffn
 
address@hidden {Directive} %generate-tables @address@hidden@} @var{tables}
+Always generate the specified tables, and optionally force them to be the
+specified type.  @xref{Decl Summary}.
address@hidden deffn
+
 @deffn {Directive} %glr-parser
 Bison declaration to produce a GLR parser.  @xref{GLR
 Parsers, ,Writing GLR Parsers}.
diff --git a/src/forcetable.c b/src/forcetable.c
new file mode 100644
index 0000000..f2fd8dd
--- /dev/null
+++ b/src/forcetable.c
@@ -0,0 +1,117 @@
+/* Forcing generation of selected tables.
+
+   Copyright (C) 1984, 1986, 1989, 1992, 2000-2006, 2009-2011 Free
+   Software Foundation, Inc.
+
+   This file is part of Bison, the GNU Compiler Compiler.
+
+   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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include "system.h"
+
+#include <c-strcase.h>
+#include "complain.h"
+#include "forcetable.h"
+
+/*----------------------------------------------------------.
+| List of tables that users can control generation of using |
+| the %generate-tables directive.                          |
+`----------------------------------------------------------*/
+
+static struct force_table      forced_table_info [] = {
+  {0, "check",                 NULL},
+  {0, "conflict_list_heads",   NULL},
+  {0, "conflicting_rules",     NULL},
+  {0, "defact",                        NULL},
+  {0, "defgoto",               NULL},
+  {0, "dprec",                 NULL},
+  {0, "immediate",             NULL},
+  {0, "merger",                        NULL},
+  {0, "pact",                  NULL},
+  {0, "pgoto",                 NULL},
+  {0, "prhs",                  NULL},
+  {0, "r1",                    NULL},
+  {0, "r2",                    NULL},
+  {0, "rhs",                   NULL},
+  {0, "rline",                 NULL},
+  {0, "stos",                  NULL},
+  {0, "table",                 NULL},
+  {0, "tname",                 NULL},
+  {0, "toknum",                        NULL},
+  {0, "translate",             NULL},
+  {0, NULL, NULL}
+};
+
+#define        NUM_TABLES \
+       (sizeof (forced_table_info) / sizeof (forced_table_info [0]) - 1)
+
+/*----------------------------------------------------------.
+| Force the generation of the given table, and (optionally) |
+| force it to have a given type.                           |
+`----------------------------------------------------------*/
+
+void
+force_table_generation (
+
+const char *   tabtype,        /* Type to force table to (or NULL) */
+const char *   tabname,        /* Name of table to forcibly generate */
+location       loc             /* Location of tabname */
+)
+{
+  int          i;
+  struct force_table *ftp;
+  const char *tname;
+
+  tname = tabname;
+
+  /* Remove "yy" prefix, if user provided in the declaration. */
+  if ((tname[0] == 'y' || tname[0] == 'Y') &&
+      (tname[1] == 'y' || tname[1] == 'Y'))
+    tname += 2;
+
+  for (i = 0; i < NUM_TABLES; i++)
+    {
+      ftp = &forced_table_info[i];
+      if (c_strcasecmp (tname, ftp->table_name) == 0) break;
+    }
+  if (i >= NUM_TABLES)
+    {
+      complain_at (loc, _("invalid table name %s"), tabname);
+      return;
+    }
+
+  if (ftp->forced)
+    complain_at (loc, _("redefinition of table %s"), tabname);
+  else
+    {
+      ftp->forced = 1;
+
+      aver (ftp->table_type == NULL);
+
+      if (tabtype)
+       ftp->table_type = xstrdup (tabtype);
+    }
+}
+
+const struct force_table *
+get_forced_table_info (int table_index)
+{
+const struct force_table *ftp = NULL;
+
+  if (table_index >= 0 && table_index < NUM_TABLES)
+    ftp = &forced_table_info [table_index];
+
+  return ftp;
+}
diff --git a/src/forcetable.h b/src/forcetable.h
new file mode 100644
index 0000000..a78badb
--- /dev/null
+++ b/src/forcetable.h
@@ -0,0 +1,37 @@
+/* Forcing generation of selected tables.
+
+   Copyright (C) 2002, 2004, 2009-2011 Free Software Foundation, Inc.
+
+   This file is part of Bison, the GNU Compiler Compiler.
+
+   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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef FORCETABLE_H_
+#define FORCETABLE_H_
+
+#include "location.h"
+
+struct force_table     /* %generate-tables info about one parser table. */
+{
+  bool         forced;         /* User forced generation of table? */
+  const char * table_name;     /* Name of table */
+  const char * table_type;     /* User-specified type for table */
+};
+
+void force_table_generation (const char * tabtype,
+                            const char * tabname,
+                            location loc);
+const struct force_table * get_forced_table_info (int table_index);
+
+#endif /* !FORCETABLE_H_ */
diff --git a/src/local.mk b/src/local.mk
index 1e54ce7..6ae822e 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -54,6 +54,8 @@ src_bison_SOURCES =                           \
   src/files.c                                  \
   src/files.h                                  \
   src/flex-scanner.h                           \
+  src/forcetable.c                             \
+  src/forcetable.h                             \
   src/getargs.c                                        \
   src/getargs.h                                        \
   src/gram.c                                   \
diff --git a/src/output.c b/src/output.c
index 61ea495..0a43a58 100644
--- a/src/output.c
+++ b/src/output.c
@@ -31,6 +31,7 @@
 
 #include "complain.h"
 #include "files.h"
+#include "forcetable.h"
 #include "getargs.h"
 #include "gram.h"
 #include "muscle-tab.h"
@@ -106,6 +107,7 @@ GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_int_table, int)
 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_base_table, base_number)
 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_rule_number_table, rule_number)
 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_symbol_number_table, symbol_number)
+GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_item_number_table, item_number)
 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_state_number_table, state_number)
 
 
@@ -210,6 +212,9 @@ prepare_symbols (void)
 static void
 prepare_rules (void)
 {
+  unsigned int i = 0;
+  item_number *rhs = xnmalloc (nritems, sizeof *rhs);
+  unsigned int *prhs = xnmalloc (nrules, sizeof *prhs);
   unsigned int *rline = xnmalloc (nrules, sizeof *rline);
   symbol_number *r1 = xnmalloc (nrules, sizeof *r1);
   unsigned int *r2 = xnmalloc (nrules, sizeof *r2);
@@ -220,10 +225,18 @@ prepare_rules (void)
   rule_number r;
   for (r = 0; r < nrules; ++r)
     {
+      item_number *rhsp = NULL;
+      /* Index of rule R in RHS. */
+      prhs[r] = i;
+      /* RHS of the rule R. */
+      for (rhsp = rules[r].rhs; *rhsp >= 0; ++rhsp)
+       rhs[i++] = *rhsp;
       /* LHS of the rule R. */
       r1[r] = rules[r].lhs->number;
       /* Length of rule R's RHS. */
       r2[r] = rule_rhs_length(&rules[r]);
+      /* Separator in RHS. */
+      rhs[i++] = -1;
       /* Line where rule was defined. */
       rline[r] = rules[r].location.start.line;
       /* Dynamic precedence (GLR).  */
@@ -233,7 +246,10 @@ prepare_rules (void)
       /* Immediate reduction flags (GLR).  */
       immediate[r] = rules[r].is_predicate;
     }
+  aver (i == nritems);
 
+  muscle_insert_item_number_table ("rhs", rhs, ritem[0], 1, nritems);
+  muscle_insert_unsigned_int_table ("prhs", prhs, 0, 0, nrules);
   muscle_insert_unsigned_int_table ("rline", rline, 0, 0, nrules);
   muscle_insert_symbol_number_table ("r1", r1, 0, 0, nrules);
   muscle_insert_unsigned_int_table ("r2", r2, 0, 0, nrules);
@@ -462,6 +478,46 @@ prepare_symbol_definitions (void)
 }
 
 
+/*-------------------------------------------.
+| Prepare the muscles forcing parser tables. |
+`-------------------------------------------*/
+
+static void
+prepare_force_tables (void)
+{
+int    table_index;
+const struct force_table *ftp;
+const char *key;
+const char *tabname;
+const char *tabtype;
+
+  for (table_index = 0; ; table_index++)
+    {
+      ftp = get_forced_table_info (table_index);
+      if (!ftp) break;
+      if (!ftp->forced) continue;
+
+      /* User has force-enabled this table. */
+      tabname = ftp->table_name;
+      obstack_sgrow (&format_obstack, tabname);
+      obstack_sgrow (&format_obstack, "_table_enabled_by_user");
+      obstack_1grow (&format_obstack, '\0');
+      key = obstack_finish (&format_obstack);
+      MUSCLE_INSERT_INT (key, 1);
+
+      tabtype = ftp->table_type;
+      if (!tabtype) continue;
+
+      /* User has forced the type of this table. */
+      obstack_sgrow (&format_obstack, tabname);
+      obstack_sgrow (&format_obstack, "_user_specified_table_type");
+      obstack_1grow (&format_obstack, '\0');
+      key = obstack_finish (&format_obstack);
+      MUSCLE_INSERT_STRING_RAW (key, tabtype);
+    }
+}
+
+
 /*--------------------------------------.
 | Output the tokens definition to OUT.  |
 `--------------------------------------*/
@@ -748,6 +804,7 @@ output (void)
   prepare_states ();
   prepare_actions ();
   prepare_symbol_definitions ();
+  prepare_force_tables ();
 
   prepare ();
 
diff --git a/src/parse-gram.y b/src/parse-gram.y
index 317cb86..bb0e32c 100644
--- a/src/parse-gram.y
+++ b/src/parse-gram.y
@@ -23,6 +23,7 @@
 #include "complain.h"
 #include "conflicts.h"
 #include "files.h"
+#include "forcetable.h"
 #include "getargs.h"
 #include "gram.h"
 #include "muscle-tab.h"
@@ -150,6 +151,7 @@ static char const *char_name (char);
   PERCENT_EXPECT_RR       "%expect-rr"
   PERCENT_FLAG            "%<flag>"
   PERCENT_FILE_PREFIX     "%file-prefix"
+  PERCENT_GENERATE_TABLES "%generate-tables"
   PERCENT_GLR_PARSER      "%glr-parser"
   PERCENT_INITIAL_ACTION  "%initial-action"
   PERCENT_LANGUAGE        "%language"
@@ -188,12 +190,12 @@ static char const *char_name (char);
 
 /* braceless is not to be used for rule or symbol actions, as it
    calls code_props_plain_init.  */
-%type <chars> STRING "%{...%}" EPILOGUE braceless content.opt
+%type <chars> STRING "%{...%}" EPILOGUE braceless content.opt tabletype.opt
 %type <code> "{...}" "%?{...}"
 %printer { fputs (quotearg_style (c_quoting_style, $$), stderr); }
         STRING
 %printer { fprintf (stderr, "{\n%s\n}", $$); }
-        braceless content.opt "{...}" "%{...%}" EPILOGUE
+        braceless content.opt "{...}" "%{...%}" EPILOGUE tabletype.opt
 
 %type <uniqstr> BRACKETED_ID ID ID_COLON PERCENT_FLAG TAG variable
 %printer { fputs ($$, stderr); } <uniqstr>
@@ -315,6 +317,7 @@ prologue_declaration:
 | "%expect-rr" INT                { expected_rr_conflicts = $2; }
 | "%file-prefix" STRING            { spec_file_prefix = $2; }
 | "%file-prefix" "=" STRING        { spec_file_prefix = $3; } /* deprecated */
+| "%generate-tables" tabletype.opt tablenames
 | "%glr-parser"
     {
       nondeterministic_parser = true;
@@ -624,6 +627,34 @@ named_ref.opt:
   BRACKETED_ID   { $$ = named_ref_new($1, @1); }
 ;
 
+tabletype.opt:
+/* Nothing. */ { $$ = NULL; }
+| "{...}"
+{      /* Like braceless, but no final newline added. */
+      code_props plain_code;
+      $1[strlen ($1) - 1] = '\0';
+      code_props_plain_init (&plain_code, $1+1, @1);
+      code_props_translate_code (&plain_code);
+      gram_scanner_last_string_free ();
+      $$ = plain_code.code;
+    }
+;
+
+/*----------------------------------------------------.
+| Table names listed in a %generate-tables directive. |
+`----------------------------------------------------*/
+
+tablenames:
+  /* Nothing. */
+| tablenames ID
+    {
+      /* Always preceded by tabletype.opt */
+      const char * tabtype = $<chars>0;
+      uniqstr tabname = $2;
+      force_table_generation (tabtype, tabname, @2);
+    }
+;
+
 /*---------------------------.
 | variable and content.opt.  |
 `---------------------------*/
diff --git a/src/scan-gram.l b/src/scan-gram.l
index cd901f7..cddd299 100644
--- a/src/scan-gram.l
+++ b/src/scan-gram.l
@@ -206,6 +206,7 @@ splice       (\\[ \f\t\v]*\n)*
   "%expect"[-_]"rr"                 return PERCENT_EXPECT_RR;
   "%file-prefix"                    return PERCENT_FILE_PREFIX;
   "%fixed"[-_]"output"[-_]"files"   return PERCENT_YACC;
+  "%generate"[-_]"tables"          return PERCENT_GENERATE_TABLES;
   "%initial-action"                 return PERCENT_INITIAL_ACTION;
   "%glr-parser"                     return PERCENT_GLR_PARSER;
   "%language"                       return PERCENT_LANGUAGE;
diff --git a/tests/input.at b/tests/input.at
index 8d1e80d..7c1ffe6 100644
--- a/tests/input.at
+++ b/tests/input.at
@@ -1347,3 +1347,50 @@ input.y:2.1-7: warning: POSIX Yacc forbids dashes in 
symbol names: foo-bar
 AT_BISON_CHECK([[-Werror,no-all,yacc input.y]], [[1]], [[]], [[experr]])
 
 AT_CLEANUP
+
+## ---------------- ##
+## %generate-tables ##
+## ---------------- ##
+
+# AT_CHECK_GENERATE_TABLES(GENERATE-TABLES-DECL, )
+# -------------------------------------
+# Generate a grammar having the given declaration.
+m4_define([AT_CHECK_GENERATE_TABLES],
+[
+AT_DATA([input.y],
+[[$1
+%token a b
+%start s
+%%
+s : a | b | s a | s b;
+]])
+
+AT_BISON_CHECK([input.y], [$2], [$3], [$4], [$5], [$6])
+])
+
+AT_SETUP([[%generate-tables]])
+
+AT_CHECK_GENERATE_TABLES([%generate-tables {int} yytable])
+AT_CHECK([grep '^static const.*yytable' <input.tab.c], [],
+[[static const int yytable[] =
+]])
+
+AT_CHECK_GENERATE_TABLES([%generate-tables check conflict_list_heads 
conflicting_rules defact defgoto dprec immediate merger pact pgoto prhs r1 r2 
rhs rline stos table tname toknum translate])
+
+AT_CHECK_GENERATE_TABLES([%generate-tables {int} XYZZY], [1], [],
+[[input.y:1.24-28: invalid table name XYZZY
+]])
+
+AT_CHECK_GENERATE_TABLES()
+AT_CHECK([grep '^static const.*yyprhs[]' <input.tab.c], [1])
+AT_CHECK([grep '^static const.*yyrhs[]'  <input.tab.c], [1])
+
+AT_CHECK_GENERATE_TABLES([%generate-tables {int} prhs rhs])
+AT_CHECK([grep '^static const.*yyprhs[]' <input.tab.c], [],
+[[static const int yyprhs[] =
+]])
+AT_CHECK([grep '^static const.*yyrhs[]'  <input.tab.c], [],
+[[static const int yyrhs[] =
+]])
+
+AT_CLEANUP



reply via email to

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