GNU Bison NEWS
+* Noteworthy changes in release ?.? (????-??-??) [?]
+
+** Incompatible changes
+
+*** Obsolete features
+
+ Support for YYFAIL is removed, as announced since Bison 2.4.2.
+ Support for yystype and yyltype (instead of YYSTYPE and YYLTYPE)
+ is removed, as announced in Bison 1.875.
+
+** Warnings
+
+*** Warning categories are now displayed in warnings
+
+ For instance:
+
+ foo.y:4.6: warning: type clash on default action: <foo> != <bar> [-Wother]
+
+*** Useless semantic types
+
+ Bison now warns about useless (uninhabited) semantic types. Since
+ semantic types are not declared to Bison (they are defined in the opaque
+ %union structure), it is %printer/%destructor directives about useless
+ types that trigger the warning:
+
+ %token <type1> term
+ %type <type2> nterm
+ %printer {} <type1> <type3>
+ %destructor {} <type2> <type4>
+ %%
+ nterm: term { $$ = $1; };
+
+ 3.28-34: warning: type <type3> is used, but is not associated to any symbol
+ 4.28-34: warning: type <type4> is used, but is not associated to any symbol
+
+*** Undeclared symbols
+
+ Bison used to raise an error for %printer and %destructor directives for
+ undefined symbols.
+
+ %printer {} symbol1
+ %destructor {} symbol2
+ %%
+ exp: "a";
+
+ This is now only a warning.
+
+*** Useless destructors or printers
+
+ Bison now warns about useless destructors or printers. In the following
+ example, the printer for <type1>, and the destructor for <type2> are
+ useless: all symbols of <type1> (token1) already have a printer, and all
+ symbols of type <type2> (token2) already have a destructor.
+
+ %token <type1> token1
+ <type2> token2
+ <type3> token3
+ <type4> token4
+ %printer {} token1 <type1> <type3>
+ %destructor {} token2 <type2> <type4>
+
+** Additional yylex/yyparse arguments
+
+ The new directive %param declares additional arguments to both yylex and
+ yyparse. The %lex-param, %parse-param, and %param directives support one
+ or more arguments. Instead of
+
+ %lex-param {arg1_type *arg1}
+ %lex-param {arg2_type *arg2}
+ %parse-param {arg1_type *arg1}
+ %parse-param {arg2_type *arg2}
+
+ one may now declare
+
+ %param {arg1_type *arg1} {arg2_type *arg2}
+
+** Java skeleton improvements
+
+ The constants for token names were moved to the Lexer interface.
+ Also, it is possible to add code to the parser's constructors using
+ "%code init" and "%define init_throws".
+
+** C++ skeleton improvements
+
+ The C++ parser features a syntax_error exception, which can be
+ thrown from the scanner or from user rules to raise syntax errors.
+ This facilitates reporting errors caught in sub-functions (e.g.,
+ rejecting too large integral literals from a conversion function
+ used by the scanner, or rejecting invalid combinations from a
+ factory invoked by the user actions).
+
+** Variable api.tokens.prefix
+
+ The variable api.tokens.prefix changes the way tokens are identified in
+ the generated files. This is especially useful to avoid collisions
+ with identifiers in the target language. For instance
+
+ %token FILE for ERROR
+ %define api.tokens.prefix "TOK_"
+ %%
+ start: FILE for ERROR;
+
+ will generate the definition of the symbols TOK_FILE, TOK_for, and
+ TOK_ERROR in the generated sources. In particular, the scanner must
+ use these prefixed token names, although the grammar itself still
+ uses the short names (as in the sample rule given above).
+
+** Variable api.namespace
+
+ The "namespace" variable is renamed "api.namespace". Backward
+ compatibility is ensured, but upgrading is recommended.
+
+** Variable parse.error
+
+ The variable error controls the verbosity of error messages. The
+ use of the %error-verbose directive is deprecated in favor of
+ %define parse.error "verbose".
+
+** Semantic predicates
+
+ The new, experimental, semantic-predicate feature allows actions of
+ the form %?{ BOOLEAN-EXPRESSION }, which cause syntax errors (as for
+ YYERROR) if the expression evaluates to 0, and are evaluated immediately
+ in GLR parsers, rather than being deferred. The result is that they
+ allow the programmer to prune possible parses based on the values of
+ run-time expressions.
+
* Noteworthy changes in release ?.? (????-??-??) [?]
+ Bison no longer executes user-specified M4 code when processing a grammar.
+
+ ** Future Changes
+
+ In addition to the removal of the features announced in Bison 2.6, the
+ next major release will remove the "Temporary hack for adding a semicolon
+ to the user action", as announced in the release 2.5. Instead of:
+
+ exp: exp "+" exp { $$ = $1 + $3 };
+
+ write:
+
+ exp: exp "+" exp { $$ = $1 + $3; };
+
+ ** Bug fixes
+
+ *** Type names are now properly escaped.
+
+ *** glr.cc: set_debug_level and debug_level work as expected.
+
+ *** Stray @ or $ in actions
+
+ While Bison used to warn about stray $ or @ in action rules, it did not
+ for other actions such as printers, destructors, or initial actions. It
+ now does.
+
+ ** Type names in actions
+
+ For consistency with rule actions, it is now possible to qualify $$ by a
+ type-name in destructors, printers, and initial actions. For instance:
+
+ %printer { fprintf (yyo, "(%d, %f)", $<ival>$, $<fval>$); } <*> <>;
+
+ will display two values for each typed and untyped symbol (provided
+ that YYSTYPE has both "ival" and "fval" fields).
* Noteworthy changes in release 2.6 (2012-07-19) [stable]
* Short term
++** scan-code.l
++Avoid variables for format strings, as then GCC cannot check them.
++show_sub_messages should call show_sub_message.
++
** Variable names.
What should we name `variant' and `lex_symbol'?
b4_define_flag_if([token_table]) # Whether yytoken_table is demanded.
b4_define_flag_if([yacc]) # Whether POSIX Yacc is emulated.
-# yytoken_table is needed to support verbose errors.
-b4_error_verbose_if([m4_define([b4_token_table_flag], [1])])
+
+## --------- ##
+## Symbols. ##
+## --------- ##
+
+# In order to unify the handling of the various aspects of symbols
+# (tag, type_name, whether terminal, etc.), bison.exe defines one
+# macro per (token, field), where field can has_id, id, etc.: see
+# src/output.c:prepare_symbols_definitions().
+#
+# The following macros provide access to these values.
+
+# b4_symbol_(NUM, FIELD)
+# ----------------------
+# Recover a FIELD about symbol #NUM. Thanks to m4_indir, fails if
+# undefined.
+m4_define([b4_symbol_],
+[m4_indir([b4_symbol($1, $2)])])
+
+
+# b4_symbol(NUM, FIELD)
+# ---------------------
+# Recover a FIELD about symbol #NUM. Thanks to m4_indir, fails if
+# undefined. If FIELD = id, prepend the prefix.
+m4_define([b4_symbol],
+[m4_case([$2],
+ [id], [m4_do([b4_percent_define_get([api.tokens.prefix])],
+ [b4_symbol_([$1], [id])])],
+ [b4_symbol_($@)])])
+
+
+# b4_symbol_if(NUM, FIELD, IF-TRUE, IF-FALSE)
+# -------------------------------------------
+# If FIELD about symbol #NUM is 1 expand IF-TRUE, if is 0, expand IF-FALSE.
+# Otherwise an error.
+m4_define([b4_symbol_if],
+[m4_case(b4_symbol([$1], [$2]),
+ [1], [$3],
+ [0], [$4],
+ [m4_fatal([$0: field $2 of $1 is not a Boolean:] b4_symbol([$1], [$2]))])])
+
+
+# b4_symbol_action_location(SYMBOL-NUM, KIND)
+# -------------------------------------------
+# Report the location of the KIND action as FILE:LINE.
+m4_define([b4_symbol_action_location],
+[b4_symbol([$1], [$2_file]):b4_syncline([b4_symbol([$1], [$2_line])])])
+
+
+# b4_symbol_action(SYMBOL-NUM, KIND)
+# ----------------------------------
+# Run the action KIND (destructor or printer) for SYMBOL-NUM.
+# Same as in C, but using references instead of pointers.
+m4_define([b4_symbol_action],
+[b4_symbol_if([$1], [has_$2],
- [m4_pushdef([b4_dollar_dollar],
- [b4_symbol_value([(*yyvaluep)],
- b4_symbol_if([$1], [has_type],
- [b4_symbol([$1], [type])]))])dnl
- m4_pushdef([b4_at_dollar], [(*yylocationp)])dnl
++[b4_dollar_pushdef([(*yyvaluep)],
++ b4_symbol_if([$1], [has_type],
++ [m4_dquote(b4_symbol([$1], [type]))]),
++ [(*yylocationp)])dnl
+ b4_symbol_case_([$1])[]dnl
+b4_syncline([b4_symbol([$1], [$2_line])], ["b4_symbol([$1], [$2_file])"])
+ b4_symbol([$1], [$2])
+b4_syncline([@oline@], [@ofile@])
+ break;
+
- m4_popdef([b4_at_dollar])dnl
- m4_popdef([b4_dollar_dollar])dnl
++b4_dollar_popdef[]dnl
+])])
+
+
+# b4_symbol_destructor(SYMBOL-NUM)
+# b4_symbol_printer(SYMBOL-NUM)
+# --------------------------------
+m4_define([b4_symbol_destructor], [b4_symbol_action([$1], [destructor])])
+m4_define([b4_symbol_printer], [b4_symbol_action([$1], [printer])])
+
+
+# b4_symbol_case_(SYMBOL-NUM)
+# ---------------------------
+# Issue a "case NUM" for SYMBOL-NUM.
+m4_define([b4_symbol_case_],
+[ case b4_symbol([$1], [number]): // b4_symbol([$1], [tag])
+])
+
+
+# b4_symbol_foreach(MACRO)
+# ------------------------
+# Invoke MACRO(SYMBOL-NUM) for each SYMBOL-NUM.
+m4_define([b4_symbol_foreach],
+ [m4_map([$1], m4_defn([b4_symbol_numbers]))])
+
+# b4_symbol_map(MACRO)
+# --------------------
+# Return a list (possibly empty elements) of MACRO invoked for each
+# SYMBOL-NUM.
+m4_define([b4_symbol_map],
+[m4_map_args_sep([$1(], [)], [,], b4_symbol_numbers)])
+
+
+# b4_token_visible_if(NUM, IF-TRUE, IF-FALSE)
+# -------------------------------------------
+# Whether NUM denotes a token that has an exported definition (i.e.,
+# shows in enum yytokentype).
+m4_define([b4_token_visible_if],
+[b4_symbol_if([$1], [is_token],
+ [b4_symbol_if([$1], [has_id], [$2], [$3])],
+ [$3])])
+
+# b4_token_has_definition(NUM)
+# ----------------------------
+# 1 if NUM is visible, nothing otherwise.
+m4_define([b4_token_has_definition],
+[b4_token_visible_if([$1], [1])])
+
+# b4_any_token_visible_if([IF-TRUE], [IF-FALSE])
+# ----------------------------------------------
+# Whether there is a token that needs to be defined.
+m4_define([b4_any_token_visible_if],
+[m4_ifval(b4_symbol_foreach([b4_token_has_definition]),
+ [$1], [$2])])
+
+
+# b4_token_format(FORMAT, NUM)
+# ----------------------------
+m4_define([b4_token_format],
+[b4_token_visible_if([$2],
+[m4_quote(m4_format([$1],
+ [b4_symbol([$2], [id])],
+ [b4_symbol([$2], [user_number])]))])])
+
+
+## ------- ##
+## Types. ##
+## ------- ##
+
+# b4_type_action_(NUMS)
+# ---------------------
+# Run actions for the symbol NUMS that all have the same type-name.
+# Skip NUMS that have no type-name.
+m4_define([b4_type_action_],
+[b4_symbol_if([$1], [has_type],
+[m4_map([b4_symbol_case_], [$@])[]dnl
+ b4_dollar_dollar([b4_symbol([$1], [number])],
+ [b4_symbol([$1], [tag])],
+ [b4_symbol([$1], [type])]);
+ break;
+
+])])
+
+# b4_type_foreach(MACRO)
+# ----------------------
+# Invoke MACRO(SYMBOL-NUMS) for each set of SYMBOL-NUMS for each type set.
+m4_define([b4_type_foreach],
+ [m4_map([$1], m4_defn([b4_type_names]))])
--- /dev/null
-[m4_if([$2], [[]],
- [m4_ifval([$3], [($1.$3)],
- [$1])],
- [($1.$2)])])
+ -*- Autoconf -*-
+
+ # Common code for C-like languages (C, C++, Java, etc.)
+
+ # Copyright (C) 2012 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
+ # 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/>.
+
+ # b4_dollar_dollar_(VALUE, FIELD, DEFAULT-FIELD)
+ # ----------------------------------------------
+ # If FIELD (or DEFAULT-FIELD) is non-null, return "VALUE.FIELD",
+ # otherwise just VALUE. Be sure to pass "(VALUE)" is VALUE is a
+ # pointer.
+ m4_define([b4_dollar_dollar_],
++[b4_symbol_value([$1],
++ m4_if([$2], [[]],
++ [[$3]], [[$2]]))])
+
+ # b4_dollar_pushdef(VALUE-POINTER, DEFAULT-FIELD, LOCATION)
+ # b4_dollar_popdef
+ # ---------------------------------------------------------
+ # Define b4_dollar_dollar for VALUE and DEFAULT-FIELD,
+ # and b4_at_dollar for LOCATION.
+ m4_define([b4_dollar_pushdef],
+ [m4_pushdef([b4_dollar_dollar],
+ [b4_dollar_dollar_([$1], m4_dquote($][1), [$2])])dnl
+ m4_pushdef([b4_at_dollar], [$3])dnl
+ ])
+ m4_define([b4_dollar_popdef],
+ [m4_popdef([b4_at_dollar])dnl
+ m4_popdef([b4_dollar_dollar])dnl
+ ])
#endif
])
m4_ifdef([b4_initial_action], [
- m4_pushdef([b4_at_dollar], [yylloc])dnl
- m4_pushdef([b4_dollar_dollar], [yylval])dnl
+ b4_dollar_pushdef([yylval], [], [yylloc])dnl
-/* User initialization code. */
-b4_user_initial_action
+ /* User initialization code. */
+ b4_user_initial_action
- m4_popdef([b4_dollar_dollar])dnl
- m4_popdef([b4_at_dollar])])dnl
+ b4_dollar_popdef])[]dnl
[
if (! yyinitGLRStack (yystackp, YYINITDEPTH))
goto yyexhaustedlab;
m4_include(b4_pkgdatadir/[c++.m4])
- [m4_pushdef([b4_dollar_dollar],
- [b4_symbol_value_template([yysym.value],
- b4_symbol_if([$1], [has_type],
- [b4_symbol([$1], [type])]))])dnl
- m4_pushdef([b4_at_dollar], [yysym.location])dnl
+
+# b4_integral_parser_table_declare(TABLE-NAME, CONTENT, COMMENT)
+# --------------------------------------------------------------
+# Declare "parser::yy<TABLE-NAME>_" which contents is CONTENT.
+m4_define([b4_integral_parser_table_declare],
+[m4_ifval([$3], [b4_c_comment([$3], [ ])
+])dnl
+ static const b4_int_type_for([$2]) yy$1_[[]];dnl
+])
+
+# b4_integral_parser_table_define(TABLE-NAME, CONTENT, COMMENT)
+# -------------------------------------------------------------
+# Define "parser::yy<TABLE-NAME>_" which contents is CONTENT.
+m4_define([b4_integral_parser_table_define],
+[ const b4_int_type_for([$2])
+ b4_parser_class_name::yy$1_[[]] =
+ {
+ $2
+ };dnl
+])
+
+
+# b4_symbol_value_template(VAL, [TYPE])
+# -------------------------------------
+# Same as b4_symbol_value, but used in a template method. It makes
+# a difference when using variants.
+m4_copy([b4_symbol_value], [b4_symbol_value_template])
+
+
+# b4_lhs_value([TYPE])
+# --------------------
+# Expansion of $<TYPE>$.
+m4_define([b4_lhs_value],
+ [b4_symbol_value([yylhs.value], [$1])])
+
+
+# b4_lhs_location()
+# -----------------
+# Expansion of @$.
+m4_define([b4_lhs_location],
+ [yylhs.location])
+
+
+# b4_rhs_data(RULE-LENGTH, NUM)
+# -----------------------------
+# Return the data corresponding to the symbol #NUM, where the current
+# rule has RULE-LENGTH symbols on RHS.
+m4_define([b4_rhs_data],
+ [yystack_@{b4_subtract($@)@}])
+
+
+# b4_rhs_state(RULE-LENGTH, NUM)
+# ------------------------------
+# The state corresponding to the symbol #NUM, where the current
+# rule has RULE-LENGTH symbols on RHS.
+m4_define([b4_rhs_state],
+ [b4_rhs_data([$1], [$2]).state])
+
+
+# b4_rhs_value(RULE-LENGTH, NUM, [TYPE])
+# --------------------------------------
+# Expansion of $<TYPE>NUM, where the current rule has RULE-LENGTH
+# symbols on RHS.
+m4_define([b4_rhs_value],
+ [b4_symbol_value([b4_rhs_data([$1], [$2]).value], [$3])])
+
+
+# b4_rhs_location(RULE-LENGTH, NUM)
+# ---------------------------------
+# Expansion of @NUM, where the current rule has RULE-LENGTH symbols
+# on RHS.
+m4_define([b4_rhs_location],
+ [b4_rhs_data([$1], [$2]).location])
+
+
+# b4_symbol_action(SYMBOL-NUM, KIND)
+# ----------------------------------
+# Run the action KIND (destructor or printer) for SYMBOL-NUM.
+# Same as in C, but using references instead of pointers.
+m4_define([b4_symbol_action],
+[b4_symbol_if([$1], [has_$2],
- m4_popdef([b4_at_dollar])dnl
- m4_popdef([b4_dollar_dollar])dnl
++[m4_pushdef([b4_symbol_value], m4_defn([b4_symbol_value_template]))[]dnl
++b4_dollar_pushdef([yysym.value],
++ b4_symbol_if([$1], [has_type],
++ [m4_dquote(b4_symbol([$1], [type]))]),
++ [yysym.location])dnl
+ b4_symbol_case_([$1])
+b4_syncline([b4_symbol([$1], [$2_line])], ["b4_symbol([$1], [$2_file])"])
+ b4_symbol([$1], [$2])
+b4_syncline([@oline@], [@ofile@])
+ break;
+
++m4_popdef([b4_symbol_value])[]dnl
++b4_dollar_popdef[]dnl
+])])
+
+
+m4_pushdef([b4_copyright_years],
+ [2002-2012])
+
m4_define([b4_parser_class_name],
[b4_percent_define_get([[parser_class_name]])])
YYCDEBUG << "Starting parse" << std::endl;
]m4_ifdef([b4_initial_action], [
- m4_pushdef([b4_at_dollar], [yyla.location])dnl
- m4_pushdef([b4_dollar_dollar], [yyla.value])dnl
-b4_dollar_pushdef([yylval], [], [yylloc])dnl
-/* User initialization code. */
-b4_user_initial_action
++b4_dollar_pushdef([yyla.value], [], [yyla.location])dnl
+ /* User initialization code. */
+ b4_user_initial_action
- m4_popdef([b4_dollar_dollar])dnl
- m4_popdef([b4_at_dollar])])dnl
+ b4_dollar_popdef])[]dnl
- [ /* Initialize the stacks. The initial state will be pushed in
+ [ /* Initialize the stack. The initial state will be set in
yynewstate, since the latter expects the semantical and the
location values to have been already stored, initialize these
stacks with a primary value. */
yyerrstatus_ = 0;
]m4_ifdef([b4_initial_action], [
- m4_pushdef([b4_at_dollar], [yylloc])dnl
- m4_pushdef([b4_dollar_dollar], [yylval])dnl
+ b4_dollar_pushdef([yylval], [], [yylloc])dnl
-/* User initialization code. */
-b4_user_initial_action
+ /* User initialization code. */
+ b4_user_initial_action
- m4_popdef([b4_dollar_dollar])dnl
- m4_popdef([b4_at_dollar])])dnl
+ b4_dollar_popdef])[]dnl
[ /* Initialize the stack. */
yystack.push (yystate, yylval]b4_locations_if([, yylloc])[);
--- /dev/null
+## Copyright (C) 2002, 2005-2012 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
+## 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/>.
+
+dist_pkgdata_DATA = \
+ data/README \
+ data/bison.m4 \
+ data/c++-skel.m4 \
+ data/c++.m4 \
++ data/c-like.m4 \
+ data/c-skel.m4 \
+ data/c.m4 \
+ data/glr.c \
+ data/glr.cc \
+ data/java-skel.m4 \
+ data/java.m4 \
+ data/lalr1.cc \
+ data/lalr1.java \
+ data/location.cc \
+ data/stack.hh \
+ data/variant.hh \
+ data/yacc.c
+
+m4sugardir = $(pkgdatadir)/m4sugar
+dist_m4sugar_DATA = \
+ data/m4sugar/foreach.m4 \
+ data/m4sugar/m4sugar.m4
+
+xsltdir = $(pkgdatadir)/xslt
+dist_xslt_DATA = \
+ data/xslt/bison.xsl \
+ data/xslt/xml2dot.xsl \
+ data/xslt/xml2text.xsl \
+ data/xslt/xml2xhtml.xsl
void muscle_pair_list_grow (const char *muscle,
- const char *a1, const char *a2)
+ const char *a1, const char *a2)
{
char *pair;
- obstack_sgrow (&muscle_obstack, "[[[");
- MUSCLE_OBSTACK_SGROW (&muscle_obstack, a1);
- obstack_sgrow (&muscle_obstack, "]], [[");
- MUSCLE_OBSTACK_SGROW (&muscle_obstack, a2);
- obstack_sgrow (&muscle_obstack, "]]]");
+ obstack_sgrow (&muscle_obstack, "[");
+ obstack_quote (&muscle_obstack, a1);
+ obstack_sgrow (&muscle_obstack, ", ");
+ obstack_quote (&muscle_obstack, a2);
+ obstack_sgrow (&muscle_obstack, "]");
obstack_1grow (&muscle_obstack, 0);
pair = obstack_finish (&muscle_obstack);
muscle_grow (muscle, pair, ",\n");
muscle_boundary_grow (char const *key, boundary bound)
{
char *extension;
- MUSCLE_OBSTACK_SGROW (&muscle_obstack, bound.file);
+ obstack_sgrow (&muscle_obstack, "[[");
+ obstack_escape (&muscle_obstack, bound.file);
- obstack_1grow (&muscle_obstack, ':');
+ obstack_1grow (&muscle_obstack, ':');
obstack_fgrow1 (&muscle_obstack, "%d", bound.line);
- obstack_1grow (&muscle_obstack, '.');
+ obstack_1grow (&muscle_obstack, '.');
obstack_fgrow1 (&muscle_obstack, "%d", bound.column);
- obstack_1grow (&muscle_obstack, '\0');
+ obstack_sgrow (&muscle_obstack, "]]");
+ obstack_1grow (&muscle_obstack, '\0');
extension = obstack_finish (&muscle_obstack);
muscle_grow (key, extension, "");
obstack_free (&muscle_obstack, extension);
char const *loc_name;
loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
if (!muscle_find_const (loc_name))
- fatal(_("%s: undefined %%define variable %s"),
+ complain (fatal, _("%s: undefined %%define variable %s"),
"muscle_percent_define_get_loc", quote (variable));
- return muscle_location_decode (loc_name);
+ return location_decode (loc_name);
}
char const *
extern struct obstack muscle_obstack;
#define MUSCLE_INSERT_BOOL(Key, Value) \
- do { \
- int v__ = Value; \
- MUSCLE_INSERT_INT (Key, v__); \
- } while(0)
+ do { \
- int v = Value; \
- MUSCLE_INSERT_INT (Key, v); \
++ int v__ = Value; \
++ MUSCLE_INSERT_INT (Key, v__); \
+ } while (0)
#define MUSCLE_INSERT_INT(Key, Value) \
- do { \
- obstack_fgrow1 (&muscle_obstack, "%d", Value); \
- obstack_1grow (&muscle_obstack, 0); \
- muscle_insert (Key, obstack_finish (&muscle_obstack)); \
- } while(0)
+ do { \
+ obstack_fgrow1 (&muscle_obstack, "%d", Value); \
+ obstack_1grow (&muscle_obstack, 0); \
+ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
+ } while (0)
#define MUSCLE_INSERT_LONG_INT(Key, Value) \
- do { \
- obstack_fgrow1 (&muscle_obstack, "%ld", Value); \
- obstack_1grow (&muscle_obstack, 0); \
- muscle_insert (Key, obstack_finish (&muscle_obstack)); \
- } while(0)
+ do { \
+ obstack_fgrow1 (&muscle_obstack, "%ld", Value); \
+ obstack_1grow (&muscle_obstack, 0); \
+ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
+ } while (0)
+/* Key -> Value, but don't apply escaping to Value. */
#define MUSCLE_INSERT_STRING_RAW(Key, Value) \
- do { \
- obstack_sgrow (&muscle_obstack, Value); \
- obstack_1grow (&muscle_obstack, 0); \
- muscle_insert (Key, obstack_finish (&muscle_obstack)); \
- } while(0)
+ do { \
+ obstack_sgrow (&muscle_obstack, Value); \
+ obstack_1grow (&muscle_obstack, 0); \
+ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
+ } while (0)
+/* Key -> Value, applying M4 escaping to Value. */
#define MUSCLE_INSERT_STRING(Key, Value) \
- do { \
- MUSCLE_OBSTACK_SGROW (&muscle_obstack, Value); \
- obstack_1grow (&muscle_obstack, 0); \
- muscle_insert (Key, obstack_finish (&muscle_obstack)); \
- } while(0)
-
- #define MUSCLE_OBSTACK_SGROW(Obstack, Value) \
- do { \
- char const *p__; \
- for (p__ = Value; *p__; p__++) \
- switch (*p__) \
- { \
- case '$': obstack_sgrow (Obstack, "$]["); break; \
- case '@': obstack_sgrow (Obstack, "@@" ); break; \
- case '[': obstack_sgrow (Obstack, "@{" ); break; \
- case ']': obstack_sgrow (Obstack, "@}" ); break; \
- default: obstack_1grow (Obstack, *p__); break; \
- } \
- } while(0)
+ do { \
+ obstack_escape (&muscle_obstack, Value); \
+ obstack_1grow (&muscle_obstack, 0); \
+ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
+ } while (0)
#define MUSCLE_INSERT_C_STRING(Key, Value) \
- do { \
- MUSCLE_OBSTACK_SGROW (&muscle_obstack, \
- quotearg_style (c_quoting_style, \
- Value)); \
- obstack_1grow (&muscle_obstack, 0); \
- muscle_insert (Key, obstack_finish (&muscle_obstack)); \
- } while(0)
+ do { \
+ obstack_escape (&muscle_obstack, \
+ quotearg_style (c_quoting_style, Value)); \
+ obstack_1grow (&muscle_obstack, 0); \
+ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
+ } while (0)
/* Append VALUE to the current value of KEY. If KEY did not already
exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously
set_quoting_flags (qo, QA_SPLIT_TRIGRAPHS);
for (i = 0; i < nsyms; i++)
{
- char *cp = quotearg_alloc (symbols[i]->tag, -1, qo);
- /* Width of the next token, including the two quotes, the
- comma and the space. */
- int width = strlen (cp) + 2;
-
- if (j + width > 75)
- {
- obstack_sgrow (&format_obstack, "\n ");
- j = 1;
- }
-
- if (i)
- obstack_1grow (&format_obstack, ' ');
- obstack_escape (&format_obstack, cp);
+ char *cp = quotearg_alloc (symbols[i]->tag, -1, qo);
+ /* Width of the next token, including the two quotes, the
+ comma and the space. */
+ int width = strlen (cp) + 2;
+
+ if (j + width > 75)
+ {
+ obstack_sgrow (&format_obstack, "\n ");
+ j = 1;
+ }
+
+ if (i)
+ obstack_1grow (&format_obstack, ' ');
- MUSCLE_OBSTACK_SGROW (&format_obstack, cp);
++ obstack_escape (&format_obstack, cp);
free (cp);
- obstack_1grow (&format_obstack, ',');
- j += width;
+ obstack_1grow (&format_obstack, ',');
+ j += width;
}
free (qo);
obstack_sgrow (&format_obstack, " ]b4_null[");
for (r = 0; r < nrules; ++r)
if (rules[r].action)
{
- fprintf (out, "b4_case(%d, [b4_syncline(%d, ", r + 1,
- rules[r].action_location.start.line);
- string_output (out, rules[r].action_location.start.file);
- fprintf (out, ")\n[ %s]])\n\n", rules[r].action);
+ fprintf (out, "b4_%scase(%d, [b4_syncline(%d, ",
+ rules[r].is_predicate ? "predicate_" : "",
+ r + 1, rules[r].action_location.start.line);
- escaped_output (out, rules[r].action_location.start.file);
++ string_output (out, rules[r].action_location.start.file);
+ fprintf (out, ")\n[ %s]])\n\n", rules[r].action);
}
fputs ("])\n\n", out);
}
{
grammar_start_symbol_set ($2, @2);
}
-| "%destructor" "{...}" generic_symlist
- {
- code_props code;
- code_props_symbol_action_init (&code, $2, @2);
- code_props_translate_code (&code);
- {
- symbol_list *list;
- for (list = $3; list; list = list->next)
- symbol_list_destructor_set (list, &code);
- symbol_list_free ($3);
- }
- }
-| "%printer" "{...}" generic_symlist
+| code_props_type "{...}" generic_symlist
{
- symbol_list *list;
- for (list = $3; list; list = list->next)
- symbol_list_code_props_set (list, $1, @2, $2);
- symbol_list_free ($3);
+ code_props code;
+ code_props_symbol_action_init (&code, $2, @2);
+ code_props_translate_code (&code);
+ {
+ symbol_list *list;
+ for (list = $3; list; list = list->next)
- symbol_list_printer_set (list, &code);
++ symbol_list_code_props_set (list, $1, &code);
+ symbol_list_free ($3);
+ }
}
| "%default-prec"
{
#define YY_USER_ACTION location_compute (loc, &loc->end, yytext, yyleng);
+ static char *fetch_type_name (char *cp, char const **type_name,
+ location dollar_loc);
+
static void handle_action_dollar (symbol_list *rule, char *cp,
- location dollar_loc);
+ location dollar_loc);
static void handle_action_at (symbol_list *rule, char *cp, location at_loc);
/* A string to be pushed to obstack after dollar/at has been handled. */
STRING_GROW;
BEGIN SC_LINE_COMMENT;
}
- warn_at (*loc, _("stray '%s'"), yytext);
+ [$@] {
++ complain_at (*loc, Wother, _("stray '%s'"), yytext);
+ obstack_escape (&obstack_for_string, yytext);
+ need_semicolon = true;
+ }
+ [\[\]] {
+ obstack_escape (&obstack_for_string, yytext);
+ need_semicolon = true;
+ }
}
<SC_RULE_ACTION>
}
- /*-----------------------------------------.
- | Escape M4 quoting characters in C code. |
- `-----------------------------------------*/
-
<*>
{
- \$ obstack_sgrow (&obstack_for_string, "$][");
- \@ obstack_sgrow (&obstack_for_string, "@@");
- \[ obstack_sgrow (&obstack_for_string, "@{");
- \] obstack_sgrow (&obstack_for_string, "@}");
- }
-
- /*-----------------------------------------------------.
- | By default, grow the string obstack with the input. |
- `-----------------------------------------------------*/
+ /* Escape M4 quoting characters in C code. */
+ [$@\[\]] obstack_escape (&obstack_for_string, yytext);
- <*>.|\n STRING_GROW;
+ /* By default, grow the string obstack with the input. */
+ .|\n STRING_GROW;
- /* End of processing. */
+ /* End of processing. */
- <*><<EOF>> {
- STRING_FINISH;
- return last_string;
- }
+ <<EOF>> STRING_FINISH; return last_string;
+ }
%%
int max_left_semantic_context = 0;
- ++cp;
+ /* If CP points to a typename (i.e., <.*?>), set TYPE_NAME to its
+ beginning (i.e., after the opening "<", and return the pointer
+ immediately after it. */
+
+ static
+ char *
+ fetch_type_name (char *cp, char const **type_name,
+ location dollar_loc)
+ {
+ if (*cp == '<')
+ {
+ *type_name = ++cp;
+ while (*cp != '>')
- 'text' is needed for error messages. */
++ ++cp;
+
+ /* The '>' symbol will be later replaced by '\0'. Original
- complain_at (dollar_loc, _("explicit type given in untyped grammar"));
++ 'text' is needed for error messages. */
+ ++cp;
+ if (untyped_var_seen)
++ complain_at (dollar_loc, complaint,
++ _("explicit type given in untyped grammar"));
+ tag_seen = true;
+ }
+ return cp;
+ }
+
/*------------------------------------------------------------------.
| TEXT is pointing to a wannabee semantic value (i.e., a '$'). |
| |
}
/* Get the type name if explicit. */
- if (*cp == '<')
- {
- type_name = ++cp;
- while (*cp != '>')
- ++cp;
-
- /* The '>' symbol will be later replaced by '\0'. Original
- 'text' is needed for error messages. */
- gt_ptr = cp;
- ++cp;
- if (untyped_var_seen)
- complain_at (dollar_loc, complaint,
- _("explicit type given in untyped grammar"));
- tag_seen = true;
- }
+ cp = fetch_type_name (cp, &type_name, dollar_loc);
n = parse_ref (cp, effective_rule, effective_rule_length,
- rule->midrule_parent_rhs_index, text, dollar_loc, '$');
+ rule->midrule_parent_rhs_index, text, dollar_loc, '$');
- if (gt_ptr)
- *gt_ptr = '\0';
+ /* End type_name. */
+ if (type_name)
+ cp[-1] = '\0';
switch (n)
{
if (!type_name)
{
if (union_seen | tag_seen)
- complain_at (dollar_loc, _("$%s of %s has no declared type"),
- cp, quote (effective_rule->content.sym->tag));
+ complain_at (dollar_loc, complaint,
+ _("$%s of %s has no declared type"), cp,
+ quote (effective_rule->content.sym->tag));
else
untyped_var_seen = true;
- type_name = "";
}
- obstack_fgrow3 (&obstack_for_string,
- "]b4_rhs_value(%d, %d, [%s])[",
- effective_rule_length, n, type_name);
+ obstack_fgrow2 (&obstack_for_string,
- "]b4_rhs_value(%d, %d, ", effective_rule_length, n);
++ "]b4_rhs_value(%d, %d, ", effective_rule_length, n);
+ obstack_quote (&obstack_for_string, type_name);
+ obstack_sgrow (&obstack_for_string, ")[");
if (n > 0)
- symbol_list_n_get (effective_rule, n)->action_props.is_value_used =
- true;
+ symbol_list_n_get (effective_rule, n)->action_props.is_value_used =
+ true;
break;
}
}
}
/* This pattern must not match more than the previous @ patterns. */
-@[^@{}`(\n]* fail_for_invalid_at (yytext);
-\n out_lineno++; ECHO;
-[^@\n]+ ECHO;
+@[^@{}`(\n]* fail_for_invalid_at (yytext);
+\n out_lineno++; ECHO;
+[^@\n]+ ECHO;
- <INITIAL><<EOF>> {
+ <<EOF>> {
if (outname)
{
free (outname);
}
}
- @.? { fail_for_invalid_at (yytext); }
+ @.? fail_for_invalid_at (yytext);
}
- <SC_AT_DIRECTIVE_SKIP_WS>{
- [ \t\r\n]
+ <SC_AT_DIRECTIVE_SKIP_WS>
+ {
+ [ \t\r\n] continue;
- . { yyless (0); BEGIN SC_AT_DIRECTIVE_ARGS; }
+ . { yyless (0); BEGIN SC_AT_DIRECTIVE_ARGS; }
}
- <SC_AT_DIRECTIVE_ARGS,SC_AT_DIRECTIVE_SKIP_WS>{
+ <SC_AT_DIRECTIVE_ARGS,SC_AT_DIRECTIVE_SKIP_WS>
+ {
<<EOF>> {
- fatal (_("unclosed %s directive in skeleton"), at_directive_argv[0]);
+ complain (fatal, _("unclosed %s directive in skeleton"),
+ at_directive_argv[0]);
}
}
}
void
-symbol_list_destructor_set (symbol_list *node, code_props const *destructor)
-{
- switch (node->content_type)
- {
- case SYMLIST_SYMBOL:
- symbol_destructor_set (node->content.sym, destructor);
- break;
- case SYMLIST_TYPE:
- semantic_type_destructor_set (
- semantic_type_get (node->content.type_name), destructor);
- break;
- case SYMLIST_DEFAULT_TAGGED:
- default_tagged_destructor_set (destructor);
- break;
- case SYMLIST_DEFAULT_TAGLESS:
- default_tagless_destructor_set (destructor);
- break;
- }
-}
-
-void
-symbol_list_printer_set (symbol_list *node, code_props const *printer)
+symbol_list_code_props_set (symbol_list *node, code_props_type kind,
- location loc, char const *code)
++ code_props const *cprops)
{
- code_props cprops;
- code_props_symbol_action_init (&cprops, code, loc);
- code_props_translate_code (&cprops);
switch (node->content_type)
{
case SYMLIST_SYMBOL:
- symbol_code_props_set (node->content.sym, kind, &cprops);
- symbol_printer_set (node->content.sym, printer);
++ symbol_code_props_set (node->content.sym, kind, cprops);
+ if (node->content.sym->status == undeclared)
+ node->content.sym->status = used;
break;
case SYMLIST_TYPE:
- semantic_type_printer_set (
- semantic_type_get (node->content.type_name), printer);
- break;
- case SYMLIST_DEFAULT_TAGGED:
- default_tagged_printer_set (printer);
- break;
- case SYMLIST_DEFAULT_TAGLESS:
- default_tagless_printer_set (printer);
+ semantic_type_code_props_set
+ (semantic_type_get (node->content.sem_type->tag,
+ &node->content.sem_type->location),
- kind, &cprops);
++ kind, cprops);
+ if (node->content.sem_type->status == undeclared)
+ node->content.sem_type->status = used;
break;
}
}
/* Check whether the node is a border element of a rule. */
bool symbol_list_null (symbol_list *node);
- /** Set the \c \%destructor or \c \%printer for \c node as \c code at
- \c loc. */
-/** Set the \c \%destructor for \c node as \c code at \c loc. */
-void symbol_list_destructor_set (symbol_list *node,
- code_props const *destructor);
-
-/** Set the \c \%printer for \c node as \c code at \c loc. */
-void symbol_list_printer_set (symbol_list *node,
- code_props const *printer);
++/** Set the \c \%destructor or \c \%printer for \c node as \c cprops. */
+void symbol_list_code_props_set (symbol_list *node, code_props_type kind,
- location loc, char const *code);
++ code_props const *cprops);
#endif /* !SYMLIST_H_ */
/** Its \c \%type's location. */
location type_location;
- /** Any \c \%destructor declared specifically for this symbol.
-
- Access this field only through <tt>symbol</tt>'s interface
- functions. For example, if <tt>symbol::destructor = NULL</tt>, a
- default \c \%destructor or a per-type \c \%destructor might be
- appropriate, and \c symbol_destructor_get will compute the
- correct one. */
- code_props destructor;
-
- /** Any \c \%printer declared specifically for this symbol.
+ /** Any \c \%destructor (resp. \%printer) declared specificially for this
+ symbol.
- Access this field only through <tt>symbol</tt>'s interface functions.
- \sa symbol::destructor */
- code_props printer;
+ Access this field only through <tt>symbol</tt>'s interface functions. For
- Example, if <tt>symbol::destructor = NULL</tt> (resp. <tt>symbol::printer
++ example, if <tt>symbol::destructor = NULL</tt> (resp. <tt>symbol::printer
+ = NULL</tt>), a default \c \%destructor (resp. \%printer) or a per-type
- \c symbol_destructor_printer_get will compute the corect one. */
++ \c symbol_destructor_printer_get will compute the correct one. */
+ code_props props[CODE_PROPS_SIZE];
symbol_number number;
location prec_location;
| Obstacks. |
`-----------*/
-# define obstack_chunk_alloc xmalloc
-# define obstack_chunk_free free
-# include <obstack.h>
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+#include <obstack.h>
-# define obstack_sgrow(Obs, Str) \
+#define obstack_sgrow(Obs, Str) \
obstack_grow (Obs, Str, strlen (Str))
-# define obstack_fgrow1(Obs, Format, Arg1) \
+#define obstack_fgrow1(Obs, Format, Arg1) \
- do { \
- char buf[4096]; \
- sprintf (buf, Format, Arg1); \
- obstack_grow (Obs, buf, strlen (buf)); \
- } while (0)
+ do { \
+ char buf[4096]; \
+ sprintf (buf, Format, Arg1); \
+ obstack_grow (Obs, buf, strlen (buf)); \
+ } while (0)
-# define obstack_fgrow2(Obs, Format, Arg1, Arg2) \
- do { \
- char buf[4096]; \
- sprintf (buf, Format, Arg1, Arg2); \
- obstack_grow (Obs, buf, strlen (buf)); \
+#define obstack_fgrow2(Obs, Format, Arg1, Arg2) \
- do { \
- char buf[4096]; \
- sprintf (buf, Format, Arg1, Arg2); \
- obstack_grow (Obs, buf, strlen (buf)); \
- } while (0)
++ do { \
++ char buf[4096]; \
++ sprintf (buf, Format, Arg1, Arg2); \
++ obstack_grow (Obs, buf, strlen (buf)); \
+ } while (0)
-# define obstack_fgrow3(Obs, Format, Arg1, Arg2, Arg3) \
+#define obstack_fgrow3(Obs, Format, Arg1, Arg2, Arg3) \
- do { \
- char buf[4096]; \
- sprintf (buf, Format, Arg1, Arg2, Arg3); \
- obstack_grow (Obs, buf, strlen (buf)); \
- } while (0)
+ do { \
+ char buf[4096]; \
+ sprintf (buf, Format, Arg1, Arg2, Arg3); \
+ obstack_grow (Obs, buf, strlen (buf)); \
+ } while (0)
-# define obstack_fgrow4(Obs, Format, Arg1, Arg2, Arg3, Arg4) \
+#define obstack_fgrow4(Obs, Format, Arg1, Arg2, Arg3, Arg4) \
- do { \
- char buf[4096]; \
- sprintf (buf, Format, Arg1, Arg2, Arg3, Arg4); \
- obstack_grow (Obs, buf, strlen (buf)); \
- } while (0)
+ do { \
+ char buf[4096]; \
+ sprintf (buf, Format, Arg1, Arg2, Arg3, Arg4); \
+ obstack_grow (Obs, buf, strlen (buf)); \
+ } while (0)
+
+
+ /* Output Str escaped for our postprocessing (i.e., escape M4 special
+ characters).
+
+ For instance "[foo]" -> "@{foo@}", "$$" -> "$][$][". */
+
+ # define obstack_escape(Obs, Str) \
+ do { \
- char const *p; \
- for (p = Str; *p; p++) \
- switch (*p) \
++ char const *p__; \
++ for (p__ = Str; *p__; p__++) \
++ switch (*p__) \
+ { \
+ case '$': obstack_sgrow (Obs, "$]["); break; \
+ case '@': obstack_sgrow (Obs, "@@" ); break; \
+ case '[': obstack_sgrow (Obs, "@{" ); break; \
+ case ']': obstack_sgrow (Obs, "@}" ); break; \
- default: obstack_1grow (Obs, *p ); break; \
++ default: obstack_1grow (Obs, *p__ ); break; \
+ } \
+ } while (0)
+
+
+ /* Output Str both quoted for M4 (i.e., embed in [[...]]), and escaped
+ for our postprocessing (i.e., escape M4 special characters). If
+ Str is empty (or NULL), output "[]" instead of "[[]]" as it make M4
+ programming easier (m4_ifval can be used).
+
+ For instance "[foo]" -> "[[@{foo@}]]", "$$" -> "[[$][$][]]". */
+
+ # define obstack_quote(Obs, Str) \
+ do { \
+ char const* obstack_quote_p = Str; \
+ if (obstack_quote_p && obstack_quote_p[0]) \
+ { \
+ obstack_sgrow (Obs, "[["); \
+ obstack_escape (Obs, obstack_quote_p); \
+ obstack_sgrow (Obs, "]]"); \
+ } \
+ else \
+ obstack_sgrow (Obs, "[]"); \
+ } while (0)
+
+
| Extensions to use for the output files. |
`-----------------------------------------*/
-# ifndef OUTPUT_EXT
-# define OUTPUT_EXT ".output"
-# endif
+#ifndef OUTPUT_EXT
+# define OUTPUT_EXT ".output"
+#endif
-# ifndef TAB_EXT
-# define TAB_EXT ".tab"
-# endif
+#ifndef TAB_EXT
+# define TAB_EXT ".tab"
+#endif
- #ifndef DEFAULT_TMPDIR
- # define DEFAULT_TMPDIR "/tmp"
- #endif
-
/*---------------------.
m4_popdef([AT_TEST])
AT_CLEANUP
-[[%token TOK
+
+
+ ## -------------- ##
+ ## Stray $ or @. ##
+ ## -------------- ##
+
+ AT_SETUP([[Stray $ or @]])
+
+ # Give %printer and %destructor "<*> exp TOK" instead of "<*>" to
+ # check that the warnings are reported once, not three times.
+
+ AT_DATA_GRAMMAR([[input.y]],
-[[input.y:10.19: warning: stray '$'
-input.y:10.23: warning: stray '@'
-input.y:11.19: warning: stray '$'
-input.y:11.23: warning: stray '@'
-input.y:12.19: warning: stray '$'
-input.y:12.23: warning: stray '@'
-input.y:14.19: warning: stray '$'
-input.y:14.23: warning: stray '@'
++[[%type <TYPE> exp
++%token <TYPE> TOK TOK2
+ %destructor { $%; @%; } <*> exp TOK;
+ %initial-action { $%; @%; };
+ %printer { $%; @%; } <*> exp TOK;
+ %%
+ exp: TOK { $%; @%; $$ = $1; };
+ ]])
+
+ AT_BISON_CHECK([[input.y]], 0, [],
- a a[last]
++[[input.y:11.19: warning: stray '$' [-Wother]
++input.y:11.23: warning: stray '@' [-Wother]
++input.y:12.19: warning: stray '$' [-Wother]
++input.y:12.23: warning: stray '@' [-Wother]
++input.y:13.19: warning: stray '$' [-Wother]
++input.y:13.23: warning: stray '@' [-Wother]
++input.y:15.19: warning: stray '$' [-Wother]
++input.y:15.23: warning: stray '@' [-Wother]
+ ]])
+
+ AT_CLEANUP
+
+
+
+ ## ---------------- ##
+ ## Code injection. ##
+ ## ---------------- ##
+
+
+ AT_SETUP([[Code injection]])
+
+ m4_pattern_allow([^m4_errprintn$])
+
+ # AT_TEST([MACRO])
+ # ----------------
+ # Try to have MACRO be run by bison.
+ m4_pushdef([AT_TEST],
+ [AT_DATA([[input.y]],
+ [[%type <$1(DEAD %type)> exp
+ %token <$1(DEAD %token)> a
++%token b
+ %initial-action
+ {
+ $$;
+ $<$1(DEAD %initial-action)>$
+ };
+ %printer
+ {
+ $$
+ $<$1(DEAD %printer)>$
+ } <> <*>;
+ %lex-param
+ {
+ $1(DEAD %lex-param)
+ };
+ %parse-param
+ {
+ $1(DEAD %parse-param)
+ };
+ %%
+ exp:
- $<$1(DEAD action 3)>last
++ a a[name] b
+ {
+ $$;
+ $][1;
+ $<$1(DEAD action 1)>$
+ $<$1(DEAD action 2)>1
++ $<$1(DEAD action 3)>name
+ $<$1(DEAD action 4)>0
+ ;
+ };
+ ]])
+
+ # FIXME: Provide a means to iterate over all the skeletons.
+ AT_BISON_CHECK([[-d input.y]])
+ AT_BISON_CHECK([[-d -S glr.c input.y]])
+ AT_BISON_CHECK([[-d -S lalr1.cc input.y]])
+ AT_BISON_CHECK([[-d -S glr.cc input.y]])
+ AT_BISON_CHECK([[ -S lalr1.java input.y]])
+ ])
+
+ AT_TEST([m4_errprintn])
+ AT_TEST([@:>@m4_errprintn])
+
+ m4_popdef([AT_TEST])
+
+ AT_CLEANUP