]> 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 --cc 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
diff --cc bootstrap.conf
index 486268d715d15edc5e57e10c3e6d2cfd9baa5225,165d5e7d84675cbae6edc6dd123b2ba74f8ed596..e90cf12d4d0e01da3e784bf38194f4528f5701b8
@@@ -23,8 -23,11 +23,11 @@@ 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
diff --cc cfg.mk
index f1caf313e85f360c41d0ccfdfe874746dcc7a31c,53855aefc78e01481201ac5bdf9fd04044d14e32..af1e09e8d94cedef4c9ff5a76fd2766ba6d2e20b
--- 1/cfg.mk
--- 2/cfg.mk
+++ b/cfg.mk
@@@ -64,9 -70,11 +64,11 @@@ $(call exclude,                                                             
    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 --cc 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
  /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 --cc m4/.gitignore
Simple merge
diff --cc src/conflicts.c
index ccd50ebf78d72b01c40fbcdd2ac3d708af4ef079,ba0b6ed3fe80af1d657060d76670c5ecd6f16340..dad6568391e62e318c72117ee338b5c88a3d163f
@@@ -70,69 -70,69 +70,69 @@@ log_resolution (rule *r, symbol_number 
      {
        /* 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");
      }
index 1168a9c33e5d7e6604d025c63be2977d49b24edd,bd1fd174719941c0ea86b2e727e34404d6dbf13f..bb54bed75a760100fa804362b7eec974c28d349d
@@@ -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);
Simple merge
diff --cc src/output.c
index c227be223f4c89749696305e8aebc7f5ed3365d9,e77a2d1a0fc85a75d6f6bec202d96351778dfef2..24bb83cd146331c7ae337072a2cee56fb9c7af09
@@@ -53,51 -54,51 +53,51 @@@ 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)
@@@ -394,88 -338,96 +394,88 @@@ merger_output (FILE *out
    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);
  }
  
  
index 61d3651297342ef40bdd1d69a5fc5297f2dbe0ae,f5695a7a734951fe65d5d498359f3fd66522292f..d37afb2cd9d45c3fe36d208101f5941c2251f778
@@@ -68,39 -68,39 +68,39 @@@ print_core (struct obstack *oout, stat
  
        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, "]");
 +            }
 +        }
      }
  }
  
diff --cc src/scan-code.l
index 2fe880ed6a371d03215cc19af83d16320a6759e7,fa593beb8da889aeeb3c9685dacf0497f7422508..83501475fe9107292fe1fb1d03c5b945e711f4df
@@@ -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);
 +        }
      }
  }
  
@@@ -784,8 -788,8 +784,8 @@@ handle_action_dollar (symbol_list *rule
              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)
@@@ -834,8 -838,8 +834,8 @@@ handle_action_at (symbol_list *rule, ch
        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;
      }
  }
diff --cc src/scan-skel.l
index b79e58323e0cc2a95fc1232c6437ed2a56099151,ed61b5c80e5682cac96134b42c8dbd6ad95529fa..32bfe7374914ef6602a51482c7049c653bbefbab
@@@ -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);
diff --cc src/system.h
index 1d0af8fabddb6e7b5c10678dc1288de5c9abd369,1ae6a6b44a5921e9ca8bec6d65fac6eabb1d1b93..a56c058a10360c7d867f350e859844bd7680b864
@@@ -169,42 -156,13 +169,13 @@@ typedef size_t uintptr_t
  | 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).
  
Simple merge