]> git.saurik.com Git - bison.git/commitdiff
Merge branch 'maint'
authorAkim Demaille <akim@lrde.epita.fr>
Tue, 31 Jul 2012 09:50:18 +0000 (11:50 +0200)
committerAkim Demaille <akim@lrde.epita.fr>
Tue, 31 Jul 2012 10:03:55 +0000 (12:03 +0200)
* maint:
  use obstack_printf
  scanner: restore a missing start condition
  gnulib: update
  maint: post-release administrivia
  version 2.6.1
  gnulib: update
  maint: fix some syntax-check issues
  tests: do not depend on __cplusplus to decide for C++ or C output

Conflicts:
NEWS
bootstrap.conf
cfg.mk
lib/.gitignore

14 files changed:
1  2 
NEWS
bootstrap.conf
cfg.mk
lib/.gitignore
m4/.gitignore
src/conflicts.c
src/muscle-tab.c
src/muscle-tab.h
src/output.c
src/print_graph.c
src/scan-code.l
src/scan-skel.l
src/system.h
tests/actions.at

diff --combined NEWS
index fa1b948f57e090eef5e955ffc0a13cac480ff89f,f940d8edd7763b666116f927b4123a4cd2af1ed9..bd47608b551782d521d8140b3ff3b89b1588846d
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -2,145 -2,9 +2,148 @@@ GNU Bison NEW
  
  * 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
 +
 +  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++ skeletons improvements
 +
 +*** parser header (%defines) is no longer mandatory (lalr1.cc)
 +
 +  In which case, if needed, the support classes are defined in the generated
 +  parser, instead of additional files (location.hh, position.hh and
 +  stack.hh).
 +
 +*** locations are no longer mandatory (lalr1.cc, glr.cc)
 +
 +  Both lalr1.cc and glr.cc no longer require %location.
 +
 +*** syntax_error exception (lalr1.cc)
 +
 +  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 ?.? (????-??-??) [?]
 +
+ * Noteworthy changes in release 2.6.1 (2012-07-30) [stable]
   Bison no longer executes user-specified M4 code when processing a grammar.
  
  ** Future Changes
  
  * Noteworthy changes in release 2.6 (2012-07-19) [stable]
  
 -** Future Changes
 +** Future changes:
  
    The next major release of Bison will drop support for the following
    deprecated features.  Please report disagreements to bug-bison@gnu.org.
@@@ -1980,8 -1844,7 +1983,8 @@@ along with this program.  If not, see <
   LocalWords:  namespaces strerror const autoconfiguration Dconst Autoconf's FDL
   LocalWords:  Automake TMPDIR LESSEQ ylwrap endif yydebug YYTOKEN YYLSP ival hh
   LocalWords:  extern YYTOKENTYPE TOKENTYPE yytokentype tokentype STYPE lval pdf
 - LocalWords:  lang yyoutput dvi html ps POSIX lvalp llocp
 + LocalWords:  lang yyoutput dvi html ps POSIX lvalp llocp Wother nterm arg init
 + LocalWords:  TOK
  
  Local Variables:
  mode: outline
diff --combined bootstrap.conf
index 486268d715d15edc5e57e10c3e6d2cfd9baa5225,165d5e7d84675cbae6edc6dd123b2ba74f8ed596..e90cf12d4d0e01da3e784bf38194f4528f5701b8
@@@ -23,19 -23,18 +23,22 @@@ gnulib_modules=
    error extensions fdl fopen-safer getopt-gnu
    gettext git-version-gen gitlog-to-changelog
    gpl-3.0 hash inttypes isnan javacomp-script
 -  javaexec-script ldexpl malloc-gnu mbschr mbsrchr
 +  javaexec-script ldexpl malloc-gnu
-   mbswidth obstack perror progname
+   mbswidth
+   obstack
+   obstack-printf
+   perror progname
    quote quotearg
    readme-release
    realloc-posix
    spawn-pipe stdbool stpcpy strdup-posix strerror strtoul strverscmp
    unistd unistd-safer unlocked-io update-copyright unsetenv verify
    warnings
 -  xalloc xalloc-die xmemdup0 xstrndup
 +  xalloc
 +  xalloc-die
 +  xconcat-filename
 +  xmemdup0
 +  xstrndup
  
    fprintf-posix printf-posix snprintf-posix sprintf-posix
    vsnprintf-posix vsprintf-posix
@@@ -45,9 -44,9 +48,9 @@@
  XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\
   --from-code=UTF-8\\\
   --flag=asprintf:2:c-format\\\
 - --flag=complain:1:c-format --flag=complain_at:2:c-format\\\
 - --flag=fatal:1:c-format --flag=fatal_at:2:c-format\\\
 - --flag=warn:1:c-format  --flag=warn_at:2:c-format\\\
 + --flag=complain:2:c-format\\\
 + --flag=complain_at:3:c-format\\\
 + --flag=complain_at_indent:4:c-format\\\
   --flag=unexpected_end:2:c-format\\\
  '
  XGETTEXT_OPTIONS_RUNTIME=$XGETTEXT_OPTIONS'\\\
@@@ -75,9 -74,6 +78,9 @@@ gnulib_tool_option_extras='--symlink --
  
  bootstrap_post_import_hook()
  {
 +  # Massage lib/gnulib.mk before using it later in the bootstrapping process.
 +  etc/prefix-gnulib-mk --lib-name=$gnulib_name lib/$gnulib_mk
 +
    # Ensure that ChangeLog exists, for automake.
    test -f ChangeLog || touch ChangeLog
  }
diff --combined cfg.mk
index f1caf313e85f360c41d0ccfdfe874746dcc7a31c,53855aefc78e01481201ac5bdf9fd04044d14e32..af1e09e8d94cedef4c9ff5a76fd2766ba6d2e20b
--- 1/cfg.mk
--- 2/cfg.mk
+++ b/cfg.mk
@@@ -36,9 -36,15 +36,9 @@@ url_dir_list = 
    ftp://$(gnu_rel_host)/gnu/bison
  
  # Tests not to run as part of "make distcheck".
 -# Exclude changelog-check here so that there's less churn in ChangeLog
 -# files -- otherwise, you'd need to have the upcoming version number
 -# at the top of the file for each `make distcheck' run.
 -local-checks-to-skip = \
 -  changelog-check \
 +local-checks-to-skip =                        \
    sc_immutable_NEWS                   \
 -  sc_prohibit_always_true_header_tests        \
 -  sc_prohibit_atoi_atof                       \
 -  sc_prohibit_strcmp
 +  sc_prohibit_atoi_atof
  
  # The local directory containing the checked-out copy of gnulib used in
  # this release.  Used solely to get a date for the "announcement" target.
@@@ -59,14 -65,16 +59,16 @@@ exclude = 
  $(call exclude,                                                               \
    bindtextdomain=^lib/main.c$$                                                \
    program_name=^lib/main.c$$                                          \
-   prohibit_always-defined_macros=^data/yacc.c|^djgpp/                 \
+   prohibit_always-defined_macros=^data/yacc.c$$|^djgpp/                       \
    prohibit_always-defined_macros+=?|^lib/timevar.c$$                  \
    prohibit_always-defined_macros+=?|^src/(parse-gram.c|system.h)$$    \
    prohibit_always-defined_macros+=?|^tests/regression.at$$            \
    prohibit_defined_have_decl_tests=?|^lib/timevar.c$$                 \
 -  prohibit_empty_lines_at_EOF=^src/parse-gram.[ch]$$                  \
 +  prohibit_empty_lines_at_EOF=^src/parse-gram.h$$                     \
+   prohibit_magic_number_exit=^doc/bison.texi$$                                \
+   prohibit_magic_number_exit+=?|^tests/(conflicts|regression).at$$    \
 +  prohibit_strcmp=^doc/bison\.texi$$                                  \
    require_config_h_first=^(lib/yyerror|data/(glr|yacc))\.c$$          \
    space_tab=^tests/(input|c\+\+)\.at$$                                        \
 -  trailing_blank=^src/parse-gram.[ch]$$                                       \
    unmarked_diagnostics=^(djgpp/|doc/bison.texi$$)                     \
  )
diff --combined lib/.gitignore
index 8e0e20968eb2bf600463e1d4d7bfbff1ff7c77a2,964d7f4525e629602cd58fdb828b265652bba4e3..a448e841ed2b304f9343fd3799e7db08d1f95e11
@@@ -35,6 -35,6 +35,8 @@@
  /close.c
  /closeout.c
  /closeout.h
++/concat-filename.c
++/concat-filename.h
  /config.charset
  /config.h
  /config.in.h
@@@ -62,6 -62,6 +64,7 @@@
  /fd-hook.h
  /fd-safer-flag.c
  /fd-safer.c
++/filename.h
  /float+.h
  /float.c
  /float.h
  /mbchar.c
  /mbchar.h
  /mbrtowc.c
 -/mbschr.c
  /mbsinit.c
 -/mbsrchr.c
  /mbswidth.c
  /mbswidth.h
  /mbuiter.h
  /nonblocking.h
  /obstack.c
  /obstack.h
++/obstack_printf.c
  /open.c
  /pathmax.h
  /perror.c
  /sys_socket.in.h
  /sys_stat.h
  /sys_stat.in.h
++/sys_types.in.h
  /sys_wait.h
  /sys_wait.in.h
  /sysexits.in.h
  /xalloc-die.c
  /xalloc-oversized.h
  /xalloc.h
++/xconcat-filename.c
  /xmalloc.c
++/xmemdup0.c
++/xmemdup0.h
  /xsize.h
  /xstrndup.c
  /xstrndup.h
--/xmemdup0.c
--/xmemdup0.h
--/sys_types.in.h
- /concat-filename.c
- /concat-filename.h
- /filename.h
- /xconcat-filename.c
 -/obstack_printf.c
diff --combined m4/.gitignore
index 875400a9839458282f1096ab5648644fb3437050,797ed6df9ceb6e4498ba6c2097b3e595ea1cc40b..c6a84ce83eaf0615dd72c061816e858300f897fc
@@@ -51,7 -51,6 +51,7 @@@
  /inline.m4
  /intdiv0.m4
  /intl.m4
 +/intl.m4~
  /intldir.m4
  /intlmacosx.m4
  /intmax.m4
  /perror.m4
  /pipe2.m4
  /po.m4
 +/po.m4~
  /posix_spawn.m4
  /printf-frexp.m4
  /printf-frexpl.m4
  /xalloc.m4
  /xsize.m4
  /xstrndup.m4
+ /obstack-printf.m4
diff --combined src/conflicts.c
index ccd50ebf78d72b01c40fbcdd2ac3d708af4ef079,ba0b6ed3fe80af1d657060d76670c5ecd6f16340..dad6568391e62e318c72117ee338b5c88a3d163f
@@@ -1,7 -1,7 +1,7 @@@
  /* Find and resolve or report lookahead conflicts for bison,
  
 -   Copyright (C) 1984, 1989, 1992, 2000-2007, 2009-2012 Free Software
 -   Foundation, Inc.
 +   Copyright (C) 1984, 1989, 1992, 2000-2012 Free Software Foundation,
 +   Inc.
  
     This file is part of Bison, the GNU Compiler Compiler.
  
@@@ -64,75 -64,75 +64,75 @@@ enum conflict_resolutio
  
  static inline void
  log_resolution (rule *r, symbol_number token,
 -              enum conflict_resolution resolution)
 +                enum conflict_resolution resolution)
  {
    if (report_flag & report_solved_conflicts)
      {
        /* The description of the resolution. */
        switch (resolution)
 -      {
 -      case shift_resolution:
 -      case right_resolution:
 -        obstack_printf (&solved_conflicts_obstack,
 -                        _("    Conflict between rule %d and token %s"
 -                          " resolved as shift"),
 -                        r->number,
 -                        symbols[token]->tag);
 -        break;
 -
 -      case reduce_resolution:
 -      case left_resolution:
 -        obstack_printf (&solved_conflicts_obstack,
 -                        _("    Conflict between rule %d and token %s"
 -                          " resolved as reduce"),
 -                        r->number,
 -                        symbols[token]->tag);
 -        break;
 -
 -      case nonassoc_resolution:
 -        obstack_printf (&solved_conflicts_obstack,
 -                        _("    Conflict between rule %d and token %s"
 -                          " resolved as an error"),
 -                        r->number,
 -                        symbols[token]->tag);
 -        break;
 -      }
 +        {
 +        case shift_resolution:
 +        case right_resolution:
-           obstack_fgrow2 (&solved_conflicts_obstack,
++          obstack_printf (&solved_conflicts_obstack,
 +                          _("    Conflict between rule %d and token %s"
 +                            " resolved as shift"),
 +                          r->number,
 +                          symbols[token]->tag);
 +          break;
 +
 +        case reduce_resolution:
 +        case left_resolution:
-           obstack_fgrow2 (&solved_conflicts_obstack,
++          obstack_printf (&solved_conflicts_obstack,
 +                          _("    Conflict between rule %d and token %s"
 +                            " resolved as reduce"),
 +                          r->number,
 +                          symbols[token]->tag);
 +          break;
 +
 +        case nonassoc_resolution:
-           obstack_fgrow2 (&solved_conflicts_obstack,
++          obstack_printf (&solved_conflicts_obstack,
 +                          _("    Conflict between rule %d and token %s"
 +                            " resolved as an error"),
 +                          r->number,
 +                          symbols[token]->tag);
 +          break;
 +        }
  
        /* The reason. */
        switch (resolution)
 -      {
 -      case shift_resolution:
 -        obstack_printf (&solved_conflicts_obstack,
 -                        " (%s < %s)",
 -                        r->prec->tag,
 -                        symbols[token]->tag);
 -        break;
 -
 -      case reduce_resolution:
 -        obstack_printf (&solved_conflicts_obstack,
 -                        " (%s < %s)",
 -                        symbols[token]->tag,
 -                        r->prec->tag);
 -        break;
 -
 -      case left_resolution:
 -        obstack_printf (&solved_conflicts_obstack,
 -                        " (%%left %s)",
 -                        symbols[token]->tag);
 -        break;
 -
 -      case right_resolution:
 -        obstack_printf (&solved_conflicts_obstack,
 -                        " (%%right %s)",
 -                        symbols[token]->tag);
 -        break;
 -
 -      case nonassoc_resolution:
 -        obstack_printf (&solved_conflicts_obstack,
 -                        " (%%nonassoc %s)",
 -                        symbols[token]->tag);
 -        break;
 -      }
 +        {
 +        case shift_resolution:
-           obstack_fgrow2 (&solved_conflicts_obstack,
++          obstack_printf (&solved_conflicts_obstack,
 +                          " (%s < %s)",
 +                          r->prec->tag,
 +                          symbols[token]->tag);
 +          break;
 +
 +        case reduce_resolution:
-           obstack_fgrow2 (&solved_conflicts_obstack,
++          obstack_printf (&solved_conflicts_obstack,
 +                          " (%s < %s)",
 +                          symbols[token]->tag,
 +                          r->prec->tag);
 +          break;
 +
 +        case left_resolution:
-           obstack_fgrow1 (&solved_conflicts_obstack,
++          obstack_printf (&solved_conflicts_obstack,
 +                          " (%%left %s)",
 +                          symbols[token]->tag);
 +          break;
 +
 +        case right_resolution:
-           obstack_fgrow1 (&solved_conflicts_obstack,
++          obstack_printf (&solved_conflicts_obstack,
 +                          " (%%right %s)",
 +                          symbols[token]->tag);
 +          break;
 +
 +        case nonassoc_resolution:
-           obstack_fgrow1 (&solved_conflicts_obstack,
++          obstack_printf (&solved_conflicts_obstack,
 +                          " (%%nonassoc %s)",
 +                          symbols[token]->tag);
 +          break;
 +        }
  
        obstack_sgrow (&solved_conflicts_obstack, ".\n");
      }
          {
          case shift_resolution:
          case right_resolution:
-           obstack_fgrow2 (&solved_conflicts_xml_obstack,
+           obstack_printf (&solved_conflicts_xml_obstack,
                            "        <resolution rule=\"%d\" symbol=\"%s\""
                            " type=\"shift\">",
                            r->number,
  
          case reduce_resolution:
          case left_resolution:
-           obstack_fgrow2 (&solved_conflicts_xml_obstack,
+           obstack_printf (&solved_conflicts_xml_obstack,
                            "        <resolution rule=\"%d\" symbol=\"%s\""
                            " type=\"reduce\">",
                            r->number,
            break;
  
          case nonassoc_resolution:
-           obstack_fgrow2 (&solved_conflicts_xml_obstack,
+           obstack_printf (&solved_conflicts_xml_obstack,
                            "        <resolution rule=\"%d\" symbol=\"%s\""
                            " type=\"error\">",
                            r->number,
        switch (resolution)
          {
          case shift_resolution:
-           obstack_fgrow2 (&solved_conflicts_xml_obstack,
+           obstack_printf (&solved_conflicts_xml_obstack,
                            "%s &lt; %s",
                            xml_escape_n (0, r->prec->tag),
                            xml_escape_n (1, symbols[token]->tag));
            break;
  
          case reduce_resolution:
-           obstack_fgrow2 (&solved_conflicts_xml_obstack,
+           obstack_printf (&solved_conflicts_xml_obstack,
                            "%s &lt; %s",
                            xml_escape_n (0, symbols[token]->tag),
                            xml_escape_n (1, r->prec->tag));
            break;
  
          case left_resolution:
-           obstack_fgrow1 (&solved_conflicts_xml_obstack,
+           obstack_printf (&solved_conflicts_xml_obstack,
                            "%%left %s",
                            xml_escape (symbols[token]->tag));
            break;
  
          case right_resolution:
-           obstack_fgrow1 (&solved_conflicts_xml_obstack,
+           obstack_printf (&solved_conflicts_xml_obstack,
                            "%%right %s",
                            xml_escape (symbols[token]->tag));
            break;
  
          case nonassoc_resolution:
-           obstack_fgrow1 (&solved_conflicts_xml_obstack,
+           obstack_printf (&solved_conflicts_xml_obstack,
                            "%%nonassoc %s",
                            xml_escape (symbols[token]->tag));
        break;
@@@ -226,7 -226,7 +226,7 @@@ flush_shift (state *s, int token
    bitset_reset (lookahead_set, token);
    for (i = 0; i < trans->num; i++)
      if (!TRANSITION_IS_DISABLED (trans, i)
 -      && TRANSITION_SYMBOL (trans, i) == token)
 +        && TRANSITION_SYMBOL (trans, i) == token)
        TRANSITION_DISABLE (trans, i);
  }
  
@@@ -268,56 -268,51 +268,56 @@@ resolve_sr_conflict (state *s, int rule
  
    for (i = 0; i < ntokens; i++)
      if (bitset_test (lookahead_tokens, i)
 -      && bitset_test (lookahead_set, i)
 -      && symbols[i]->prec)
 +        && bitset_test (lookahead_set, i)
 +        && symbols[i]->prec)
        {
 -      /* Shift-reduce conflict occurs for token number i
 -         and it has a precedence.
 -         The precedence of shifting is that of token i.  */
 -      if (symbols[i]->prec < redprec)
 -        {
 -          log_resolution (redrule, i, reduce_resolution);
 -          flush_shift (s, i);
 -        }
 -      else if (symbols[i]->prec > redprec)
 -        {
 -          log_resolution (redrule, i, shift_resolution);
 -          flush_reduce (lookahead_tokens, i);
 -        }
 -      else
 -        /* Matching precedence levels.
 -           For left association, keep only the reduction.
 -           For right association, keep only the shift.
 -           For nonassociation, keep neither.  */
 -
 -        switch (symbols[i]->assoc)
 -          {
 -          default:
 -            abort ();
 -
 -          case right_assoc:
 -            log_resolution (redrule, i, right_resolution);
 -            flush_reduce (lookahead_tokens, i);
 -            break;
 -
 -          case left_assoc:
 -            log_resolution (redrule, i, left_resolution);
 -            flush_shift (s, i);
 -            break;
 -
 -          case non_assoc:
 -            log_resolution (redrule, i, nonassoc_resolution);
 -            flush_shift (s, i);
 -            flush_reduce (lookahead_tokens, i);
 -            /* Record an explicit error for this token.  */
 -            errors[(*nerrs)++] = symbols[i];
 -            break;
 -          }
 +        /* Shift-reduce conflict occurs for token number i
 +           and it has a precedence.
 +           The precedence of shifting is that of token i.  */
 +        if (symbols[i]->prec < redprec)
 +          {
 +            log_resolution (redrule, i, reduce_resolution);
 +            flush_shift (s, i);
 +          }
 +        else if (symbols[i]->prec > redprec)
 +          {
 +            log_resolution (redrule, i, shift_resolution);
 +            flush_reduce (lookahead_tokens, i);
 +          }
 +        else
 +          /* Matching precedence levels.
 +             For non-defined associativity, keep both: unexpected
 +             associativity conflict.
 +             For left associativity, keep only the reduction.
 +             For right associativity, keep only the shift.
 +             For nonassociativity, keep neither.  */
 +
 +          switch (symbols[i]->assoc)
 +            {
 +            case undef_assoc:
 +              abort ();
 +
 +            case precedence_assoc:
 +              break;
 +
 +            case right_assoc:
 +              log_resolution (redrule, i, right_resolution);
 +              flush_reduce (lookahead_tokens, i);
 +              break;
 +
 +            case left_assoc:
 +              log_resolution (redrule, i, left_resolution);
 +              flush_shift (s, i);
 +              break;
 +
 +            case non_assoc:
 +              log_resolution (redrule, i, nonassoc_resolution);
 +              flush_shift (s, i);
 +              flush_reduce (lookahead_tokens, i);
 +              /* Record an explicit error for this token.  */
 +              errors[(*nerrs)++] = symbols[i];
 +              break;
 +            }
        }
  }
  
@@@ -350,7 -345,7 +350,7 @@@ set_conflicts (state *s, symbol **error
       precedence.  */
    for (i = 0; i < reds->num; ++i)
      if (reds->rules[i]->prec && reds->rules[i]->prec->prec
 -      && !bitset_disjoint_p (reds->lookahead_tokens[i], lookahead_set))
 +        && !bitset_disjoint_p (reds->lookahead_tokens[i], lookahead_set))
        resolve_sr_conflict (s, i, errors, &nerrs);
  
    if (nerrs)
    for (i = 0; i < reds->num; ++i)
      {
        if (!bitset_disjoint_p (reds->lookahead_tokens[i], lookahead_set))
 -      conflicts[s->number] = 1;
 +        conflicts[s->number] = 1;
        bitset_or (lookahead_set, lookahead_set, reds->lookahead_tokens[i]);
      }
  }
@@@ -404,9 -399,9 +404,9 @@@ conflicts_solve (void
        set_conflicts (states[i], errors);
  
        /* For uniformity of the code, make sure all the states have a valid
 -       `errs' member.  */
 +         `errs' member.  */
        if (!states[i]->errs)
 -      states[i]->errs = errs_new (0, 0);
 +        states[i]->errs = errs_new (0, 0);
      }
  
    free (errors);
@@@ -475,11 -470,11 +475,11 @@@ count_rr_conflicts (state *s, bool one_
        int count = 0;
        int j;
        for (j = 0; j < reds->num; ++j)
 -      if (bitset_test (reds->lookahead_tokens[j], i))
 -        count++;
 +        if (bitset_test (reds->lookahead_tokens[j], i))
 +          count++;
  
        if (count >= 2)
 -      rrc_count += one_per_token ? 1 : count-1;
 +        rrc_count += one_per_token ? 1 : count-1;
      }
  
    return rrc_count;
@@@ -495,7 -490,7 +495,7 @@@ conflict_report (FILE *out, int src_num
  {
    if (src_num && rrc_num)
      fprintf (out, _("conflicts: %d shift/reduce, %d reduce/reduce\n"),
 -           src_num, rrc_num);
 +             src_num, rrc_num);
    else if (src_num)
      fprintf (out, _("conflicts: %d shift/reduce\n"), src_num);
    else if (rrc_num)
@@@ -516,12 -511,12 +516,12 @@@ conflicts_output (FILE *out
      {
        state *s = states[i];
        if (conflicts[i])
 -      {
 -        fprintf (out, _("State %d "), i);
 -        conflict_report (out, count_sr_conflicts (s),
 -                         count_rr_conflicts (s, true));
 -        printed_sth = true;
 -      }
 +        {
 +          fprintf (out, _("State %d "), i);
 +          conflict_report (out, count_sr_conflicts (s),
 +                           count_rr_conflicts (s, true));
 +          printed_sth = true;
 +        }
      }
    if (printed_sth)
      fputs ("\n\n", out);
  | Total the number of S/R and R/R conflicts.  Unlike the  |
  | code in conflicts_output, however, count EACH pair of   |
  | reductions for the same state and lookahead as one      |
 -| conflict.                                             |
 +| conflict.                                               |
  `--------------------------------------------------------*/
  
  int
@@@ -545,8 -540,8 +545,8 @@@ conflicts_total_count (void
    for (i = 0; i < nstates; i++)
      if (conflicts[i])
        {
 -      count += count_sr_conflicts (states[i]);
 -      count += count_rr_conflicts (states[i], false);
 +        count += count_sr_conflicts (states[i]);
 +        count += count_rr_conflicts (states[i], false);
        }
    return count;
  }
@@@ -576,15 -571,15 +576,15 @@@ conflicts_print (void
  
      for (i = 0; i < nstates; i++)
        if (conflicts[i])
 -      {
 -        src_total += count_sr_conflicts (states[i]);
 -        rrc_total += count_rr_conflicts (states[i], true);
 -      }
 +        {
 +          src_total += count_sr_conflicts (states[i]);
 +          rrc_total += count_rr_conflicts (states[i], true);
 +        }
    }
  
    if (! glr_parser && rrc_total > 0 && expected_rr_conflicts != -1)
      {
 -      warn (_("%%expect-rr applies only to GLR parsers"));
 +      complain (Wother, _("%%expect-rr applies only to GLR parsers"));
        expected_rr_conflicts = -1;
      }
  
    /* Report the total number of conflicts on STDERR.  */
    if (expected_sr_conflicts == -1 && expected_rr_conflicts == -1)
      {
 -      if (!(warnings_flag & warnings_conflicts_sr))
 +      if (!(warnings_flag & Wconflicts_sr))
          src_total = 0;
 -      if (!(warnings_flag & warnings_conflicts_rr))
 +      if (!(warnings_flag & Wconflicts_rr))
          rrc_total = 0;
      }
    if (src_total | rrc_total)
        if (expected_sr_conflicts == -1 && expected_rr_conflicts == -1)
          set_warning_issued ();
        if (! yacc_flag)
 -      fprintf (stderr, "%s: ", current_file);
 +        fprintf (stderr, "%s: ", current_file);
        conflict_report (stderr, src_total, rrc_total);
      }
  
    if (expected_sr_conflicts != -1 || expected_rr_conflicts != -1)
      {
        if (! src_ok)
 -      complain (ngettext ("expected %d shift/reduce conflict",
 -                          "expected %d shift/reduce conflicts",
 -                          src_expected),
 -                src_expected);
 +        complain (complaint, ngettext ("expected %d shift/reduce conflict",
 +                                       "expected %d shift/reduce conflicts",
 +                                       src_expected),
 +                  src_expected);
        if (! rrc_ok)
 -      complain (ngettext ("expected %d reduce/reduce conflict",
 -                          "expected %d reduce/reduce conflicts",
 -                          rrc_expected),
 -                rrc_expected);
 +        complain (complaint, ngettext ("expected %d reduce/reduce conflict",
 +                                       "expected %d reduce/reduce conflicts",
 +                                       rrc_expected),
 +                  rrc_expected);
      }
  }
  
diff --combined src/muscle-tab.c
index 1168a9c33e5d7e6604d025c63be2977d49b24edd,bd1fd174719941c0ea86b2e727e34404d6dbf13f..bb54bed75a760100fa804362b7eec974c28d349d
@@@ -50,7 -50,7 +50,7 @@@ hash_compare_muscles (void const *x, vo
  {
    muscle_entry const *m1 = x;
    muscle_entry const *m2 = y;
 -  return strcmp (m1->key, m2->key) == 0;
 +  return STREQ (m1->key, m2->key);
  }
  
  static size_t
@@@ -80,7 -80,7 +80,7 @@@ muscle_init (void
    obstack_init (&muscle_obstack);
  
    muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
 -                                hash_compare_muscles, muscle_entry_free);
 +                                  hash_compare_muscles, muscle_entry_free);
  
    /* Version and input file.  */
    MUSCLE_INSERT_STRING ("version", VERSION);
@@@ -177,7 -177,7 +177,7 @@@ static voi
  muscle_syncline_grow (char const *key, location loc)
  {
    char *extension = NULL;
-   obstack_fgrow1 (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
+   obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
    obstack_quote (&muscle_obstack,
                   quotearg_style (c_quoting_style, loc.start.file));
    obstack_sgrow (&muscle_obstack, ")[");
@@@ -202,7 -202,7 +202,7 @@@ muscle_code_grow (const char *key, cons
  
  
  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, "[");
@@@ -268,12 -268,12 +268,12 @@@ muscle_boundary_grow (char const *key, 
    char *extension;
    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_printf (&muscle_obstack, "%d", bound.line);
 -  obstack_1grow  (&muscle_obstack, '.');
 +  obstack_1grow (&muscle_obstack, '.');
-   obstack_fgrow1 (&muscle_obstack, "%d", bound.column);
+   obstack_printf (&muscle_obstack, "%d", bound.column);
    obstack_sgrow  (&muscle_obstack, "]]");
 -  obstack_1grow  (&muscle_obstack, '\0');
 +  obstack_1grow (&muscle_obstack, '\0');
    extension = obstack_finish (&muscle_obstack);
    muscle_grow (key, extension, "");
    obstack_free (&muscle_obstack, extension);
@@@ -396,42 -396,25 +396,42 @@@ muscle_user_name_list_grow (char const 
    muscle_grow (key, "]]", "");
  }
  
 +/** If the \a variable name is obsolete, return the name to use,
 + * otherwise \a variable. */
 +static
 +char const *
 +muscle_percent_variable_update (char const *variable)
 +{
 +  typedef struct
 +  {
 +    const char *obsolete;
 +    const char *updated;
 +  } conversion_type;
 +  const conversion_type conversion[] =
 +    {
 +      { "api.push_pull", "api.push-pull", },
 +      { "lr.keep_unreachable_states", "lr.keep-unreachable-states", },
 +      { "namespace", "api.namespace", },
 +    };
 +  int i;
 +  for (i = 0; i < sizeof conversion / sizeof *conversion; ++i)
 +    if (STREQ (conversion[i].obsolete, variable))
 +      return conversion[i].updated;
 +  return variable;
 +}
 +
  void
  muscle_percent_define_insert (char const *variable, location variable_loc,
                                char const *value,
                                muscle_percent_define_how how)
  {
 -  char *variable_tr = NULL;
    char const *name;
    char const *loc_name;
    char const *syncline_name;
    char const *how_name;
  
    /* Permit certain names with underscores for backward compatibility.  */
 -  if (0 == strcmp (variable, "api.push_pull")
 -      || 0 == strcmp (variable, "lr.keep_unreachable_states"))
 -    {
 -      variable_tr = strdup (variable);
 -      tr (variable_tr, '_', '-');
 -      variable = variable_tr;
 -    }
 +  variable = muscle_percent_variable_update (variable);
  
    name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
    loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
        muscle_percent_define_how how_old =
          atoi (muscle_find_const (how_name));
        if (how_old == MUSCLE_PERCENT_DEFINE_F)
 -        {
 -          free (variable_tr);
 -          return;
 -        }
 -      complain_at (variable_loc, _("%%define variable %s redefined"),
 +        return;
 +      complain_at (variable_loc, complaint, _("%%define variable %s redefined"),
                     quote (variable));
 -      complain_at (muscle_percent_define_get_loc (variable),
 -                   _("previous definition"));
 +      location loc = muscle_percent_define_get_loc (variable);
 +      complain_at (loc, complaint, _("previous definition"));
      }
  
    MUSCLE_INSERT_STRING (name, value);
    muscle_user_name_list_grow ("percent_define_user_variables", variable,
                                variable_loc);
    MUSCLE_INSERT_INT (how_name, how);
 +}
 +
 +/* This is used for backward compatibility, e.g., "%define api.pure"
 +   supersedes "%pure-parser".  */
 +void
 +muscle_percent_define_ensure (char const *variable, location loc,
 +                              bool value)
 +{
 +  char const *val = value ? "" : "false";
 +  char const *name;
 +  name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
  
 -  free (variable_tr);
 +  /* %pure-parser is deprecated in favor of `%define api.pure', so use
 +     `%define api.pure' in a backward-compatible manner here.  First,
 +     don't complain if %pure-parser is specified multiple times.  */
 +  if (!muscle_find_const (name))
 +    muscle_percent_define_insert (variable, loc, val,
 +                                  MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
 +  /* In all cases, use api.pure now so that the backend doesn't complain if
 +     the skeleton ignores api.pure, but do warn now if there's a previous
 +     conflicting definition from an actual %define.  */
 +  if (muscle_percent_define_flag_if (variable) != value)
 +    muscle_percent_define_insert (variable, loc, val,
 +                                  MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
  }
  
  char *
@@@ -511,7 -475,7 +511,7 @@@ muscle_percent_define_get_loc (char con
    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 location_decode (loc_name);
  }
@@@ -525,7 -489,7 +525,7 @@@ muscle_percent_define_get_syncline (cha
      UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
    syncline = muscle_find_const (syncline_name);
    if (!syncline)
 -    fatal(_("%s: undefined %%define variable %s"),
 +    complain (fatal, _("%s: undefined %%define variable %s"),
            "muscle_percent_define_get_syncline", quote (variable));
    return syncline;
  }
@@@ -563,23 -527,22 +563,23 @@@ muscle_percent_define_flag_if (char con
    if (muscle_percent_define_ifdef (variable))
      {
        char *value = muscle_percent_define_get (variable);
 -      if (value[0] == '\0' || 0 == strcmp (value, "true"))
 +      if (value[0] == '\0' || STREQ (value, "true"))
          result = true;
 -      else if (0 == strcmp (value, "false"))
 +      else if (STREQ (value, "false"))
          result = false;
        else if (!muscle_find_const (invalid_boolean_name))
          {
            muscle_insert (invalid_boolean_name, "");
 -          complain_at(muscle_percent_define_get_loc (variable),
 -                      _("invalid value for %%define Boolean variable %s"),
 -                      quote (variable));
 +          location loc = muscle_percent_define_get_loc (variable);
 +          complain_at (loc, complaint,
 +                       _("invalid value for %%define Boolean variable %s"),
 +                       quote (variable));
          }
        free (value);
      }
    else
 -    fatal(_("%s: undefined %%define variable %s"),
 -          "muscle_percent_define_flag", quote (variable));
 +    complain (fatal, _("%s: undefined %%define variable %s"),
 +              "muscle_percent_define_flag", quote (variable));
  
    return result;
  }
@@@ -623,18 -586,17 +623,18 @@@ muscle_percent_define_check_values (cha
          {
            for (++values; *values; ++values)
              {
 -              if (0 == strcmp (value, *values))
 +              if (STREQ (value, *values))
                  break;
              }
            if (!*values)
              {
                location loc = muscle_percent_define_get_loc (*variablep);
 -              complain_at(loc,
 -                          _("invalid value for %%define variable %s: %s"),
 -                          quote (*variablep), quote_n (1, value));
 +              complain_at (loc, complaint,
 +                           _("invalid value for %%define variable %s: %s"),
 +                           quote (*variablep), quote_n (1, value));
                for (values = variablep + 1; *values; ++values)
 -                complain_at (loc, _("accepted value: %s"), quote (*values));
 +                complain_at (loc, complaint, _("accepted value: %s"),
 +                             quote (*values));
              }
            else
              {
            free (value);
          }
        else
 -        fatal (_("%s: undefined %%define variable %s"),
 -               "muscle_percent_define_check_values", quote (*variablep));
 +        complain (fatal, _("%s: undefined %%define variable %s"),
 +                  "muscle_percent_define_check_values", quote (*variablep));
      }
  }
  
diff --combined src/muscle-tab.h
index 1f33f8c15a9bf1fc67750a654bd93dccdce825e5,696103f393f161b69e93afd882ca019c40656300..ac852978439fbefb542e33c66ed16966d17b28e5
@@@ -1,6 -1,7 +1,6 @@@
  /* Muscle table manager for Bison,
  
 -   Copyright (C) 2001-2003, 2006-2007, 2009-2012 Free Software
 -   Foundation, Inc.
 +   Copyright (C) 2001-2003, 2006-2012 Free Software Foundation, Inc.
  
     This file is part of Bison, the GNU Compiler Compiler.
  
@@@ -36,25 -37,24 +36,25 @@@ extern struct obstack muscle_obstack
  
  #define MUSCLE_INSERT_BOOL(Key, Value)                          \
    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_printf (&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_printf (&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);                     \
@@@ -62,7 -62,6 +62,7 @@@
      muscle_insert (Key, obstack_finish (&muscle_obstack));      \
    } while (0)
  
 +/* Key -> Value, applying M4 escaping to Value. */
  #define MUSCLE_INSERT_STRING(Key, Value)                        \
    do {                                                          \
      obstack_escape (&muscle_obstack, Value);                    \
@@@ -124,13 -123,6 +124,13 @@@ void muscle_percent_define_insert (cha
                                     char const *value,
                                     muscle_percent_define_how how);
  
 +/* Make sure that VARIABLE is set to the boolean VALUE.  Warn on mismatches
 +   only, but accept repeated declaration.  Used for backward compatibility
 +   between old directives such as %pure-parser, and the recommended use of
 +   variables (%define api.pure).   */
 +void muscle_percent_define_ensure (char const *variable, location variable_loc,
 +                                   bool value);
 +
  /* Mimic b4_percent_define_get in ../data/bison.m4 exactly.  That is, if the
     %define variable VARIABLE is defined, return its value.  Otherwise, return
     the empty string.  Also, record Bison's usage of VARIABLE by defining
diff --combined src/output.c
index c227be223f4c89749696305e8aebc7f5ed3365d9,e77a2d1a0fc85a75d6f6bec202d96351778dfef2..24bb83cd146331c7ae337072a2cee56fb9c7af09
@@@ -21,9 -21,8 +21,9 @@@
  #include <config.h>
  #include "system.h"
  
 +#include <concat-filename.h>
  #include <configmake.h>
 -#include <error.h>
 +#include <filename.h>
  #include <get-errno.h>
  #include <quotearg.h>
  #include <spawn-pipe.h>
@@@ -42,6 -41,8 +42,6 @@@
  #include "symtab.h"
  #include "tables.h"
  
 -# define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
 -
  static struct obstack format_obstack;
  
  
  `-------------------------------------------------------------------*/
  
  
 -#define GENERATE_MUSCLE_INSERT_TABLE(Name, Type)                      \
 -                                                                      \
 -static void                                                           \
 -Name (char const *name,                                                       \
 -      Type *table_data,                                                       \
 -      Type first,                                                     \
 -      int begin,                                                      \
 -      int end)                                                                \
 -{                                                                     \
 -  Type min = first;                                                   \
 -  Type max = first;                                                   \
 -  long int lmin;                                                      \
 -  long int lmax;                                                      \
 -  int i;                                                              \
 -  int j = 1;                                                          \
 -                                                                      \
 -  obstack_printf (&format_obstack, "%6d", first);                     \
 -  for (i = begin; i < end; ++i)                                               \
 -    {                                                                 \
 -      obstack_1grow (&format_obstack, ',');                           \
 -      if (j >= 10)                                                    \
 -      {                                                               \
 -        obstack_sgrow (&format_obstack, "\n  ");                      \
 -        j = 1;                                                        \
 -      }                                                               \
 -      else                                                            \
 -      ++j;                                                            \
 -      obstack_printf (&format_obstack, "%6d", table_data[i]);         \
 -      if (table_data[i] < min)                                                \
 -      min = table_data[i];                                            \
 -      if (max < table_data[i])                                                \
 -      max = table_data[i];                                            \
 -    }                                                                 \
 -  obstack_1grow (&format_obstack, 0);                                 \
 -  muscle_insert (name, obstack_finish (&format_obstack));             \
 -                                                                      \
 -  lmin = min;                                                         \
 -  lmax = max;                                                         \
 -  /* Build `NAME_min' and `NAME_max' in the obstack. */                       \
 -  obstack_printf (&format_obstack, "%s_min", name);                   \
 -  obstack_1grow (&format_obstack, 0);                                 \
 -  MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmin);    \
 -  obstack_printf (&format_obstack, "%s_max", name);                   \
 -  obstack_1grow (&format_obstack, 0);                                 \
 -  MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmax);    \
 +#define GENERATE_MUSCLE_INSERT_TABLE(Name, Type)                        \
 +                                                                        \
 +static void                                                             \
 +Name (char const *name,                                                 \
 +      Type *table_data,                                                 \
 +      Type first,                                                       \
 +      int begin,                                                        \
 +      int end)                                                          \
 +{                                                                       \
 +  Type min = first;                                                     \
 +  Type max = first;                                                     \
 +  long int lmin;                                                        \
 +  long int lmax;                                                        \
 +  int i;                                                                \
 +  int j = 1;                                                            \
 +                                                                        \
-   obstack_fgrow1 (&format_obstack, "%6d", first);                       \
++  obstack_printf (&format_obstack, "%6d", first);                       \
 +  for (i = begin; i < end; ++i)                                         \
 +    {                                                                   \
 +      obstack_1grow (&format_obstack, ',');                             \
 +      if (j >= 10)                                                      \
 +        {                                                               \
 +          obstack_sgrow (&format_obstack, "\n  ");                      \
 +          j = 1;                                                        \
 +        }                                                               \
 +      else                                                              \
 +        ++j;                                                            \
-       obstack_fgrow1 (&format_obstack, "%6d", table_data[i]);           \
++      obstack_printf (&format_obstack, "%6d", table_data[i]);           \
 +      if (table_data[i] < min)                                          \
 +        min = table_data[i];                                            \
 +      if (max < table_data[i])                                          \
 +        max = table_data[i];                                            \
 +    }                                                                   \
 +  obstack_1grow (&format_obstack, 0);                                   \
 +  muscle_insert (name, obstack_finish (&format_obstack));               \
 +                                                                        \
 +  lmin = min;                                                           \
 +  lmax = max;                                                           \
 +  /* Build `NAME_min' and `NAME_max' in the obstack. */                 \
-   obstack_fgrow1 (&format_obstack, "%s_min", name);                     \
++  obstack_printf (&format_obstack, "%s_min", name);                     \
 +  obstack_1grow (&format_obstack, 0);                                   \
 +  MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmin);      \
-   obstack_fgrow1 (&format_obstack, "%s_max", name);                     \
++  obstack_printf (&format_obstack, "%s_max", name);                     \
 +  obstack_1grow (&format_obstack, 0);                                   \
 +  MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmax);      \
  }
  
  GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_unsigned_int_table, unsigned int)
@@@ -105,6 -106,7 +105,6 @@@ GENERATE_MUSCLE_INSERT_TABLE(muscle_ins
  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)
  
  
@@@ -152,14 -154,13 +152,14 @@@ prepare_symbols (void
  {
    MUSCLE_INSERT_INT ("tokens_number", ntokens);
    MUSCLE_INSERT_INT ("nterms_number", nvars);
 +  MUSCLE_INSERT_INT ("symbols_number", nsyms);
    MUSCLE_INSERT_INT ("undef_token_number", undeftoken->number);
    MUSCLE_INSERT_INT ("user_token_number_max", max_user_token_number);
  
    muscle_insert_symbol_number_table ("translate",
 -                                   token_translations,
 -                                   token_translations[0],
 -                                   1, max_user_token_number + 1);
 +                                     token_translations,
 +                                     token_translations[0],
 +                                     1, max_user_token_number + 1);
  
    /* tname -- token names.  */
    {
      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, ' ');
 +        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 (i = 0; i < ntokens; ++i)
        values[i] = symbols[i]->user_token_number;
      muscle_insert_int_table ("toknum", values,
 -                           values[0], 1, ntokens);
 +                             values[0], 1, ntokens);
      free (values);
    }
  }
  
  
 -/*-------------------------------------------------------------.
 -| Prepare the muscles related to the rules: rhs, prhs, r1, r2, |
 -| rline, dprec, merger.                                        |
 -`-------------------------------------------------------------*/
 +/*----------------------------------------------------------------.
 +| Prepare the muscles related to the rules: r1, r2, rline, dprec, |
 +| merger, immediate.                                              |
 +`----------------------------------------------------------------*/
  
  static void
  prepare_rules (void)
  {
 -  rule_number r;
 -  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);
    int *dprec = xnmalloc (nrules, sizeof *dprec);
    int *merger = xnmalloc (nrules, sizeof *merger);
 +  int *immediate = xnmalloc (nrules, sizeof *immediate);
  
 +  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] = i - prhs[r];
 -      /* Separator in RHS. */
 -      rhs[i++] = -1;
 +      r2[r] = rule_rhs_length(&rules[r]);
        /* Line where rule was defined. */
        rline[r] = rules[r].location.start.line;
        /* Dynamic precedence (GLR).  */
        dprec[r] = rules[r].dprec;
        /* Merger-function index (GLR).  */
        merger[r] = rules[r].merger;
 +      /* 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);
    muscle_insert_int_table ("dprec", dprec, 0, 0, nrules);
    muscle_insert_int_table ("merger", merger, 0, 0, nrules);
 +  muscle_insert_int_table ("immediate", immediate, 0, 0, nrules);
  
    MUSCLE_INSERT_INT ("rules_number", nrules);
    MUSCLE_INSERT_INT ("max_left_semantic_context", max_left_semantic_context);
  
 -  free (rhs);
 -  free (prhs);
    free (rline);
    free (r1);
    free (r2);
    free (dprec);
    free (merger);
 +  free (immediate);
  }
  
  /*--------------------------------------------.
@@@ -272,7 -284,7 +272,7 @@@ prepare_states (void
    for (i = 0; i < nstates; ++i)
      values[i] = states[i]->accessing_symbol;
    muscle_insert_symbol_number_table ("stos", values,
 -                                   0, 1, nstates);
 +                                     0, 1, nstates);
    free (values);
  
    MUSCLE_INSERT_INT ("last", high);
  }
  
  
 +/*-------------------------------------------------------.
 +| Compare two symbols by type-name, and then by number.  |
 +`-------------------------------------------------------*/
 +
 +static int
 +symbol_type_name_cmp (const symbol **lhs, const symbol **rhs)
 +{
 +  int res = UNIQSTR_CMP((*lhs)->type_name, (*rhs)->type_name);
 +  if (res)
 +    return res;
 +  return (*lhs)->number - (*rhs)->number;
 +}
 +
 +
 +/*----------------------------------------------------------------.
 +| Return a (malloc'ed) table of the symbols sorted by type-name.  |
 +`----------------------------------------------------------------*/
 +
 +static symbol **
 +symbols_by_type_name (void)
 +{
 +  typedef int (*qcmp_type) (const void *, const void *);
 +  symbol **res = xmemdup (symbols, nsyms * sizeof *res);
 +  qsort (res, nsyms, sizeof *res, (qcmp_type) &symbol_type_name_cmp);
 +  return res;
 +}
 +
 +
 +/*------------------------------------------------------------------.
 +| Define b4_type_names, which is a list of (lists of the numbers of |
 +| symbols with same type-name).                                     |
 +`------------------------------------------------------------------*/
 +
 +static void
 +type_names_output (FILE *out)
 +{
 +  int i;
 +  symbol **syms = symbols_by_type_name ();
 +  fputs ("m4_define([b4_type_names],\n[", out);
 +  for (i = 0; i < nsyms; /* nothing */)
 +    {
 +      // The index of the first symbol of the current type-name.
 +      int i0 = i;
 +      fputs (i ? ",\n[" : "[", out);
 +      for (; i < nsyms && syms[i]->type_name == syms[i0]->type_name; ++i)
 +        fprintf (out, "%s%d", i != i0 ? ", " : "", syms[i]->number);
 +      fputs ("]", out);
 +    }
 +  fputs ("])\n\n", out);
 +  free (syms);
 +}
 +
 +
 +/*-------------------------------------.
 +| The list of all the symbol numbers.  |
 +`-------------------------------------*/
 +
 +static void
 +symbol_numbers_output (FILE *out)
 +{
 +  int i;
 +  fputs ("m4_define([b4_symbol_numbers],\n[", out);
 +  for (i = 0; i < nsyms; ++i)
 +    fprintf (out, "%s[%d]", i ? ", " : "", i);
 +  fputs ("])\n\n", out);
 +}
 +
  
  /*---------------------------------.
  | Output the user actions to OUT.  |
@@@ -362,18 -307,17 +362,18 @@@ user_actions_output (FILE *out
    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);
 +        string_output (out, rules[r].action_location.start.file);
 +        fprintf (out, ")\n[    %s]])\n\n", rules[r].action);
        }
    fputs ("])\n\n", out);
  }
  
 -/*--------------------------------------.
 -| Output the merge functions to OUT.   |
 -`--------------------------------------*/
 +/*------------------------------------.
 +| Output the merge functions to OUT.  |
 +`------------------------------------*/
  
  static void
  merger_output (FILE *out)
    for (n = 1, p = merge_functions; p != NULL; n += 1, p = p->next)
      {
        if (p->type[0] == '\0')
 -      fprintf (out, "  case %d: *yy0 = %s (*yy0, *yy1); break;\n",
 -               n, p->name);
 +        fprintf (out, "  case %d: *yy0 = %s (*yy0, *yy1); break;\n",
 +                 n, p->name);
        else
 -      fprintf (out, "  case %d: yy0->%s = %s (*yy0, *yy1); break;\n",
 -               n, p->type, p->name);
 +        fprintf (out, "  case %d: yy0->%s = %s (*yy0, *yy1); break;\n",
 +                 n, p->type, p->name);
      }
    fputs ("]])\n\n", out);
  }
  
 -/*--------------------------------------.
 -| Output the tokens definition to OUT.  |
 -`--------------------------------------*/
 +
 +/*---------------------------------------------.
 +| Prepare the muscles for symbol definitions.  |
 +`---------------------------------------------*/
  
  static void
 -token_definitions_output (FILE *out)
 +prepare_symbol_definitions (void)
  {
    int i;
 -  char const *sep = "";
 -
 -  fputs ("m4_define([b4_tokens], \n[", out);
 -  for (i = 0; i < ntokens; ++i)
 +  for (i = 0; i < nsyms; ++i)
      {
        symbol *sym = symbols[i];
 -      int number = sym->user_token_number;
 -
 -      /* At this stage, if there are literal string aliases, they are
 -         part of SYMBOLS, so we should not find their aliased symbols
 -         here.  */
 -      aver (number != USER_NUMBER_HAS_STRING_ALIAS);
 -
 -      /* Skip error token.  */
 -      if (sym == errtoken)
 -      continue;
 -
 -      /* If this string has an alias, then it is necessarily the alias
 -       which is to be output.  */
 -      if (sym->alias)
 -      sym = sym->alias;
 -
 -      /* Don't output literal chars or strings (when defined only as a
 -       string).  Note that must be done after the alias resolution:
 -       think about `%token 'f' "f"'.  */
 -      if (sym->tag[0] == '\'' || sym->tag[0] == '\"')
 -      continue;
 -
 -      /* Don't #define nonliteral tokens whose names contain periods,
 -         dashes or '$' (as does the default value of the EOF token).  */
 -      if (mbschr (sym->tag, '.')
 -          || mbschr (sym->tag, '-')
 -          || mbschr (sym->tag, '$'))
 -      continue;
 -
 -      fprintf (out, "%s[[[%s]], %d]",
 -             sep, sym->tag, number);
 -      sep = ",\n";
 -    }
 -  fputs ("])\n\n", out);
 -}
 +      const char *key;
 +      const char *value;
  
-       obstack_fgrow2 (&format_obstack, "symbol(%d, %s)",        \
 +#define SET_KEY(Entry)                                          \
++      obstack_printf (&format_obstack, "symbol(%d, %s)",        \
 +                      i, Entry);                                \
 +      obstack_1grow (&format_obstack, 0);                       \
 +      key = obstack_finish (&format_obstack);
  
 -/*---------------------------------------------------.
 -| Output the symbol destructors or printers to OUT.  |
 -`---------------------------------------------------*/
 +#define SET_KEY2(Entry, Suffix)                                 \
-       obstack_fgrow3 (&format_obstack, "symbol(%d, %s_%s)",     \
++      obstack_printf (&format_obstack, "symbol(%d, %s_%s)",     \
 +                      i, Entry, Suffix);                        \
 +      obstack_1grow (&format_obstack, 0);                       \
 +      key = obstack_finish (&format_obstack);
  
 -static void
 -symbol_code_props_output (FILE *out, char const *what,
 -                          code_props const *(*get)(symbol const *))
 -{
 -  int i;
 -  char const *sep = "";
 +      // Whether the symbol has an identifier.
 +      value = symbol_id_get (sym);
 +      SET_KEY("has_id");
 +      MUSCLE_INSERT_INT (key, !!value);
  
 -  fputs ("m4_define([b4_symbol_", out);
 -  fputs (what, out);
 -  fputs ("], \n[", out);
 -  for (i = 0; i < nsyms; ++i)
 -    {
 -      symbol *sym = symbols[i];
 -      char const *code = (*get) (sym)->code;
 -      if (code)
 -        {
 -          location loc = (*get) (sym)->location;
 -          /* Filename, lineno,
 -             Symbol-name, Symbol-number,
 -             code, optional typename.  */
 -          fprintf (out, "%s[", sep);
 -          sep = ",\n";
 -          string_output (out, loc.start.file);
 -          fprintf (out, ", %d, ", loc.start.line);
 -          quoted_output (out, sym->tag);
 -          fprintf (out, ", %d, [[%s]]", sym->number, code);
 -          if (sym->type_name)
 -            {
 -              fputs (", ", out);
 -              quoted_output (out, sym->type_name);
 -            }
 -          fputc (']', out);
 -        }
 +      // Its identifier.
 +      SET_KEY("id");
 +      MUSCLE_INSERT_STRING (key, value ? value : "");
 +
 +      // Its tag.  Typically for documentation purpose.
 +      SET_KEY("tag");
 +      MUSCLE_INSERT_STRING (key, sym->tag);
 +
 +      SET_KEY("user_number");
 +      MUSCLE_INSERT_INT (key, sym->user_token_number);
 +
 +      SET_KEY("is_token");
 +      MUSCLE_INSERT_INT (key,
 +                         i < ntokens && sym != errtoken && sym != undeftoken);
 +
 +      SET_KEY("number");
 +      MUSCLE_INSERT_INT (key, sym->number);
 +
 +      SET_KEY("has_type");
 +      MUSCLE_INSERT_INT (key, !!sym->type_name);
 +
 +      SET_KEY("type");
 +      MUSCLE_INSERT_STRING (key, sym->type_name ? sym->type_name : "");
 +
 +      {
 +        int j;
 +        for (j = 0; j < CODE_PROPS_SIZE; ++j)
 +          {
 +            /* "printer", not "%printer".  */
 +            char const *pname = code_props_type_string (j) + 1;
 +            code_props const *p = symbol_code_props_get (sym, j);
 +            SET_KEY2("has", pname);
 +            MUSCLE_INSERT_INT (key, !!p->code);
 +
 +            if (p->code)
 +              {
 +                SET_KEY2(pname, "file");
 +                MUSCLE_INSERT_STRING (key, p->location.start.file);
 +
 +                SET_KEY2(pname, "line");
 +                MUSCLE_INSERT_INT (key, p->location.start.line);
 +
 +                SET_KEY(pname);
 +                MUSCLE_INSERT_STRING_RAW (key, p->code);
 +              }
 +          }
 +      }
 +#undef SET_KEY2
 +#undef SET_KEY
      }
 -  fputs ("])\n\n", out);
  }
  
  
@@@ -486,30 -438,30 +486,30 @@@ prepare_actions (void
       lookahead token type.  */
  
    muscle_insert_rule_number_table ("defact", yydefact,
 -                                 yydefact[0], 1, nstates);
 +                                   yydefact[0], 1, nstates);
  
    /* Figure out what to do after reducing with each rule, depending on
       the saved state from before the beginning of parsing the data
       that matched this rule.  */
    muscle_insert_state_number_table ("defgoto", yydefgoto,
 -                                  yydefgoto[0], 1, nsyms - ntokens);
 +                                    yydefgoto[0], 1, nsyms - ntokens);
  
  
    /* Output PACT. */
    muscle_insert_base_table ("pact", base,
 -                           base[0], 1, nstates);
 +                             base[0], 1, nstates);
    MUSCLE_INSERT_INT ("pact_ninf", base_ninf);
  
    /* Output PGOTO. */
    muscle_insert_base_table ("pgoto", base,
 -                           base[nstates], nstates + 1, nvectors);
 +                             base[nstates], nstates + 1, nvectors);
  
    muscle_insert_base_table ("table", table,
 -                          table[0], 1, high + 1);
 +                            table[0], 1, high + 1);
    MUSCLE_INSERT_INT ("table_ninf", table_ninf);
  
    muscle_insert_base_table ("check", check,
 -                          check[0], 1, high + 1);
 +                            check[0], 1, high + 1);
  
    /* GLR parsing slightly modifies YYTABLE and YYCHECK (and thus
       YYPACT) so that in states with unresolved conflicts, the default
       that case.  Nevertheless, it seems even better to be able to use
       the GLR skeletons even without the non-deterministic tables.  */
    muscle_insert_unsigned_int_table ("conflict_list_heads", conflict_table,
 -                                  conflict_table[0], 1, high + 1);
 +                                    conflict_table[0], 1, high + 1);
    muscle_insert_unsigned_int_table ("conflicting_rules", conflict_list,
 -                                  0, 1, conflict_list_cnt);
 +                                    0, 1, conflict_list_cnt);
  }
  
 +
  /*--------------------------------------------.
  | Output the definitions of all the muscles.  |
  `--------------------------------------------*/
@@@ -535,11 -486,13 +535,11 @@@ static voi
  muscles_output (FILE *out)
  {
    fputs ("m4_init()\n", out);
 -
 -  user_actions_output (out);
    merger_output (out);
 -  token_definitions_output (out);
 -  symbol_code_props_output (out, "destructors", &symbol_destructor_get);
 -  symbol_code_props_output (out, "printers", &symbol_printer_get);
 -
 +  symbol_numbers_output (out);
 +  type_names_output (out);
 +  user_actions_output (out);
 +  // Must be last.
    muscles_m4_output (out);
  }
  \f
  static void
  output_skeleton (void)
  {
 -  FILE *in;
    int filter_fd[2];
 -  char const *argv[10];
    pid_t pid;
  
    /* Compute the names of the package data dir and skeleton files.  */
 -  char const m4sugar[] = "m4sugar/m4sugar.m4";
 -  char const m4bison[] = "bison.m4";
 -  char *full_m4sugar;
 -  char *full_m4bison;
 -  char *full_skeleton;
 -  char const *p;
 -  char const *m4 = (p = getenv ("M4")) ? p : M4;
 -  char const *pkgdatadir = compute_pkgdatadir ();
 -  size_t skeleton_size = strlen (skeleton) + 1;
 -  size_t pkgdatadirlen = strlen (pkgdatadir);
 -  while (pkgdatadirlen && pkgdatadir[pkgdatadirlen - 1] == '/')
 -    pkgdatadirlen--;
 -  full_skeleton = xmalloc (pkgdatadirlen + 1
 -                         + (skeleton_size < sizeof m4sugar
 -                            ? sizeof m4sugar : skeleton_size));
 -  memcpy (full_skeleton, pkgdatadir, pkgdatadirlen);
 -  full_skeleton[pkgdatadirlen] = '/';
 -  strcpy (full_skeleton + pkgdatadirlen + 1, m4sugar);
 -  full_m4sugar = xstrdup (full_skeleton);
 -  strcpy (full_skeleton + pkgdatadirlen + 1, m4bison);
 -  full_m4bison = xstrdup (full_skeleton);
 -  if (mbschr (skeleton, '/'))
 -    strcpy (full_skeleton, skeleton);
 -  else
 -    strcpy (full_skeleton + pkgdatadirlen + 1, skeleton);
 +  char const *m4 = (m4 = getenv ("M4")) ? m4 : M4;
 +  char const *datadir = pkgdatadir ();
 +  char *m4sugar = xconcatenated_filename (datadir, "m4sugar/m4sugar.m4", NULL);
 +  char *m4bison = xconcatenated_filename (datadir, "bison.m4", NULL);
 +  char *skel = (IS_PATH_WITH_DIR (skeleton)
 +                ? xstrdup (skeleton)
 +                : xconcatenated_filename (datadir, skeleton, NULL));
  
    /* Test whether m4sugar.m4 is readable, to check for proper
       installation.  A faulty installation can cause deadlock, so a
       cheap sanity check is worthwhile.  */
 -  xfclose (xfopen (full_m4sugar, "r"));
 +  xfclose (xfopen (m4sugar, "r"));
  
    /* Create an m4 subprocess connected to us via two pipes.  */
  
    if (trace_flag & trace_tools)
      fprintf (stderr, "running: %s %s - %s %s\n",
 -             m4, full_m4sugar, full_m4bison, full_skeleton);
 +             m4, m4sugar, m4bison, skel);
  
    /* Some future version of GNU M4 (most likely 1.6) may treat the -dV in a
       position-dependent manner.  Keep it as the first argument so that all
       <http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html>
       for details.  */
    {
 +    char const *argv[10];
      int i = 0;
      argv[i++] = m4;
  
        argv[i++] = M4_GNU_OPTION;
  
      argv[i++] = "-I";
 -    argv[i++] = pkgdatadir;
 +    argv[i++] = datadir;
      if (trace_flag & trace_m4)
        argv[i++] = "-dV";
 -    argv[i++] = full_m4sugar;
 +    argv[i++] = m4sugar;
      argv[i++] = "-";
 -    argv[i++] = full_m4bison;
 -    argv[i++] = full_skeleton;
 +    argv[i++] = m4bison;
 +    argv[i++] = skel;
      argv[i++] = NULL;
      aver (i <= ARRAY_CARDINALITY (argv));
 +
 +    /* The ugly cast is because gnulib gets the const-ness wrong.  */
 +    pid = create_pipe_bidi ("m4", m4, (char **)(void*)argv, false, true,
 +                            true, filter_fd);
    }
  
 -  /* The ugly cast is because gnulib gets the const-ness wrong.  */
 -  pid = create_pipe_bidi ("m4", m4, (char **)(void*)argv, false, true,
 -                          true, filter_fd);
 -  free (full_m4sugar);
 -  free (full_m4bison);
 -  free (full_skeleton);
 +  free (m4sugar);
 +  free (m4bison);
 +  free (skel);
  
    if (trace_flag & trace_muscles)
      muscles_output (stderr);
    {
 -    FILE *out = fdopen (filter_fd[1], "w");
 -    if (! out)
 -      error (EXIT_FAILURE, get_errno (),
 -             "fdopen");
 +    FILE *out = xfdopen (filter_fd[1], "w");
      muscles_output (out);
      xfclose (out);
    }
  
    /* Read and process m4's output.  */
    timevar_push (TV_M4);
 -  in = fdopen (filter_fd[0], "r");
 -  if (! in)
 -    error (EXIT_FAILURE, get_errno (),
 -         "fdopen");
 -  scan_skel (in);
 -  /* scan_skel should have read all of M4's output.  Otherwise, when we
 -     close the pipe, we risk letting M4 report a broken-pipe to the
 -     Bison user.  */
 -  aver (feof (in));
 -  xfclose (in);
 +  {
 +    FILE *in = xfdopen (filter_fd[0], "r");
 +    scan_skel (in);
 +    /* scan_skel should have read all of M4's output.  Otherwise, when we
 +       close the pipe, we risk letting M4 report a broken-pipe to the
 +       Bison user.  */
 +    aver (feof (in));
 +    xfclose (in);
 +  }
    wait_subprocess (pid, "m4", false, false, true, true, NULL);
    timevar_pop (TV_M4);
  }
  static void
  prepare (void)
  {
 -  /* BISON_USE_PUSH_FOR_PULL is for the test suite and should not be documented
 -     for the user.  */
 -  char const *use_push_for_pull_env = getenv ("BISON_USE_PUSH_FOR_PULL");
 -  bool use_push_for_pull_flag = false;
 -  if (use_push_for_pull_env != NULL
 -      && use_push_for_pull_env[0] != '\0'
 -      && 0 != strcmp (use_push_for_pull_env, "0"))
 -    use_push_for_pull_flag = true;
 +  /* BISON_USE_PUSH_FOR_PULL is for the test suite and should not be
 +     documented for the user.  */
 +  char const *cp = getenv ("BISON_USE_PUSH_FOR_PULL");
 +  bool use_push_for_pull_flag = cp && *cp && strtol (cp, 0, 10);
  
    /* Flags. */
 -  MUSCLE_INSERT_BOOL ("debug_flag", debug_flag);
    MUSCLE_INSERT_BOOL ("defines_flag", defines_flag);
 -  MUSCLE_INSERT_BOOL ("error_verbose_flag", error_verbose);
    MUSCLE_INSERT_BOOL ("glr_flag", glr_parser);
 -  MUSCLE_INSERT_BOOL ("locations_flag", locations_flag);
    MUSCLE_INSERT_BOOL ("nondeterministic_flag", nondeterministic_parser);
    MUSCLE_INSERT_BOOL ("synclines_flag", !no_lines_flag);
    MUSCLE_INSERT_BOOL ("tag_seen_flag", tag_seen);
      /* b4_pkgdatadir is used inside m4_include in the skeletons, so digraphs
         would never be expanded.  Hopefully no one has M4-special characters in
         his Bison installation path.  */
 -    MUSCLE_INSERT_STRING_RAW ("pkgdatadir", compute_pkgdatadir ());
 +    MUSCLE_INSERT_STRING_RAW ("pkgdatadir", pkgdatadir ());
    }
  }
  
@@@ -704,7 -686,6 +704,7 @@@ output (void
    prepare_rules ();
    prepare_states ();
    prepare_actions ();
 +  prepare_symbol_definitions ();
  
    prepare ();
  
  }
  
  char const *
 -compute_pkgdatadir (void)
 +pkgdatadir (void)
  {
 -  char const *pkgdatadir = getenv ("BISON_PKGDATADIR");
 -  return pkgdatadir ? pkgdatadir : PKGDATADIR;
 +  char const *cp = getenv ("BISON_PKGDATADIR");
 +  return cp ? cp : PKGDATADIR;
  }
diff --combined src/print_graph.c
index 61d3651297342ef40bdd1d69a5fc5297f2dbe0ae,f5695a7a734951fe65d5d498359f3fd66522292f..d37afb2cd9d45c3fe36d208101f5941c2251f778
@@@ -54,7 -54,7 +54,7 @@@ print_core (struct obstack *oout, stat
        snritems = nitemset;
      }
  
-   obstack_fgrow1 (oout, "%d", s->number);
+   obstack_printf (oout, "%d", s->number);
    for (i = 0; i < snritems; i++)
      {
        item_number *sp;
        sp1 = sp = ritem + sitems[i];
  
        while (*sp >= 0)
 -      sp++;
 +        sp++;
  
        r = item_number_as_rule_number (*sp);
  
-       obstack_fgrow1 (oout, "\n%s -> ", rules[r].lhs->tag);
+       obstack_printf (oout, "\n%s -> ", rules[r].lhs->tag);
  
        for (sp = rules[r].rhs; sp < sp1; sp++)
-         obstack_fgrow1 (oout, "%s ", symbols[*sp]->tag);
 -      obstack_printf (oout, "%s ", symbols[*sp]->tag);
++        obstack_printf (oout, "%s ", symbols[*sp]->tag);
  
        obstack_1grow (oout, '.');
  
        for (/* Nothing */; *sp >= 0; ++sp)
-         obstack_fgrow1 (oout, " %s", symbols[*sp]->tag);
 -      obstack_printf (oout, " %s", symbols[*sp]->tag);
++        obstack_printf (oout, " %s", symbols[*sp]->tag);
  
        /* Experimental feature: display the lookahead tokens. */
        if (report_flag & report_lookahead_tokens
            && item_number_is_rule_number (*sp1))
 -      {
 -        /* Find the reduction we are handling.  */
 -        reductions *reds = s->reductions;
 -        int redno = state_reduction_find (s, &rules[r]);
 -
 -        /* Print them if there are.  */
 -        if (reds->lookahead_tokens && redno != -1)
 -          {
 -            bitset_iterator biter;
 -            int k;
 -            char const *sep = "";
 -            obstack_sgrow (oout, "[");
 -            BITSET_FOR_EACH (biter, reds->lookahead_tokens[redno], k, 0)
 -              {
 -                obstack_printf (oout, "%s%s", sep, symbols[k]->tag);
 -                sep = ", ";
 -              }
 -            obstack_sgrow (oout, "]");
 -          }
 -      }
 +        {
 +          /* Find the reduction we are handling.  */
 +          reductions *reds = s->reductions;
 +          int redno = state_reduction_find (s, &rules[r]);
 +
 +          /* Print them if there are.  */
 +          if (reds->lookahead_tokens && redno != -1)
 +            {
 +              bitset_iterator biter;
 +              int k;
 +              char const *sep = "";
 +              obstack_sgrow (oout, "[");
 +              BITSET_FOR_EACH (biter, reds->lookahead_tokens[redno], k, 0)
 +                {
-                   obstack_fgrow2 (oout, "%s%s", sep, symbols[k]->tag);
++                  obstack_printf (oout, "%s%s", sep, symbols[k]->tag);
 +                  sep = ", ";
 +                }
 +              obstack_sgrow (oout, "]");
 +            }
 +        }
      }
  }
  
@@@ -123,21 -123,21 +123,21 @@@ print_actions (state const *s, FILE *fg
    for (i = 0; i < trans->num; i++)
      if (!TRANSITION_IS_DISABLED (trans, i))
        {
 -      state *s1 = trans->states[i];
 -      symbol_number sym = s1->accessing_symbol;
 -
 -      /* Shifts are solid, gotos are dashed, and error is dotted.  */
 -      char const *style =
 -        (TRANSITION_IS_ERROR (trans, i) ? "dotted"
 -         : TRANSITION_IS_SHIFT (trans, i) ? "solid"
 -         : "dashed");
 -
 -      if (TRANSITION_IS_ERROR (trans, i)
 -          && strcmp (symbols[sym]->tag, "error") != 0)
 -        abort ();
 -      output_edge (s->number, s1->number,
 -                   TRANSITION_IS_ERROR (trans, i) ? NULL : symbols[sym]->tag,
 -                   style, fgraph);
 +        state *s1 = trans->states[i];
 +        symbol_number sym = s1->accessing_symbol;
 +
 +        /* Shifts are solid, gotos are dashed, and error is dotted.  */
 +        char const *style =
 +          (TRANSITION_IS_ERROR (trans, i) ? "dotted"
 +           : TRANSITION_IS_SHIFT (trans, i) ? "solid"
 +           : "dashed");
 +
 +        if (TRANSITION_IS_ERROR (trans, i)
 +            && STRNEQ (symbols[sym]->tag, "error"))
 +          abort ();
 +        output_edge (s->number, s1->number,
 +                     TRANSITION_IS_ERROR (trans, i) ? NULL : symbols[sym]->tag,
 +                     style, fgraph);
        }
  }
  
diff --combined src/scan-code.l
index 2fe880ed6a371d03215cc19af83d16320a6759e7,fa593beb8da889aeeb3c9685dacf0497f7422508..83501475fe9107292fe1fb1d03c5b945e711f4df
  #define code_wrap() 1
  
  #define FLEX_PREFIX(Id) code_ ## Id
 -#include "flex-scanner.h"
 +#include <src/flex-scanner.h>
  
 -#include "complain.h"
 -#include "reader.h"
 -#include "getargs.h"
 -#include "scan-code.h"
 -#include "symlist.h"
 +#include <src/complain.h>
 +#include <src/reader.h>
 +#include <src/getargs.h>
 +#include <src/muscle-tab.h>
 +#include <src/scan-code.h>
 +#include <src/symlist.h>
  
  #include <c-ctype.h>
  #include <get-errno.h>
@@@ -51,7 -50,7 +51,7 @@@ static char *fetch_type_name (char *cp
                                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. */
@@@ -79,17 -78,17 +79,17 @@@ static bool untyped_var_seen
  /* POSIX says that a tag must be both an id and a C union member, but
     historically almost any character is allowed in a tag.  We disallow
     NUL and newline, as this simplifies our implementation.  */
 -tag    [^\0\n>]+
 +tag      [^\0\n>]+
  
  /* Zero or more instances of backslash-newline.  Following GCC, allow
     white space between the backslash and the newline.  */
 -splice         (\\[ \f\t\v]*\n)*
 +splice   (\\[ \f\t\v]*\n)*
  
  /* C style identifier. Must start with letter. Will be used for
     named symbol references. Shall be kept synchronized with
     scan-gram.l "letter" and "id". */
 -letter          [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
 -id      {letter}({letter}|[-0-9])*
 +letter    [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
 +id        {letter}({letter}|[-0-9])*
  ref      -?[0-9]+|{id}|"["{id}"]"|"$"
  
  %%
       is expected to return only once.  This initialization is
       therefore done once per action to translate. */
    aver (sc_context == SC_SYMBOL_ACTION
 -      || sc_context == SC_RULE_ACTION
 -      || sc_context == INITIAL);
 +        || sc_context == SC_RULE_ACTION
 +        || sc_context == INITIAL);
    BEGIN sc_context;
  %}
  
  
  <SC_LINE_COMMENT>
  {
 -  "\n"                 STRING_GROW; BEGIN sc_context;
 -  {splice}     STRING_GROW;
 +  "\n"           STRING_GROW; BEGIN sc_context;
 +  {splice}       STRING_GROW;
  }
  
  
  
  <SC_CHARACTER,SC_STRING>
  {
 -  {splice}|\\{splice}.        STRING_GROW;
 +  {splice}|\\{splice}.  STRING_GROW;
  }
  
  <SC_CHARACTER>
  {
 -  "'"         STRING_GROW; BEGIN sc_context;
 +  "'"           STRING_GROW; BEGIN sc_context;
  }
  
  <SC_STRING>
  {
 -  "\""                STRING_GROW; BEGIN sc_context;
 +  "\""          STRING_GROW; BEGIN sc_context;
  }
  
  
      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;
    }
      if (outer_brace && !yacc_flag && language_prio == default_prio
          && skeleton_prio == default_prio && need_semicolon && ! in_cpp)
        {
 -        warn_at (*loc, _("a ';' might be needed at the end of action code"));
 -        warn_at (*loc, _("future versions of Bison will not add the ';'"));
 +        complain_at (*loc, Wother,
 +                     _("a ';' might be needed at the end of action code"));
 +        complain_at (*loc, Wother,
 +                     _("future versions of Bison will not add the ';'"));
          obstack_1grow (&obstack_for_string, ';');
        }
  
    {splice}  STRING_GROW;
    [\n\r]    STRING_GROW; if (in_cpp) in_cpp = need_semicolon = false;
    [ \t\f]   STRING_GROW;
 -
 -  /* YYFAIL is undocumented and was formally deprecated in Bison
 -     2.4.2.  */
 -  YYFAIL {
 -    STRING_GROW; need_semicolon = true;
 -    warn_at (*loc, _("use of YYFAIL, which is deprecated and will be"
 -                     " removed"));
 -  }
 -
 -  /* The sole purpose of this is to make sure identifiers that merely
 -     contain YYFAIL don't produce the above warning.  */
 -  [A-Za-z_][0-9A-Za-z_]* STRING_GROW; need_semicolon = true;
 -
 -  . STRING_GROW; need_semicolon = true;
 +  .         STRING_GROW; need_semicolon = true;
  }
  
  <SC_SYMBOL_ACTION>
    }
    "@$" {
      obstack_sgrow (&obstack_for_string, "]b4_at_dollar[");
 -    locations_flag = true;
 +    muscle_percent_define_ensure("locations", the_location, true);
    }
  }
  
    /* By default, grow the string obstack with the input.  */
    .|\n        STRING_GROW;
  
 -  /* End of processing. */
 + /* End of processing. */
    <<EOF>>     STRING_FINISH; return last_string;
  }
  
@@@ -335,9 -345,9 +335,9 @@@ variant_table_grow (void
    if (variant_count > variant_table_size)
      {
        while (variant_count > variant_table_size)
 -      variant_table_size = 2 * variant_table_size + 3;
 +        variant_table_size = 2 * variant_table_size + 3;
        variant_table = xnrealloc (variant_table, variant_table_size,
 -                               sizeof *variant_table);
 +                                 sizeof *variant_table);
      }
    return &variant_table[variant_count - 1];
  }
@@@ -367,7 -377,7 +367,7 @@@ find_prefix_end (const char *prefix, ch
  
  static variant *
  variant_add (uniqstr id, location id_loc, unsigned symbol_index,
 -           char *cp, char *cp_end, bool explicit_bracketing)
 +             char *cp, char *cp_end, bool explicit_bracketing)
  {
    char *prefix_end;
  
  }
  
  static const char *
 -get_at_spec (unsigned symbol_index)
 +get_at_spec(unsigned symbol_index)
  {
    static char at_buf[20];
    if (symbol_index == 0)
@@@ -414,62 -424,60 +414,62 @@@ show_sub_messages (const char* cp, boo
        if (var->err == 0)
          {
            if (is_warning)
 -            warn_at_indent (var->loc, &indent, _("refers to: %c%s at %s"),
 -                            dollar_or_at, var->id, at_spec);
 +            complain_at_indent (var->loc, Wother, &indent,
 +                                _("refers to: %c%s at %s"), dollar_or_at,
 +                                var->id, at_spec);
            else
 -            complain_at_indent (var->loc, &indent, _("refers to: %c%s at %s"),
 -                                dollar_or_at, var->id, at_spec);
 +            complain_at_indent (var->loc, complaint, &indent,
 +                                _("refers to: %c%s at %s"), dollar_or_at,
 +                                var->id, at_spec);
          }
        else
 -      {
 -        static struct obstack msg_buf;
 -        const char *tail = explicit_bracketing ? "" :
 -          cp + strlen (var->id);
 -        const char *id = var->hidden_by ? var->hidden_by->id :
 -          var->id;
 -        location id_loc = var->hidden_by ? var->hidden_by->loc :
 -          var->loc;
 -
 -        /* Create the explanation message. */
 -        obstack_init (&msg_buf);
 -
 -        obstack_printf (&msg_buf, _("possibly meant: %c"), dollar_or_at);
 -        if (contains_dot_or_dash (id))
 -          obstack_printf (&msg_buf, "[%s]", id);
 -        else
 -          obstack_sgrow (&msg_buf, id);
 -        obstack_sgrow (&msg_buf, tail);
 -
 -        if (var->err & VARIANT_HIDDEN)
 -          {
 -            obstack_printf (&msg_buf, _(", hiding %c"), dollar_or_at);
 -            if (contains_dot_or_dash (var->id))
 -              obstack_printf (&msg_buf, "[%s]", var->id);
 -            else
 -              obstack_sgrow (&msg_buf, var->id);
 -            obstack_sgrow (&msg_buf, tail);
 -          }
 -
 -        obstack_printf (&msg_buf, _(" at %s"), at_spec);
 -
 -        if (var->err & VARIANT_NOT_VISIBLE_FROM_MIDRULE)
 +        {
 +          static struct obstack msg_buf;
 +          const char *tail = explicit_bracketing ? "" :
 +            cp + strlen (var->id);
 +          const char *id = var->hidden_by ? var->hidden_by->id :
 +            var->id;
 +          location id_loc = var->hidden_by ? var->hidden_by->loc :
 +            var->loc;
 +
 +          /* Create the explanation message. */
 +          obstack_init (&msg_buf);
 +
-           obstack_fgrow1 (&msg_buf, _("possibly meant: %c"), dollar_or_at);
++          obstack_printf (&msg_buf, _("possibly meant: %c"), dollar_or_at);
 +          if (contains_dot_or_dash (id))
-             obstack_fgrow1 (&msg_buf, "[%s]", id);
++            obstack_printf (&msg_buf, "[%s]", id);
 +          else
 +            obstack_sgrow (&msg_buf, id);
 +          obstack_sgrow (&msg_buf, tail);
 +
 +          if (var->err & VARIANT_HIDDEN)
 +            {
-               obstack_fgrow1 (&msg_buf, _(", hiding %c"), dollar_or_at);
++              obstack_printf (&msg_buf, _(", hiding %c"), dollar_or_at);
 +              if (contains_dot_or_dash (var->id))
-                 obstack_fgrow1 (&msg_buf, "[%s]", var->id);
++                obstack_printf (&msg_buf, "[%s]", var->id);
 +              else
 +                obstack_sgrow (&msg_buf, var->id);
 +              obstack_sgrow (&msg_buf, tail);
 +            }
 +
-           obstack_fgrow1 (&msg_buf, _(" at %s"), at_spec);
++          obstack_printf (&msg_buf, _(" at %s"), at_spec);
 +
 +          if (var->err & VARIANT_NOT_VISIBLE_FROM_MIDRULE)
              {
                const char *format =
                  _(", cannot be accessed from mid-rule action at $%d");
-               obstack_fgrow1 (&msg_buf, format, midrule_rhs_index);
+               obstack_printf (&msg_buf, format, midrule_rhs_index);
              }
  
 -        obstack_1grow (&msg_buf, '\0');
 +          obstack_1grow (&msg_buf, '\0');
            if (is_warning)
 -            warn_at_indent (id_loc, &indent, "%s",
 -                            (char *) obstack_finish (&msg_buf));
 +            complain_at_indent (id_loc, Wother, &indent, "%s",
 +                                (char *) obstack_finish (&msg_buf));
            else
 -            complain_at_indent (id_loc, &indent, "%s",
 +            complain_at_indent (id_loc, complaint, &indent, "%s",
                                  (char *) obstack_finish (&msg_buf));
 -        obstack_free (&msg_buf, 0);
 -      }
 +          obstack_free (&msg_buf, 0);
 +        }
      }
  }
  
     accesses. */
  static long int
  parse_ref (char *cp, symbol_list *rule, int rule_length,
 -         int midrule_rhs_index, char *text, location text_loc,
 -         char dollar_or_at)
 +           int midrule_rhs_index, char *text, location text_loc,
 +           char dollar_or_at)
  {
    symbol_list *l;
    char *cp_end;
      {
        long int num = strtol (cp, &cp, 10);
        if (1 - INT_MAX + rule_length <= num && num <= rule_length)
 -      return num;
 +        return num;
        else
 -      {
 -        complain_at (text_loc, _("integer out of range: %s"),
 +        {
 +          complain_at (text_loc, complaint, _("integer out of range: %s"),
                         quote (text));
 -        return INVALID_REF;
 -      }
 +          return INVALID_REF;
 +        }
      }
  
    if ('[' == *cp)
        /* Ignore the brackets. */
        char *p;
        for (p = ++cp; *p != ']'; ++p)
 -      continue;
 +        continue;
        cp_end = p;
  
        explicit_bracketing = true;
        /* Take all characters of the name. */
        char* p;
        for (p = cp; *p; ++p)
 -      if (is_dot_or_dash (*p))
 -        {
 -          ref_tail_fields = p;
 -          break;
 -        }
 +        if (is_dot_or_dash (*p))
 +          {
 +            ref_tail_fields = p;
 +            break;
 +          }
        for (p = cp; *p; ++p)
 -      continue;
 +        continue;
        cp_end = p;
  
        explicit_bracketing = false;
      for (symbol_index = 0, l = rule; !symbol_list_null (l);
           ++symbol_index, l = l->next)
        {
 -      variant *var;
 -      if (l->content_type != SYMLIST_SYMBOL)
 -        continue;
 +        variant *var;
 +        if (l->content_type != SYMLIST_SYMBOL)
 +          continue;
  
 -      var = variant_add (l->content.sym->tag, l->sym_loc,
 +        var = variant_add (l->content.sym->tag, l->sym_loc,
                             symbol_index, cp, cp_end, explicit_bracketing);
 -      if (var && l->named_ref)
 -        var->hidden_by = l->named_ref;
 +        if (var && l->named_ref)
 +          var->hidden_by = l->named_ref;
  
 -      if (l->named_ref)
 -        variant_add (l->named_ref->id, l->named_ref->loc,
 +        if (l->named_ref)
 +          variant_add (l->named_ref->id, l->named_ref->loc,
                         symbol_index, cp, cp_end, explicit_bracketing);
        }
    }
  
        /* Check visibility from mid-rule actions. */
        if (midrule_rhs_index != 0
 -        && (symbol_index == 0 || midrule_rhs_index < symbol_index))
 +          && (symbol_index == 0 || midrule_rhs_index < symbol_index))
          var->err |= VARIANT_NOT_VISIBLE_FROM_MIDRULE;
  
        /* Check correct bracketing. */
            cp_end - cp : ref_tail_fields - cp;
          unsigned indent = 0;
  
 -        complain_at_indent (text_loc, &indent, _("invalid reference: %s"),
 -                            quote (text));
 +        complain_at_indent (text_loc, complaint, &indent,
 +                            _("invalid reference: %s"), quote (text));
          indent += SUB_INDENT;
          if (len == 0)
            {
              const char *format =
                _("syntax error after '%c', expecting integer, letter,"
                  " '_', '[', or '$'");
 -            complain_at_indent (sym_loc, &indent, format, dollar_or_at);
 +            complain_at_indent (sym_loc, complaint, &indent, format,
 +                                dollar_or_at);
            }
          else if (midrule_rhs_index)
            {
              const char *format =
                _("symbol not found in production before $%d: %.*s");
 -            complain_at_indent (rule->location, &indent, format,
 +            complain_at_indent (rule->location, complaint, &indent, format,
                                  midrule_rhs_index, len, cp);
            }
          else
            {
              const char *format =
                _("symbol not found in production: %.*s");
 -            complain_at_indent (rule->location, &indent, format,
 +            complain_at_indent (rule->location, complaint, &indent, format,
                                  len, cp);
            }
  
          unsigned indent = 0;
          if (variant_count > 1)
            {
 -            warn_at_indent (text_loc, &indent, _("misleading reference: %s"),
 -                            quote (text));
 +            complain_at_indent (text_loc, Wother, &indent,
 +                                _("misleading reference: %s"), quote (text));
              show_sub_messages (cp, explicit_bracketing, midrule_rhs_index,
                                 dollar_or_at, true, indent + SUB_INDENT);
            }
      default:
        {
          unsigned indent = 0;
 -        complain_at_indent (text_loc, &indent, _("ambiguous reference: %s"),
 -                            quote (text));
 +        complain_at_indent (text_loc, complaint, &indent,
 +                            _("ambiguous reference: %s"), quote (text));
          show_sub_messages (cp, explicit_bracketing, midrule_rhs_index,
                             dollar_or_at, false, indent + SUB_INDENT);
          return INVALID_REF;
@@@ -683,14 -690,13 +683,14 @@@ fetch_type_name (char *cp, char const *
      {
        *type_name = ++cp;
        while (*cp != '>')
 -      ++cp;
 +        ++cp;
  
        /* The '>' symbol will be later replaced by '\0'. Original
 -       'text' is needed for error messages. */
 +         'text' is needed for error messages. */
        ++cp;
        if (untyped_var_seen)
 -      complain_at (dollar_loc, _("explicit type given in untyped grammar"));
 +        complain_at (dollar_loc, complaint,
 +                     _("explicit type given in untyped grammar"));
        tag_seen = true;
      }
    return cp;
@@@ -728,7 -734,7 +728,7 @@@ handle_action_dollar (symbol_list *rule
    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, '$');
  
    /* End type_name. */
    if (type_name)
  
      case LHS_REF:
        if (!type_name)
 -      type_name = symbol_list_n_type_name_get (rule, dollar_loc, 0);
 +        type_name = symbol_list_n_type_name_get (rule, dollar_loc, 0);
  
        if (!type_name)
          {
            if (union_seen | tag_seen)
              {
                if (rule->midrule_parent_rule)
 -                complain_at (dollar_loc,
 +                complain_at (dollar_loc, complaint,
                               _("$$ for the midrule at $%d of %s"
                                 " has no declared type"),
                               rule->midrule_parent_rhs_index,
                               quote (effective_rule->content.sym->tag));
                else
 -                complain_at (dollar_loc, _("$$ of %s has no declared type"),
 +                complain_at (dollar_loc, complaint,
 +                             _("$$ of %s has no declared type"),
                               quote (rule->content.sym->tag));
              }
            else
  
      default:
        if (max_left_semantic_context < 1 - n)
 -      max_left_semantic_context = 1 - n;
 +        max_left_semantic_context = 1 - n;
        if (!type_name && 0 < n)
 -      type_name =
 -        symbol_list_n_type_name_get (effective_rule, dollar_loc, n);
 +        type_name =
 +          symbol_list_n_type_name_get (effective_rule, dollar_loc, 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;
          }
  
-       obstack_fgrow2 (&obstack_for_string,
+       obstack_printf (&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;
      }
  }
@@@ -820,10 -824,10 +820,10 @@@ handle_action_at (symbol_list *rule, ch
        effective_rule_length = symbol_list_length (rule->next);
      }
  
 -  locations_flag = true;
 +  muscle_percent_define_ensure("locations", at_loc, true);
  
    n = parse_ref (cp, effective_rule, effective_rule_length,
 -                 rule->midrule_parent_rhs_index, text, at_loc, '@');
 +                       rule->midrule_parent_rhs_index, text, at_loc, '@');
    switch (n)
      {
      case INVALID_REF:
        break;
  
      default:
-       obstack_fgrow2 (&obstack_for_string, "]b4_rhs_location(%d, %d)[",
+       obstack_printf (&obstack_for_string, "]b4_rhs_location(%d, %d)[",
 -                    effective_rule_length, n);
 +                      effective_rule_length, n);
        break;
      }
  }
@@@ -878,40 -882,43 +878,40 @@@ code_props_none_init (code_props *self
    *self = code_props_none;
  }
  
 -code_props const code_props_none = CODE_PROPS_NONE_INIT;
 +code_props code_props_none = CODE_PROPS_NONE_INIT;
  
  void
  code_props_plain_init (code_props *self, char const *code,
 -                     location code_loc)
 +                       location code_loc)
  {
 +  code_props_none_init (self);
    self->kind = CODE_PROPS_PLAIN;
    self->code = code;
    self->location = code_loc;
 -  self->is_value_used = false;
 -  self->rule = NULL;
 -  self->named_ref = NULL;
  }
  
  void
  code_props_symbol_action_init (code_props *self, char const *code,
                                 location code_loc)
  {
 +  code_props_none_init (self);
    self->kind = CODE_PROPS_SYMBOL_ACTION;
    self->code = code;
    self->location = code_loc;
 -  self->is_value_used = false;
 -  self->rule = NULL;
 -  self->named_ref = NULL;
  }
  
  void
  code_props_rule_action_init (code_props *self, char const *code,
                               location code_loc, symbol_list *rule,
 -                           named_ref *name)
 +                             named_ref *name, bool is_predicate)
  {
 +  code_props_none_init (self);
    self->kind = CODE_PROPS_RULE_ACTION;
    self->code = code;
    self->location = code_loc;
 -  self->is_value_used = false;
    self->rule = rule;
    self->named_ref = name;
 +  self->is_predicate = is_predicate;
  }
  
  void
diff --combined src/scan-skel.l
index b79e58323e0cc2a95fc1232c6437ed2a56099151,ed61b5c80e5682cac96134b42c8dbd6ad95529fa..32bfe7374914ef6602a51482c7049c653bbefbab
@@@ -1,6 -1,6 +1,6 @@@
  /* Scan Bison Skeletons.                                       -*- C -*-
  
 -   Copyright (C) 2001-2007, 2009-2012 Free Software Foundation, Inc.
 +   Copyright (C) 2001-2012 Free Software Foundation, Inc.
  
     This file is part of Bison, the GNU Compiler Compiler.
  
  #define skel_wrap() 1
  
  #define FLEX_PREFIX(Id) skel_ ## Id
 -#include "flex-scanner.h"
 +#include <src/flex-scanner.h>
  
  #include <dirname.h>
  #include <error.h>
  #include <quotearg.h>
  
 -#include "complain.h"
 -#include "getargs.h"
 -#include "files.h"
 -#include "scan-skel.h"
 +#include <src/complain.h>
 +#include <src/getargs.h>
 +#include <src/files.h>
 +#include <src/scan-skel.h>
  
  #define YY_DECL static int skel_lex (void)
  YY_DECL;
@@@ -87,11 -87,11 +87,11 @@@ static void fail_for_invalid_at (char c
  }
  
    /* 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;
  
- <<EOF>> {
+ <INITIAL><<EOF>> {
    if (outname)
      {
        free (outname);
  <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>
  {
    <<EOF>> {
 -    fatal (_("unclosed %s directive in skeleton"), at_directive_argv[0]);
 +    complain (fatal, _("unclosed %s directive in skeleton"),
 +              at_directive_argv[0]);
    }
  }
  
@@@ -181,98 -180,94 +181,98 @@@ at_directive_perform (int at_directive_
                        char *at_directive_argv[],
                        char **outnamep, int *out_linenop)
  {
 -  if (0 == strcmp (at_directive_argv[0], "@basename"))
 +  if (STREQ (at_directive_argv[0], "@basename"))
      {
        if (at_directive_argc > 2)
          fail_for_at_directive_too_many_args (at_directive_argv[0]);
        fputs (last_component (at_directive_argv[1]), yyout);
      }
 -  else if (0 == strcmp (at_directive_argv[0], "@warn")
 -           || 0 == strcmp (at_directive_argv[0], "@complain")
 -           || 0 == strcmp (at_directive_argv[0], "@fatal"))
 +  else if (STREQ (at_directive_argv[0], "@warn")
 +           || STREQ (at_directive_argv[0], "@complain")
 +           || STREQ (at_directive_argv[0], "@fatal"))
      {
 -      void (*func)(char const *, ...);
 +      warnings complaint_flag;
        switch (at_directive_argv[0][1])
          {
 -          case 'w': func = warn; break;
 -          case 'c': func = complain; break;
 -          case 'f': func = fatal; break;
 -          default: aver (false); break;
 +        case 'w': complaint_flag = Wother; break;
 +        case 'c': complaint_flag = complaint; break;
 +        case 'f': complaint_flag = fatal; break;
 +        default: aver (false); break;
          }
        switch (at_directive_argc)
          {
            case 2:
 -            func (_(at_directive_argv[1]));
 +            complain (complaint_flag, "%s", _(at_directive_argv[1]));
              break;
            case 3:
 -            func (_(at_directive_argv[1]), at_directive_argv[2]);
 +            complain (complaint_flag, _(at_directive_argv[1]),
 +                      at_directive_argv[2]);
              break;
            case 4:
 -            func (_(at_directive_argv[1]), at_directive_argv[2],
 -                  at_directive_argv[3]);
 +            complain (complaint_flag, _(at_directive_argv[1]),
 +                      at_directive_argv[2], at_directive_argv[3]);
              break;
            case 5:
 -            func (_(at_directive_argv[1]), at_directive_argv[2],
 -                  at_directive_argv[3], at_directive_argv[4]);
 +            complain (complaint_flag, _(at_directive_argv[1]),
 +                      at_directive_argv[2], at_directive_argv[3],
 +                      at_directive_argv[4]);
              break;
            case 6:
 -            func (_(at_directive_argv[1]), at_directive_argv[2],
 -                  at_directive_argv[3], at_directive_argv[4],
 -                  at_directive_argv[5]);
 +            complain (complaint_flag, _(at_directive_argv[1]),
 +                      at_directive_argv[2], at_directive_argv[3],
 +                      at_directive_argv[4], at_directive_argv[5]);
              break;
            default:
              fail_for_at_directive_too_many_args (at_directive_argv[0]);
              break;
          }
      }
 -  else if (0 == strcmp (at_directive_argv[0], "@warn_at")
 -           || 0 == strcmp (at_directive_argv[0], "@complain_at")
 -           || 0 == strcmp (at_directive_argv[0], "@fatal_at"))
 +  else if (STREQ (at_directive_argv[0], "@warn_at")
 +           || STREQ (at_directive_argv[0], "@complain_at")
 +           || STREQ (at_directive_argv[0], "@fatal_at"))
      {
 -      void (*func)(location, char const *, ...);
 +      warnings complaint_flag;
        location loc;
        if (at_directive_argc < 4)
          fail_for_at_directive_too_few_args (at_directive_argv[0]);
        switch (at_directive_argv[0][1])
          {
 -          case 'w': func = warn_at; break;
 -          case 'c': func = complain_at; break;
 -          case 'f': func = fatal_at; break;
 -          default: aver (false); break;
 +        case 'w': complaint_flag = Wother; break;
 +        case 'c': complaint_flag = complaint; break;
 +        case 'f': complaint_flag = fatal; break;
 +        default: aver (false); break;
          }
        boundary_set_from_string (&loc.start, at_directive_argv[1]);
        boundary_set_from_string (&loc.end, at_directive_argv[2]);
        switch (at_directive_argc)
          {
            case 4:
 -            func (loc, _(at_directive_argv[3]));
 +            complain_at (loc, complaint_flag, "%s", _(at_directive_argv[3]));
              break;
            case 5:
 -            func (loc, _(at_directive_argv[3]), at_directive_argv[4]);
 +            complain_at (loc, complaint_flag, _(at_directive_argv[3]),
 +                      at_directive_argv[4]);
              break;
            case 6:
 -            func (loc, _(at_directive_argv[3]), at_directive_argv[4],
 -                  at_directive_argv[5]);
 +            complain_at (loc, complaint_flag, _(at_directive_argv[3]),
 +                      at_directive_argv[4], at_directive_argv[5]);
              break;
            case 7:
 -            func (loc, _(at_directive_argv[3]), at_directive_argv[4],
 -                  at_directive_argv[5], at_directive_argv[6]);
 +            complain_at (loc, complaint_flag, _(at_directive_argv[3]),
 +                      at_directive_argv[4], at_directive_argv[5],
 +                      at_directive_argv[6]);
              break;
            case 8:
 -            func (loc, _(at_directive_argv[3]), at_directive_argv[4],
 -                  at_directive_argv[5], at_directive_argv[6],
 -                  at_directive_argv[7]);
 +            complain_at (loc, complaint_flag, _(at_directive_argv[3]),
 +                      at_directive_argv[4], at_directive_argv[5],
 +                      at_directive_argv[6], at_directive_argv[7]);
              break;
            default:
              fail_for_at_directive_too_many_args (at_directive_argv[0]);
              break;
          }
      }
 -  else if (0 == strcmp (at_directive_argv[0], "@output"))
 +  else if (STREQ (at_directive_argv[0], "@output"))
      {
        if (at_directive_argc > 2)
          fail_for_at_directive_too_many_args (at_directive_argv[0]);
  static void
  fail_for_at_directive_too_few_args (char const *at_directive_name)
  {
 -  fatal (_("too few arguments for %s directive in skeleton"),
 +  complain (fatal, _("too few arguments for %s directive in skeleton"),
           at_directive_name);
  }
  
  static void
  fail_for_at_directive_too_many_args (char const *at_directive_name)
  {
 -  fatal (_("too many arguments for %s directive in skeleton"),
 -         at_directive_name);
 +  complain (fatal, _("too many arguments for %s directive in skeleton"),
 +            at_directive_name);
  }
  
  static void
  fail_for_invalid_at (char const *at)
  {
 -  fatal ("invalid @ in skeleton: %s", at);
 +  complain (fatal, "invalid @ in skeleton: %s", at);
  }
diff --combined src/system.h
index 1d0af8fabddb6e7b5c10678dc1288de5c9abd369,1ae6a6b44a5921e9ca8bec6d65fac6eabb1d1b93..a56c058a10360c7d867f350e859844bd7680b864
     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
  
  #ifndef BISON_SYSTEM_H
 -# define BISON_SYSTEM_H
 +#define BISON_SYSTEM_H
  
  /* flex 2.5.31 gratutiously defines macros like INT8_MIN.  But this
     runs afoul of pre-C99 compilers that have <inttypes.h> or
     <stdint.h>, which are included below if available.  It also runs
     afoul of pre-C99 compilers that define these macros in <limits.h>.  */
 -# if ! defined __STDC_VERSION__ || __STDC_VERSION__ < 199901
 -#  undef INT8_MIN
 -#  undef INT16_MIN
 -#  undef INT32_MIN
 -#  undef INT8_MAX
 -#  undef INT16_MAX
 -#  undef UINT8_MAX
 -#  undef INT32_MAX
 -#  undef UINT16_MAX
 -#  undef UINT32_MAX
 -# endif
 -
 -# include <limits.h>
 -# include <stddef.h>
 -# include <stdlib.h>
 -# include <string.h>
 -
 -# if HAVE_SYS_TYPES_H
 -#  include <sys/types.h>
 -# endif
 -
 -# include <unistd.h>
 -# include <inttypes.h>
 -
 -# ifndef UINTPTR_MAX
 +#if ! defined __STDC_VERSION__ || __STDC_VERSION__ < 199901
 +# undef INT8_MIN
 +# undef INT16_MIN
 +# undef INT32_MIN
 +# undef INT8_MAX
 +# undef INT16_MAX
 +# undef UINT8_MAX
 +# undef INT32_MAX
 +# undef UINT16_MAX
 +# undef UINT32_MAX
 +#endif
 +
 +#include <limits.h>
 +#include <stddef.h>
 +#include <stdlib.h>
 +#include <string.h>
 +
 +#define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
 +#define STREQ(L, R)  (strcmp(L, R) == 0)
 +#define STRNEQ(L, R) (!STREQ(L, R))
 +
 +/* Just like strncmp, but the second argument must be a literal string
 +   and you don't specify the length.  */
 +#define STRNCMP_LIT(S, Literal)                         \
 +  strncmp (S, "" Literal "", sizeof (Literal) - 1)
 +
 +/* Whether Literal is a prefix of S.  */
 +#define STRPREFIX_LIT(Literal, S)               \
 +  (STRNCMP_LIT (S, Literal) == 0)
 +
 +#if HAVE_SYS_TYPES_H
 +# include <sys/types.h>
 +#endif
 +
 +#include <unistd.h>
 +#include <inttypes.h>
 +
 +#ifndef UINTPTR_MAX
  /* This isn't perfect, but it's good enough for Bison, which needs
     only to hash pointers.  */
  typedef size_t uintptr_t;
 -# endif
 +#endif
  
  // Version mismatch.
 -# define EX_MISMATCH 63
 +#define EX_MISMATCH 63
  
  /*---------.
  | Gnulib.  |
  `---------*/
  
 -# include <unlocked-io.h>
 -# include <verify.h>
 -# include <xalloc.h>
 +#include <unlocked-io.h>
 +#include <verify.h>
 +#include <xalloc.h>
  
  
  /*-----------------.
     and safer logic than it would for users.  Due to the overhead of M4,
     suppressing Code is unlikely to offer any significant improvement in
     Bison's performance anyway.  */
 -# define PACIFY_CC(Code) Code
 +#define PACIFY_CC(Code) Code
  
 -# ifndef __attribute__
 +#ifndef __attribute__
  /* This feature is available in gcc versions 2.5 and later.  */
 -#  if (! defined __GNUC__ || __GNUC__ < 2 \
 +# if (! defined __GNUC__ || __GNUC__ < 2 \
         || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
 -#   define __attribute__(Spec) /* empty */
 -#  endif
 +#  define __attribute__(Spec) /* empty */
  # endif
 +#endif
  
  /* The __-protected variants of `format' and `printf' attributes
     are accepted by gcc versions 2.6.4 (effectively 2.7) and later.  */
 -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
 -#  define __format__ format
 -#  define __printf__ printf
 -# endif
 +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
 +# define __format__ format
 +# define __printf__ printf
 +#endif
  
 -# ifndef ATTRIBUTE_NORETURN
 -#  define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
 -# endif
 +#ifndef ATTRIBUTE_NORETURN
 +# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
 +#endif
  
 -# ifndef ATTRIBUTE_UNUSED
 -#  define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
 -# endif
 +#ifndef ATTRIBUTE_UNUSED
 +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
 +#endif
  
 -# define FUNCTION_PRINT() fprintf (stderr, "%s: ", __func__)
 +#define FUNCTION_PRINT() fprintf (stderr, "%s: ", __func__)
  
  /*------.
  | NLS.  |
  `------*/
  
 -# include <locale.h>
 +#include <locale.h>
  
 -# include <gettext.h>
 -# define _(Msgid)  gettext (Msgid)
 -# define N_(Msgid) (Msgid)
 +#include <gettext.h>
 +#define _(Msgid)  gettext (Msgid)
 +#define N_(Msgid) (Msgid)
  
  
  /*-----------.
  | Booleans.  |
  `-----------*/
  
 -# include <stdbool.h>
 +#include <stdbool.h>
  
  
  
     For now, we use assert but we call it aver throughout Bison in case
     we later wish to try another scheme.
  */
 -# include <assert.h>
 -# define aver assert
 +#include <assert.h>
 +#define aver assert
  
  
  /*-----------.
  | 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)       \
-   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));      \
-   } while (0)
- #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)
- #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)
  /* Output Str escaped for our postprocessing (i.e., escape M4 special
     characters).
  
  
  # 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)
  
  | 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
  
  
  
  | Free a linked list.  |
  `---------------------*/
  
 -# define LIST_FREE(Type, List)                  \
 -  do {                                          \
 -    Type *_node, *_next;                        \
 -    for (_node = List; _node; _node = _next)    \
 -      {                                         \
 -        _next = _node->next;                    \
 -        free (_node);                           \
 -      }                                         \
 -  } while (0)
 +#define LIST_FREE(Type, List)                   \
 +do {                                            \
 +  Type *_node, *_next;                          \
 +  for (_node = List; _node; _node = _next)      \
 +    {                                           \
 +      _next = _node->next;                      \
 +      free (_node);                             \
 +    }                                           \
 +} while (0)
  
  
  /*---------------------------------------------.
diff --combined tests/actions.at
index 16711ddd91d8fda554efbb2c62d75b150e060991,1ec8ef9ae408401e4a23ed05bf617c2329bb7f21..269bcce50533a68b3002413d1d54c068e5ba278a
@@@ -1,4 -1,4 +1,4 @@@
 -# Executing Actions.                               -*- Autotest -*-
 +e# Executing Actions.                               -*- Autotest -*-
  
  # Copyright (C) 2001-2012 Free Software Foundation, Inc.
  
@@@ -30,7 -30,7 +30,7 @@@ AT_SETUP([Mid-rule actions]
  
  AT_BISON_OPTION_PUSHDEFS
  AT_DATA_GRAMMAR([[input.y]],
 -[[%error-verbose
 +[[%define parse.error verbose
  %debug
  %{
  ]AT_YYERROR_DECLARE[
@@@ -80,7 -80,7 +80,7 @@@ AT_SETUP([Exotic Dollars]
  
  AT_BISON_OPTION_PUSHDEFS
  AT_DATA_GRAMMAR([[input.y]],
 -[[%error-verbose
 +[[%define parse.error verbose
  %debug
  %{
  ]AT_YYERROR_DECLARE[
@@@ -136,7 -136,7 +136,7 @@@ AT_PARSER_CHECK([./input], 0
  AT_DATA_GRAMMAR([[input.y]],
  [[
  %{
 -#include <stdio.h>
 +# include <stdio.h>
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
    typedef struct { int val; } stype;
@@@ -264,7 -264,7 +264,7 @@@ input
        V(input, $$, @$, ": /* Nothing */\n");
      }
  | line input /* Right recursive to load the stack so that popping at
 -              END can be exercised.  */
 +                END can be exercised.  */
      {
        $$ = 2;
        V(input, $$, @$, ": ");
@@@ -561,7 -561,7 +561,7 @@@ m4_define([AT_CHECK_PRINTER_AND_DESTRUC
  
  $3
  _AT_CHECK_PRINTER_AND_DESTRUCTOR($[1], $[2], $[3], $[4],
 -[%error-verbose
 +[%define parse.error verbose
  %debug
  %verbose
  %locations
@@@ -592,7 -592,7 +592,7 @@@ AT_CHECK_PRINTER_AND_DESTRUCTOR([%glr-p
  AT_SETUP([Default tagless %printer and %destructor])
  AT_BISON_OPTION_PUSHDEFS([%locations])
  AT_DATA_GRAMMAR([[input.y]],
 -[[%error-verbose
 +[[%define parse.error verbose
  %debug
  %locations
  %initial-action {
@@@ -646,10 -646,7 +646,10 @@@ main (void
  }
  ]])
  
 -AT_BISON_CHECK([-o input.c input.y])
 +AT_BISON_CHECK([-o input.c input.y], [], [],
 +[[input.y:27.3-5: warning: useless %destructor for type <*> [-Wother]
 +input.y:27.3-5: warning: useless %printer for type <*> [-Wother]
 +]])
  AT_COMPILE([input])
  AT_PARSER_CHECK([./input], 1,
  [[<> destructor for 'd' @ 4.
@@@ -697,7 -694,7 +697,7 @@@ AT_CLEANU
  AT_SETUP([Default tagged and per-type %printer and %destructor])
  AT_BISON_OPTION_PUSHDEFS
  AT_DATA_GRAMMAR([[input.y]],
 -[[%error-verbose
 +[[%define parse.error verbose
  %debug
  
  %{
@@@ -761,10 -758,7 +761,10 @@@ main (void
  }
  ]])
  
 -AT_BISON_CHECK([-o input.c input.y])
 +AT_BISON_CHECK([-o input.c input.y], [], [],
 +[[input.y:22.3-4: warning: useless %destructor for type <> [-Wother]
 +input.y:22.3-4: warning: useless %printer for type <> [-Wother]
 +]])
  AT_COMPILE([input])
  AT_PARSER_CHECK([./input], 1,
  [[<*>/<field2>/e destructor.
@@@ -823,16 -817,16 +823,16 @@@ AT_CLEANU
  
  AT_SETUP([Default %printer and %destructor for user-defined end token])
  
 -# _AT_CHECK_DEFAULT_PRINTER_AND_DESTRUCTOR_FOR_END_TOKEN(TYPED)
 -# -------------------------------------------------------------
 -m4_define([_AT_CHECK_DEFAULT_PRINTER_AND_DESTRUCTOR_FOR_END_TOKEN],
 +# AT_TEST(TYPED)
 +# --------------
 +m4_pushdef([AT_TEST],
  [m4_if($1, 0,
    [m4_pushdef([kind], []) m4_pushdef([not_kind], [*])],
    [m4_pushdef([kind], [*]) m4_pushdef([not_kind], [])])
  
  AT_BISON_OPTION_PUSHDEFS([%locations])
  AT_DATA_GRAMMAR([[input]]$1[[.y]],
 -[[%error-verbose
 +[[%define parse.error verbose
  %debug
  %locations
  %initial-action {
@@@ -897,17 -891,8 +897,17 @@@ main (void
  ]])
  AT_BISON_OPTION_POPDEFS
  
 -AT_BISON_CHECK([-o input$1.c input$1.y])
 +AT_BISON_CHECK([-o input$1.c input$1.y], [], [],
 +[m4_if([$1], [0],
 +[[input0.y:27.3-5: warning: useless %destructor for type <*> [-Wother]
 +input0.y:27.3-5: warning: useless %printer for type <*> [-Wother]
 +]],
 +[[input1.y:27.3-4: warning: useless %destructor for type <> [-Wother]
 +input1.y:27.3-4: warning: useless %printer for type <> [-Wother]
 +]])])
 +
  AT_COMPILE([input$1])
 +
  AT_PARSER_CHECK([./input$1], 0,
  [[<]]kind[[> for 'E' @ 1.
  <]]kind[[> for 'S' @ 1.
@@@ -930,10 -915,8 +930,10 @@@ m4_popdef([kind]
  m4_popdef([not_kind])
  ])
  
 -_AT_CHECK_DEFAULT_PRINTER_AND_DESTRUCTOR_FOR_END_TOKEN(0)
 -_AT_CHECK_DEFAULT_PRINTER_AND_DESTRUCTOR_FOR_END_TOKEN(1)
 +AT_TEST(0)
 +AT_TEST(1)
 +
 +m4_popdef([AT_TEST])
  
  AT_CLEANUP
  
@@@ -993,10 -976,7 +993,10 @@@ main (void
  ]])
  AT_BISON_OPTION_POPDEFS
  
 -AT_BISON_CHECK([-o input.c input.y])
 +AT_BISON_CHECK([-o input.c input.y], [], [],
 +[[input.y:21.6-8: warning: useless %destructor for type <*> [-Wother]
 +input.y:21.6-8: warning: useless %printer for type <*> [-Wother]
 +]])
  AT_COMPILE([input])
  AT_PARSER_CHECK([./input], [1], [],
  [[Starting parse
@@@ -1095,10 -1075,7 +1095,10 @@@ main (void
  ]])
  AT_BISON_OPTION_POPDEFS
  
 -AT_BISON_CHECK([-o input.c input.y])
 +AT_BISON_CHECK([-o input.c input.y], [], [],
 +[[input.y:22.3-4: warning: useless %destructor for type <> [-Wother]
 +input.y:22.3-4: warning: useless %printer for type <> [-Wother]
 +]])
  AT_COMPILE([input])
  
  AT_CLEANUP
@@@ -1155,10 -1132,8 +1155,10 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([-o input.c input.y], 0,,
 -[[input.y:33.3-23: warning: unset value: $$
 -input.y:30.3-35.37: warning: unused value: $3
 +[[input.y:24.70-72: warning: useless %destructor for type <*> [-Wother]
 +input.y:24.70-72: warning: useless %printer for type <*> [-Wother]
 +input.y:33.3-23: warning: unset value: $$ [-Wother]
 +input.y:30.3-35.37: warning: unused value: $3 [-Wother]
  ]])
  
  AT_COMPILE([input])
@@@ -1273,16 -1248,15 +1273,14 @@@ AT_CHECK_ACTION_LOCATIONS([[%printer]]
  m4_pushdef([AT_TEST],
  [AT_SETUP([[Qualified $$ in actions: $1]])
  
 -AT_BISON_OPTION_PUSHDEFS([%locations %skeleton "$1"])
 +AT_BISON_OPTION_PUSHDEFS([%skeleton "$1"])
  
  AT_DATA_GRAMMAR([[input.y]],
  [[%skeleton "$1"
 -%defines   // FIXME: Mandated by lalr1.cc in Bison 2.6.
 -%locations // FIXME: Mandated by lalr1.cc in Bison 2.6.
 +%defines   // FIXME: Mandated by glr.cc.
  %debug
  %code requires
  {
- # include <stdio.h>
    typedef struct sem_type
    {
      int ival;
  
  # define YYSTYPE sem_type
  
- #ifdef __cplusplus
+ ]AT_SKEL_CC_IF([[
  # include <iostream>
    static void
    report (std::ostream& yyo, int ival, float fval)
    {
      yyo << "ival: " << ival << ", fval: " <<  fval;
    }
- #else
+ ]], [[
+ # include <stdio.h>
    static void
    report (FILE* yyo, int ival, float fval)
    {
      fprintf (yyo, "ival: %d, fval: %1.1f", ival, fval);
    }
- #endif
+ ]])[
  }
  
  %code
  %printer { report (yyo, $<ival>$, $$      ); } <fval>;
  %printer { report (yyo, $<ival>$, $<fval>$); } <>;
  
 -]AT_SKEL_CC_IF([[
 -/* The lalr1.cc skeleton, for backward compatibility, defines
 -   a constructor for position that initializes the filename.  The
 -   glr.cc skeleton does not (and in fact cannot: location/position
 -   are stored in a union, from which objects with constructors are
 -   excluded in C++). */
 -%initial-action {
 -  @$.initialize ();
 -}
 -]])[
 -
  %initial-action
  {
    $<ival>$ = 42;
@@@ -1354,7 -1340,10 +1353,7 @@@ AT_FULL_COMPILE([[input]]
  AT_PARSER_CHECK([./input], 0, [], [stderr])
  # Don't be too picky on the traces, GLR is not exactly the same.  Keep
  # only the lines from the printer.
 -#
 -# Don't care about locations.  FIXME: remove their removal when Bison
 -# supports C++ without locations.
 -AT_CHECK([[sed -ne 's/([-0-9.]*: /(/;/ival:/p' stderr]], 0,
 +AT_CHECK([[sed -ne '/ival:/p' stderr]], 0,
  [[Reading a token: Next token is token UNTYPED (ival: 10, fval: 0.1)
  Shifting token UNTYPED (ival: 10, fval: 0.1)
  Reading a token: Next token is token INT (ival: 20, fval: 0.2)
@@@ -1392,37 -1381,37 +1391,37 @@@ AT_DATA([input.y]
  start: test2 test1 test0 testc;
  
  test2
 -: 'a' { semi;                 /* TEST:N:2 */ }
 -| 'b' { if (0) {no_semi}      /* TEST:N:2 */ }
 -| 'c' { if (0) {semi;}                /* TEST:N:2 */ }
 -| 'd' { semi;   no_semi               /* TEST:Y:2 */ }
 -| 'e' { semi(); no_semi()     /* TEST:Y:2 */ }
 -| 'f' { semi[]; no_semi[]     /* TEST:Y:2 */ }
 -| 'g' { semi++; no_semi++     /* TEST:Y:2 */ }
 -| 'h' { {no_semi} no_semi     /* TEST:Y:2 */ }
 -| 'i' { {semi;}   no_semi     /* TEST:Y:2 */ }
 +: 'a' { semi;                   /* TEST:N:2 */ }
 +| 'b' { if (0) {no_semi}        /* TEST:N:2 */ }
 +| 'c' { if (0) {semi;}          /* TEST:N:2 */ }
 +| 'd' { semi;   no_semi         /* TEST:Y:2 */ }
 +| 'e' { semi(); no_semi()       /* TEST:Y:2 */ }
 +| 'f' { semi[]; no_semi[]       /* TEST:Y:2 */ }
 +| 'g' { semi++; no_semi++       /* TEST:Y:2 */ }
 +| 'h' { {no_semi} no_semi       /* TEST:Y:2 */ }
 +| 'i' { {semi;}   no_semi       /* TEST:Y:2 */ }
  ;
  test1
 -  : 'a' { semi;                       // TEST:N:1 ;
 -} | 'b' { if (0) {no_semi}    // TEST:N:1 ;
 -} | 'c' { if (0) {semi;}      // TEST:N:1 ;
 -} | 'd' { semi;   no_semi     // TEST:Y:1 ;
 -} | 'e' { semi(); no_semi()   // TEST:Y:1 ;
 -} | 'f' { semi[]; no_semi[]   // TEST:Y:1 ;
 -} | 'g' { semi++; no_semi++   // TEST:Y:1 ;
 -} | 'h' { {no_semi} no_semi   // TEST:Y:1 ;
 -} | 'i' { {semi;}   no_semi   // TEST:Y:1 ;
 +  : 'a' { semi;                 // TEST:N:1 ;
 +} | 'b' { if (0) {no_semi}      // TEST:N:1 ;
 +} | 'c' { if (0) {semi;}        // TEST:N:1 ;
 +} | 'd' { semi;   no_semi       // TEST:Y:1 ;
 +} | 'e' { semi(); no_semi()     // TEST:Y:1 ;
 +} | 'f' { semi[]; no_semi[]     // TEST:Y:1 ;
 +} | 'g' { semi++; no_semi++     // TEST:Y:1 ;
 +} | 'h' { {no_semi} no_semi     // TEST:Y:1 ;
 +} | 'i' { {semi;}   no_semi     // TEST:Y:1 ;
  } ;
  test0
 -  : 'a' { semi;                       // TEST:N:1 {}
 -} | 'b' { if (0) {no_semi}    // TEST:N:1 {}
 -} | 'c' { if (0) {semi;}      // TEST:N:1 {}
 -} | 'd' { semi;   no_semi     // TEST:Y:1 {}
 -} | 'e' { semi(); no_semi()   // TEST:Y:1 {}
 -} | 'f' { semi[]; no_semi[]   // TEST:Y:1 {}
 -} | 'g' { semi++; no_semi++   // TEST:Y:1 {}
 -} | 'h' { {no_semi} no_semi   // TEST:Y:1 {}
 -} | 'i' { {semi;}   no_semi   // TEST:Y:1 {}
 +  : 'a' { semi;                 // TEST:N:1 {}
 +} | 'b' { if (0) {no_semi}      // TEST:N:1 {}
 +} | 'c' { if (0) {semi;}        // TEST:N:1 {}
 +} | 'd' { semi;   no_semi       // TEST:Y:1 {}
 +} | 'e' { semi(); no_semi()     // TEST:Y:1 {}
 +} | 'f' { semi[]; no_semi[]     // TEST:Y:1 {}
 +} | 'g' { semi++; no_semi++     // TEST:Y:1 {}
 +} | 'h' { {no_semi} no_semi     // TEST:Y:1 {}
 +} | 'i' { {semi;}   no_semi     // TEST:Y:1 {}
  } ;
  
  testc
@@@ -1439,42 -1428,42 +1438,42 @@@ string;"
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o input.c input.y]], [0], [],
 -[[input.y:8.48: warning: a ';' might be needed at the end of action code
 -input.y:8.48: warning: future versions of Bison will not add the ';'
 -input.y:9.48: warning: a ';' might be needed at the end of action code
 -input.y:9.48: warning: future versions of Bison will not add the ';'
 -input.y:10.48: warning: a ';' might be needed at the end of action code
 -input.y:10.48: warning: future versions of Bison will not add the ';'
 -input.y:11.48: warning: a ';' might be needed at the end of action code
 -input.y:11.48: warning: future versions of Bison will not add the ';'
 -input.y:12.48: warning: a ';' might be needed at the end of action code
 -input.y:12.48: warning: future versions of Bison will not add the ';'
 -input.y:13.48: warning: a ';' might be needed at the end of action code
 -input.y:13.48: warning: future versions of Bison will not add the ';'
 -input.y:20.1: warning: a ';' might be needed at the end of action code
 -input.y:20.1: warning: future versions of Bison will not add the ';'
 -input.y:21.1: warning: a ';' might be needed at the end of action code
 -input.y:21.1: warning: future versions of Bison will not add the ';'
 -input.y:22.1: warning: a ';' might be needed at the end of action code
 -input.y:22.1: warning: future versions of Bison will not add the ';'
 -input.y:23.1: warning: a ';' might be needed at the end of action code
 -input.y:23.1: warning: future versions of Bison will not add the ';'
 -input.y:24.1: warning: a ';' might be needed at the end of action code
 -input.y:24.1: warning: future versions of Bison will not add the ';'
 -input.y:25.1: warning: a ';' might be needed at the end of action code
 -input.y:25.1: warning: future versions of Bison will not add the ';'
 -input.y:31.1: warning: a ';' might be needed at the end of action code
 -input.y:31.1: warning: future versions of Bison will not add the ';'
 -input.y:32.1: warning: a ';' might be needed at the end of action code
 -input.y:32.1: warning: future versions of Bison will not add the ';'
 -input.y:33.1: warning: a ';' might be needed at the end of action code
 -input.y:33.1: warning: future versions of Bison will not add the ';'
 -input.y:34.1: warning: a ';' might be needed at the end of action code
 -input.y:34.1: warning: future versions of Bison will not add the ';'
 -input.y:35.1: warning: a ';' might be needed at the end of action code
 -input.y:35.1: warning: future versions of Bison will not add the ';'
 -input.y:36.1: warning: a ';' might be needed at the end of action code
 -input.y:36.1: warning: future versions of Bison will not add the ';'
 +[[input.y:8.48: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:8.48: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:9.48: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:9.48: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:10.48: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:10.48: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:11.48: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:11.48: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:12.48: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:12.48: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:13.48: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:13.48: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:20.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:20.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:21.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:21.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:22.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:22.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:23.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:23.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:24.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:24.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:25.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:25.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:31.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:31.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:32.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:32.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:33.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:33.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:34.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:34.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:35.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:35.1: warning: future versions of Bison will not add the ';' [-Wother]
 +input.y:36.1: warning: a ';' might be needed at the end of action code [-Wother]
 +input.y:36.1: warning: future versions of Bison will not add the ';' [-Wother]
  ]])
  
  AT_MATCHES_CHECK([input.c], [[/\* TEST:N:2 \*/ \}$]],       [[3]])