]> git.saurik.com Git - bison.git/commitdiff
Merge branch 'maint'
authorAkim Demaille <akim@lrde.epita.fr>
Wed, 26 Sep 2012 12:35:47 +0000 (14:35 +0200)
committerAkim Demaille <akim@lrde.epita.fr>
Wed, 26 Sep 2012 12:51:11 +0000 (14:51 +0200)
* maint:
  warnings: introduce -Wdeprecated in the usage info
  errors: prefix the output with "error: "
  errors: indent "invalid value for %define" context
  errors: indent "%define var" redefinition context
  errors: indent "symbol redeclaration" context
  errors: indent "result type clash" error context

Conflicts:
src/complain.c
src/muscle-tab.c
src/reader.c
src/symtab.c
tests/conflicts.at
tests/input.at
tests/named-refs.at
tests/output.at
tests/skeletons.at

15 files changed:
1  2 
NEWS
THANKS
src/complain.c
src/complain.h
src/getargs.c
src/muscle-tab.c
src/reader.c
src/symtab.c
tests/conflicts.at
tests/glr-regression.at
tests/input.at
tests/named-refs.at
tests/output.at
tests/regression.at
tests/skeletons.at

diff --combined NEWS
index 7f0fe8b296f1dfbd3ae2f45192ab4c0ce8571600,772a2d510ea1a031977ac003ede2c1bea0c73d84..a70c23dbb63e4aaf2ca3e0307c17602e0fe21eb0
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -2,203 -2,6 +2,203 @@@ GNU Bison NEW
  
  * Noteworthy changes in release ?.? (????-??-??) [?]
  
 +** Incompatible changes
 +
 +*** Obsolete features
 +
 +  Support for YYFAIL is removed (deprecated in Bison 2.4.2).
 +  Support for yystype and yyltype (instead of YYSTYPE and YYLTYPE)
 +  is removed (deprecated in Bison 1.875).
 +  Support for YYPARSE_PARAM is removed (deprecated in Bison 1.875).
 +
 +** Warnings
 +
 +*** Deprecated constructs
 +
 +  The new 'deprecated' warning category flags obsolete constructs whose
 +  support will be discontinued.  It is enabled by default.  These warnings
 +  used to be reported as 'other' 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
 +
 +*** Undefined but unused symbols
 +
 +  Bison used to raise an error for undefined symbols that are not used in
 +  the grammar.  This is now only a warning.
 +
 +    %printer    {} symbol1
 +    %destructor {} symbol2
 +    %type <type>   symbol3
 +    %%
 +    exp: "a";
 +
 +*** 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>
 +
 +*** Conflicts
 +
 +  The warnings and error messages about shift/reduce and reduce/reduce
 +  conflicts have been normalized.  For instance on the following foo.y file:
 +
 +    %glr-parser
 +    %%
 +    exp: exp '+' exp | '0' | '0';
 +
 +  compare the previous version of bison:
 +
 +    $ bison foo.y
 +    foo.y: conflicts: 1 shift/reduce, 2 reduce/reduce
 +    $ bison -Werror foo.y
 +    bison: warnings being treated as errors
 +    foo.y: conflicts: 1 shift/reduce, 2 reduce/reduce
 +
 +  with the new behavior:
 +
 +    $ bison foo.y
 +    foo.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 +    foo.y: warning: 2 reduce/reduce conflicts [-Wconflicts-rr]
 +    $ bison -Werror foo.y
 +    bison: warnings being treated as errors
 +    foo.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 +    foo.y: warning: 2 reduce/reduce conflicts [-Wconflicts-rr]
 +
 +  When %expect or %expect-rr is used, such as with bar.y:
 +
 +    %expect 0
 +    %glr-parser
 +    %%
 +    exp: exp '+' exp | '0' | '0';
 +
 +  Former behavior:
 +
 +    $ bison bar.y
 +    bar.y: conflicts: 1 shift/reduce, 2 reduce/reduce
 +    bar.y: expected 0 shift/reduce conflicts
 +    bar.y: expected 0 reduce/reduce conflicts
 +
 +  New one:
 +
 +    $ bison bar.y
 +    bar.y: shift/reduce conflicts: 1 found, 0 expected
 +    bar.y: reduce/reduce conflicts: 2 found, 0 expected
 +
 +** 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
 +
 +*** The parser header is no longer mandatory (lalr1.cc, glr.cc)
 +
 +  Using %defines is now optional.  Without it, the needed support classes
 +  are defined in the generated parser, instead of additional files (such as
 +  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
 +
 +  This variable 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.
 +
 +** The directive %expect-rr is now an error in non GLR mode
 +
 +  It used to be an error only if used in non GLR mode, _and_ if there are
 +  reduce/reduce conflicts.
 +
 +* Noteworthy changes in release ?.? (????-??-??) [?]
 +
  ** Bug fixes
  
    Bugs in the test suite have been fixed.
    Incorrect definitions of YY_, issued by yacc.c when no parser header is
    generated, are removed.
  
+ ** Changes in the format of errors and exceptions output
+   This used to be the format of many error reports:
+     foo.y:5.10-24: result type clash on merge function 'merge': <t3> != <t2>
+     foo.y:4.13-27: previous declaration
+   It is now:
+     foo.y:5.10-25: result type clash on merge function 'merge': <t3> != <t2>
+     foo.y:4.13-27:     previous declaration
  * Noteworthy changes in release 2.6.2 (2012-08-03) [stable]
  
  ** Bug fixes
  
  * Noteworthy changes in release 2.6.1 (2012-07-30) [stable]
  
 -  Bison no longer executes user-specified M4 code when processing a grammar.
 + 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.
@@@ -2068,8 -1883,7 +2080,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 THANKS
index 4ed4256da8766c62c4690602783730a37f611e79,8af0abbe8c73020d4260b83b8c24375595b489e2..19ec28a9fb11828b8ad02368de1c746069cdee82
--- 1/THANKS
--- 2/THANKS
+++ b/THANKS
@@@ -71,7 -71,6 +71,7 @@@ Matt Kraai                kraai@alumni.
  Matt Rosing               rosing@peakfive.com
  Michael Hayes             m.hayes@elec.canterbury.ac.nz
  Michael Raskin            7c6f434c@mail.ru
 +Michiel De Wilde          mdewilde.agilent@gmail.com
  Mickael Labau             labau_m@epita.fr
  Mike Castle               dalgoda@ix.netcom.com
  Neil Booth                NeilB@earthling.net
@@@ -89,7 -88,6 +89,7 @@@ Per Allansson             per@appgate.c
  Peter Fales               psfales@lucent.com
  Peter Hamorsky            hamo@upjs.sk
  Piotr Gackiewicz          gacek@intertel.com.pl
 +Quentin Hocquet           hocquet@gostai.com
  Quoc Peyrot               chojin@lrde.epita.fr
  R Blake                   blakers@mac.com
  Raja R Harinath           harinath@cs.umn.edu
@@@ -104,6 -102,7 +104,7 @@@ Shura                     debil_urod@ng
  Stefano Lattarini         stefano.lattarini@gmail.com
  Steve Murphy              murf@parsetree.com
  Sum Wu                    sum@geekhouse.org
+ Théophile Ranquet         theophile.ranquet@gmail.com
  Thiru Ramakrishnan        thiru.ramakrishnan@gmail.com
  Tim Josling               tej@melbpc.org.au
  Tim Landscheidt           tim@tim-landscheidt.de
@@@ -127,6 -126,7 +128,7 @@@ thank them!  Please, help us keeping th
  
  Local Variables:
  mode: text
+ coding: utf-8
  End:
  
  -----
diff --combined src/complain.c
index d79a250250d6c41f5932e4a64c70fa4368a20412,b063c6b622b38cb036b03cb1a5b6762f10507487..1834120d698e78fcf14812db00408a59e19b5e61
  #include "files.h"
  #include "getargs.h"
  
 +warnings warnings_flag =
 +  Wconflicts_sr | Wconflicts_rr | Wdeprecated  | Wother;
 +
  bool complaint_issued;
  static unsigned *indent_ptr = 0;
  
 -\f
 +void
 +warnings_print_categories (warnings warn_flags)
 +{
 +  if (! (warn_flags & silent))
 +    {
 +      char const *warn_names[] =
 +        {
 +          "midrule-values",
 +          "yacc",
 +          "conflicts-sr",
 +          "conflicts-rr",
 +          "deprecated",
 +          "other"
 +        };
 +
 +      bool any = false;
 +      int i;
 +      for (i = 0; i < ARRAY_CARDINALITY (warn_names); ++i)
 +        if (warn_flags & 1 << i)
 +          {
 +            fprintf (stderr, "%s-W%s", any ? ", " : " [", warn_names[i]);
 +            any = true;
 +          }
 +      if (any)
 +        fprintf (stderr, "]");
 +    }
 +}
  
  /** Report an error message.
   *
   * \param loc     the location, defaulting to the current file,
   *                or the program name.
 + * \param flags   the category for this message.
   * \param prefix  put before the message (e.g., "warning").
   * \param message the error message, a printf format string.  Iff it
   *                ends with ": ", then no trailing newline is printed,
   */
  static
  void
 -error_message (location *loc,
 -             const char *prefix,
 -             const char *message, va_list args)
 +error_message (const location *loc, warnings flags, const char *prefix,
 +               const char *message, va_list args)
  {
 +  (void) flags;
    unsigned pos = 0;
  
    if (loc)
      fprintf (stderr, "%s: ", prefix);
  
    vfprintf (stderr, message, args);
 +  warnings_print_categories (flags);
    {
      size_t l = strlen (message);
 -    if (l < 2 || message[l-2] != ':' || message[l-1] != ' ') {
 -      putc ('\n', stderr);
 -      fflush (stderr);
 -    }
 +    if (l < 2 || message[l-2] != ':' || message[l-1] != ' ')
 +      {
 +        putc ('\n', stderr);
 +        fflush (stderr);
 +      }
    }
  }
  
 -/** Wrap error_message() with varargs handling. */
 -#define ERROR_MESSAGE(Loc, Prefix, Message)   \
 -{                                             \
 -  va_list args;                                       \
 -  va_start (args, Message);                   \
 -  error_message (Loc, Prefix, Message, args); \
 -  va_end (args);                              \
 -}
 -
 -
 -/*--------------------------------.
 -| Report a warning, and proceed.  |
 -`--------------------------------*/
 +/** Raise a complaint. That can be a fatal error, a complaint or just a
 +    warning.  */
  
 -void
 -set_warning_issued (void)
 +static inline void
 +complains (const location *loc, warnings flags, const char *message,
 +           va_list args)
  {
 -  static bool warning_issued = false;
 -  if (!warning_issued && (warnings_flag & warnings_error))
 +  if (flags & complaint)
      {
-       error_message (loc, complaint, NULL, message, args);
 -      fprintf (stderr, "%s: warnings being treated as errors\n", program_name);
++      error_message (loc, complaint,
++                     indent_ptr && *indent_ptr ? NULL : _("error"),
++                     message, args);
        complaint_issued = true;
      }
 -  warning_issued = true;
 -}
 -
 -void
 -warn_at (location loc, const char *message, ...)
 -{
 -  if (!(warnings_flag & warnings_other))
 -    return;
 -  set_warning_issued ();
 -  ERROR_MESSAGE (&loc, _("warning"), message);
 -}
 -
 -void
 -warn_at_indent (location loc, unsigned *indent,
 -                const char *message, ...)
 -{
 -  if (!(warnings_flag & warnings_other))
 -    return;
 -  set_warning_issued ();
 -  indent_ptr = indent;
 -  ERROR_MESSAGE (&loc, *indent ? NULL : _("warning"), message);
 +  else if (flags & fatal)
 +    {
 +      error_message (loc, fatal, _("fatal error"), message, args);
 +      exit (EXIT_FAILURE);
 +    }
 +  else if (flags & Wyacc)
 +    {
 +      if (yacc_flag)
 +        {
 +          error_message (loc, flags, NULL, message, args);
 +          complaint_issued = true;
 +        }
 +      else if (warnings_flag & Wyacc)
 +        {
 +          set_warning_issued ();
-           error_message (loc, flags, _("warning"), message, args);
++          error_message (loc, flags,
++                         indent_ptr && *indent_ptr ? NULL : _("warning"),
++                         message, args);
 +        }
 +    }
 +  else if (warnings_flag & flags)
 +    {
 +      set_warning_issued ();
-       error_message (loc, flags, _("warning"), message, args);
++      error_message (loc, flags,
++                     indent_ptr && *indent_ptr ? NULL : _("warning"),
++                     message, args);
 +    }
  }
  
  void
 -warn (const char *message, ...)
 +complain (warnings flags, const char *message, ...)
  {
 -  if (!(warnings_flag & warnings_other))
 -    return;
 -  set_warning_issued ();
 -  ERROR_MESSAGE (NULL, _("warning"), message);
 +  va_list args;
 +  va_start (args, message);
 +  complains (NULL, flags, message, args);
 +  va_end (args);
  }
  
 -
 -/*-----------------------------------------------------------.
 -| An error has occurred, but we can proceed, and die later.  |
 -`-----------------------------------------------------------*/
 -
  void
 -complain_at (location loc, const char *message, ...)
 +complain_at (location loc, warnings flags, const char *message, ...)
  {
 -  ERROR_MESSAGE (&loc, _("error"), message);
 -  complaint_issued = true;
 +  va_list args;
 +  va_start (args, message);
 +  complains (&loc, flags, message, args);
 +  va_end (args);
  }
  
 -void
 -complain_at_indent (location loc, unsigned *indent,
 -                    const char *message, ...)
 +void complain_at_indent (location loc, warnings flags, unsigned *indent,
 +                         const char *message, ...)
  {
    indent_ptr = indent;
 -  ERROR_MESSAGE (&loc, *indent ? NULL : _("error"), message);
 -  complaint_issued = true;
 -}
  
 -void
 -complain (const char *message, ...)
 -{
 -  ERROR_MESSAGE (NULL, _("error"), message);
 -  complaint_issued = true;
 +  va_list args;
 +  va_start (args, message);
 +  complains (&loc, flags, message, args);
 +  va_end (args);
  }
  
 -/*--------------------------------------------------------------.
 -| An incompatibility with POSIX Yacc: mapped either to warn* or |
 -| complain* depending on yacc_flag.                             |
 -`--------------------------------------------------------------*/
 +/*--------------------------------.
 +| Report a warning, and proceed.  |
 +`--------------------------------*/
  
  void
 -yacc_at (location loc, const char *message, ...)
 +set_warning_issued (void)
  {
 -  if (yacc_flag)
 +  static bool warning_issued = false;
 +  if (!warning_issued && (warnings_flag & Werror))
      {
 -      ERROR_MESSAGE (&loc, NULL, message);
 +      fprintf (stderr, "%s: warnings being treated as errors\n", program_name);
        complaint_issued = true;
      }
 -  else if (warnings_flag & warnings_yacc)
 -    {
 -      set_warning_issued ();
 -      ERROR_MESSAGE (&loc, _("warning"), message);
 -    }
 -}
 -
 -void
 -midrule_value_at (location loc, const char *message, ...)
 -{
 -  if (!(warnings_flag & warnings_midrule_values))
 -    return;
 -  set_warning_issued ();
 -  ERROR_MESSAGE (&loc, _("warning"), message);
 -}
 -
 -/*-------------------------------------------------.
 -| A severe error has occurred, we cannot proceed.  |
 -`-------------------------------------------------*/
 -
 -void
 -fatal_at (location loc, const char *message, ...)
 -{
 -  ERROR_MESSAGE (&loc, _("fatal error"), message);
 -  exit (EXIT_FAILURE);
 -}
 -
 -void
 -fatal (const char *message, ...)
 -{
 -  ERROR_MESSAGE (NULL, _("fatal error"), message);
 -  exit (EXIT_FAILURE);
 +  warning_issued = true;
  }
diff --combined src/complain.h
index 44be293d585d53154cd12b9f4e3ae23509e00e1e,997d577b6ff05ae74bb0d32d12e6846408b25fe5..452508efb62061f34cd58abd29963c315a888750
  
  # include "location.h"
  
 -# ifdef       __cplusplus
 -extern "C" {
 -# endif
 +/*-------------.
 +| --warnings.  |
 +`-------------*/
 +
 +typedef enum
 +  {
 +    Wnone             = 0,       /**< Issue no warnings.  */
 +    Wmidrule_values   = 1 << 0,  /**< Unset or unused midrule values.  */
 +    Wyacc             = 1 << 1,  /**< POSIXME.  */
 +    Wconflicts_sr     = 1 << 2,  /**< S/R conflicts.  */
 +    Wconflicts_rr     = 1 << 3,  /**< R/R conflicts.  */
 +    Wdeprecated       = 1 << 4,  /**< Obsolete constructs.  */
 +    Wother            = 1 << 5,  /**< All other warnings.  */
 +
 +    Werror            = 1 << 10, /**< Warnings are treated as errors.  */
 +    complaint         = 1 << 11, /**< All complaints.  */
 +    fatal             = 1 << 12, /**< All fatal errors.  */
 +    silent            = 1 << 13, /**< Do not display the warning type.  */
 +    Wall              = ~Werror  /**< All above warnings.  */
 +  } warnings;
 +
 +/** What warnings are issued.  */
 +extern warnings warnings_flag;
 +
 +/** Display a "[-Wyacc]" like message on stderr.  */
 +void warnings_print_categories (warnings warn_flags);
  
+ /* Sub-messages indent. */
+ #define SUB_INDENT (4)
  /** Record that a warning is about to be issued, and treat it as an
 -    error if <tt>warnings_flag & warnings_error</tt>.  This is exported
 +    error if <tt>warnings_flag & Werror</tt>.  This is exported
      only for the sake of Yacc-compatible conflict reports in conflicts.c.
      All other warnings should be implemented in complain.c and should use
      the normal warning format.  */
  void set_warning_issued (void);
  
 -/** Informative messages, but we proceed.  Report iff
 -    <tt>warnings_flag & warnings_other</tt>.  */
 -
 -void warn (char const *format, ...)
 -  __attribute__ ((__format__ (__printf__, 1, 2)));
 -
 -void warn_at (location loc, char const *format, ...)
 +/** Make a complaint, but don't specify any location.  */
 +void complain (warnings flags, char const *message, ...)
    __attribute__ ((__format__ (__printf__, 2, 3)));
  
 -/* Generate a message aligned by an indent.
 -   When *indent == 0, assign message's indent to *indent,
 -   When *indent > 0, align the message by *indent value. */
 -void warn_at_indent (location loc, unsigned *indent,
 -                     char const *format, ...)
 +/** Make a complaint with location.  */
 +void complain_at (location loc, warnings flags, char const *message, ...)
    __attribute__ ((__format__ (__printf__, 3, 4)));
  
 -/** An error, but we continue and die later.  */
 -
 -void complain (char const *format, ...)
 -  __attribute__ ((__format__ (__printf__, 1, 2)));
 -
 -void complain_at (location loc, char const *format, ...)
 -  __attribute__ ((__format__ (__printf__, 2, 3)));
 -
 -/* Generate a message aligned by an indent.
 -   When *indent == 0, assign message's indent to *indent,
 -   When *indent > 0, align the message by *indent value. */
 -void complain_at_indent (location loc, unsigned *indent,
 -                         char const *format, ...)
 -  __attribute__ ((__format__ (__printf__, 3, 4)));
 -
 -/** An incompatibility with POSIX Yacc: mapped either to warn* or
 -    complain* depending on yacc_flag. */
 -
 -void yacc_at (location loc, char const *format, ...)
 -  __attribute__ ((__format__ (__printf__, 2, 3)));
 -
 -/** A midrule-value warning.  Report iff
 -    <tt>warnings_flag & warnings_midrule_values</tt>.  */
 -
 -void midrule_value_at (location loc, char const *format, ...)
 -  __attribute__ ((__format__ (__printf__, 2, 3)));
 -
 -/** A fatal error, causing immediate exit.  */
 -
 -void fatal (char const *format, ...)
 -  __attribute__ ((__noreturn__, __format__ (__printf__, 1, 2)));
 -
 -void fatal_at (location loc, char const *format, ...)
 -  __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)));
 +/** Make a complaint with location and some indentation.  */
 +void complain_at_indent (location loc, warnings flags, unsigned *indent,
 +                         char const *message, ...)
 +  __attribute__ ((__format__ (__printf__, 4, 5)));
  
  /** Whether an error was reported.  */
  extern bool complaint_issued;
  
 -# ifdef       __cplusplus
 -}
 -# endif
 -
  #endif /* !COMPLAIN_H_ */
diff --combined src/getargs.c
index 74be41018b9a699000f14b3535a3b2b46b46a024,56d9724db5efa61a234ecf3c2b094c94575feca8..97f061f8f7c6a46024a8ab19f8d9fe97830362cb
  #include <c-strcase.h>
  #include <configmake.h>
  #include <error.h>
 -
 -/* Hack to get <getopt.h> to declare getopt with a prototype.  */
 -#if lint && ! defined __GNU_LIBRARY__
 -# define __GNU_LIBRARY__
 -# define HACK_FOR___GNU_LIBRARY___PROTOTYPE 1
 -#endif
 -
  #include <getopt.h>
 -
 -#ifdef HACK_FOR___GNU_LIBRARY___PROTOTYPE
 -# undef __GNU_LIBRARY__
 -# undef HACK_FOR___GNU_LIBRARY___PROTOTYPE
 -#endif
 -
  #include <progname.h>
  
  #include "complain.h"
  #include "quote.h"
  #include "uniqstr.h"
  
 -bool debug_flag;
  bool defines_flag;
  bool graph_flag;
  bool xml_flag;
 -bool locations_flag;
  bool no_lines_flag;
  bool token_table_flag;
 -bool yacc_flag;       /* for -y */
 -
 -bool error_verbose = false;
 +bool yacc_flag; /* for -y */
  
  bool nondeterministic_parser = false;
  bool glr_parser = false;
  
  int report_flag = report_none;
  int trace_flag = trace_none;
 -int warnings_flag = warnings_conflicts_sr | warnings_conflicts_rr
 -                    | warnings_other;
  
  static struct bison_language const valid_languages[] = {
    { "c", "c-skel.m4", ".c", ".h", true },
@@@ -79,32 -98,32 +79,32 @@@ const char *include = NULL
   */
  static void
  flags_argmatch (const char *option,
 -              const char * const keys[], const int values[],
 -              int all, int *flags, char *args)
 +                const char * const keys[], const int values[],
 +                int all, int *flags, char *args)
  {
    if (args)
      {
        args = strtok (args, ",");
        while (args)
 -      {
 -        int no = strncmp (args, "no-", 3) == 0 ? 3 : 0;
 -        int value = XARGMATCH (option, args + no, keys, values);
 -        if (value == 0)
 -          {
 -            if (no)
 -              *flags |= all;
 -            else
 -              *flags &= ~all;
 -          }
 -        else
 -          {
 -            if (no)
 -              *flags &= ~value;
 -            else
 -              *flags |= value;
 -          }
 -        args = strtok (NULL, ",");
 -      }
 +        {
 +          int no = STRPREFIX_LIT ("no-", args) ? 3 : 0;
 +          int value = XARGMATCH (option, args + no, keys, values);
 +          if (value == 0)
 +            {
 +              if (no)
 +                *flags |= all;
 +              else
 +                *flags &= ~all;
 +            }
 +          else
 +            {
 +              if (no)
 +                *flags &= ~value;
 +              else
 +                *flags |= value;
 +            }
 +          args = strtok (NULL, ",");
 +        }
      }
    else
      *flags |= all;
   *
   *  \param FlagName  the flag familly to update.
   *  \param Args      the effective sub arguments to decode.
 + *  \param All       the "all" value.
   *
   *  \arg FlagName_args   the list of keys.
   *  \arg FlagName_types  the list of values.
 - *  \arg FlagName_all    the all value.
   *  \arg FlagName_flag   the flag to update.
   */
 -#define FLAGS_ARGMATCH(FlagName, Args)                                        \
 +#define FLAGS_ARGMATCH(FlagName, Args, All)                             \
    flags_argmatch ("--" #FlagName, FlagName ## _args, FlagName ## _types, \
 -                FlagName ## _all, &FlagName ## _flag, Args)
 +                  All, &FlagName ## _flag, Args)
  
  
  /*----------------------.
@@@ -218,7 -237,6 +218,7 @@@ static const char * const warnings_args
    "yacc            - incompatibilities with POSIX Yacc",
    "conflicts-sr    - S/R conflicts",
    "conflicts-rr    - R/R conflicts",
 +  "deprecated      - obsolete constructs",
    "other           - all other warnings",
    "all             - all of the above",
    "error           - warnings are errors",
  
  static const int warnings_types[] =
  {
 -  warnings_none,
 -  warnings_midrule_values,
 -  warnings_yacc,
 -  warnings_conflicts_sr,
 -  warnings_conflicts_rr,
 -  warnings_other,
 -  warnings_all,
 -  warnings_error
 +  Wnone,
 +  Wmidrule_values,
 +  Wyacc,
 +  Wconflicts_sr,
 +  Wconflicts_rr,
 +  Wdeprecated,
 +  Wother,
 +  Wall,
 +  Werror
  };
  
  ARGMATCH_VERIFY (warnings_args, warnings_types);
  
 -
  /*-------------------------------------------.
  | Display the help message and exit STATUS.  |
  `-------------------------------------------*/
@@@ -251,13 -269,13 +251,13 @@@ usage (int status
  {
    if (status != 0)
      fprintf (stderr, _("Try `%s --help' for more information.\n"),
 -           program_name);
 +             program_name);
    else
      {
        /* For ../build-aux/cross-options.pl to work, use the format:
 -              ^  -S, --long[=ARGS] (whitespace)
 -       A --long option is required.
 -       Otherwise, add exceptions to ../build-aux/cross-options.pl.  */
 +                ^  -S, --long[=ARGS] (whitespace)
 +         A --long option is required.
 +         Otherwise, add exceptions to ../build-aux/cross-options.pl.  */
  
        printf (_("Usage: %s [OPTION]... FILE\n"), program_name);
        fputs (_("\
@@@ -291,8 -309,7 +291,8 @@@ Parser:\n
    -L, --language=LANGUAGE          specify the output programming language\n\
                                     (this is an experimental feature)\n\
    -S, --skeleton=FILE              specify the skeleton to use\n\
 -  -t, --debug                      instrument the parser for debugging\n\
 +  -t, --debug                      instrument the parser for tracing\n\
 +                                   same as `-Dparse.trace'\n\
        --locations                  enable location support\n\
    -D, --define=NAME[=VALUE]        similar to '%define NAME \"VALUE\"'\n\
    -F, --force-define=NAME[=VALUE]  override '%define NAME \"VALUE\"'\n\
@@@ -326,13 -343,14 +326,14 @@@ Warning categories include:\n
    `yacc'            incompatibilities with POSIX Yacc\n\
    `conflicts-sr'    S/R conflicts (enabled by default)\n\
    `conflicts-rr'    R/R conflicts (enabled by default)\n\
+   `deprecated'      obsolete constructs\n\
    `other'           all other warnings (enabled by default)\n\
    `all'             all the warnings\n\
    `no-CATEGORY'     turn off warnings in CATEGORY\n\
    `none'            turn off all the warnings\n\
    `error'           treat warnings as errors\n\
- \n\
  "), stdout);
+       putc ('\n', stdout);
  
        fputs (_("\
  THINGS is a list of comma separated words that can include:\n\
           Note we still output for 'C' so that it gets included in the
           man page.  */
        const char *lc_messages = setlocale (LC_MESSAGES, NULL);
 -      if (lc_messages && strcmp (lc_messages, "en_"))
 +      if (lc_messages && !STREQ (lc_messages, "en_"))
          /* TRANSLATORS: Replace LANG_CODE in this URL with your language
             code <http://translationproject.org/team/LANG_CODE.html> to
             form one of the URLs at http://translationproject.org/team/.
@@@ -384,14 -402,14 +385,14 @@@ version (void
    putc ('\n', stdout);
  
    fprintf (stdout,
 -         _("Copyright (C) %d Free Software Foundation, Inc.\n"),
 -         PACKAGE_COPYRIGHT_YEAR);
 +           _("Copyright (C) %d Free Software Foundation, Inc.\n"),
 +           PACKAGE_COPYRIGHT_YEAR);
  
    fputs (_("\
  This is free software; see the source for copying conditions.  There is NO\n\
  warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
  "),
 -       stdout);
 +         stdout);
  }
  
  
@@@ -408,8 -426,7 +409,8 @@@ skeleton_arg (char const *arg, int prio
        skeleton = arg;
      }
    else if (prio == skeleton_prio)
 -    complain_at (loc, _("multiple skeleton declarations are invalid"));
 +    complain_at (loc, complaint,
 +                 _("multiple skeleton declarations are invalid"));
  }
  
  void
@@@ -434,7 -451,7 +435,7 @@@ language_argmatch (char const *arg, in
    else
      return;
  
 -  complain_at (loc, msg, quotearg_colon (arg));
 +  complain_at (loc, complaint, msg, quotearg_colon (arg));
  }
  
  /*----------------------.
@@@ -480,25 -497,25 +481,25 @@@ enu
  static struct option const long_options[] =
  {
    /* Operation modes. */
 -  { "help",            no_argument,     0,   'h' },
 -  { "version",         no_argument,     0,   'V' },
 -  { "print-localedir", no_argument,     0,   PRINT_LOCALEDIR_OPTION },
 -  { "print-datadir",   no_argument,     0,   PRINT_DATADIR_OPTION   },
 +  { "help",            no_argument,       0,   'h' },
 +  { "version",         no_argument,       0,   'V' },
 +  { "print-localedir", no_argument,       0,   PRINT_LOCALEDIR_OPTION },
 +  { "print-datadir",   no_argument,       0,   PRINT_DATADIR_OPTION   },
    { "warnings",        optional_argument, 0,   'W' },
  
    /* Parser. */
 -  { "name-prefix",   required_argument,         0,   'p' },
 +  { "name-prefix",   required_argument,   0,   'p' },
    { "include",       required_argument,   0,   'I' },
  
    /* Output. */
 -  { "file-prefix", required_argument, 0,   'b' },
 -  { "output",    required_argument,   0,   'o' },
 -  { "output-file", required_argument, 0,   'o' },
 -  { "graph",     optional_argument,   0,   'g' },
 +  { "file-prefix", required_argument,   0,   'b' },
 +  { "output",      required_argument,   0,   'o' },
 +  { "output-file", required_argument,   0,   'o' },
 +  { "graph",       optional_argument,   0,   'g' },
    { "xml",         optional_argument,   0,   'x' },
 -  { "report",    required_argument,   0,   'r' },
 +  { "report",      required_argument,   0,   'r' },
    { "report-file", required_argument,   0,   REPORT_FILE_OPTION },
 -  { "verbose",           no_argument,         0,   'v' },
 +  { "verbose",     no_argument,         0,   'v' },
  
    /* Hidden. */
    { "trace",         optional_argument,   0,     'T' },
  
    /* Operation modes.  */
    { "fixed-output-files", no_argument,  0,   'y' },
 -  { "yacc",             no_argument,  0,   'y' },
 +  { "yacc",               no_argument,  0,   'y' },
  
    /* Parser.  */
 -  { "debug",        no_argument,               0,   't' },
 -  { "define",       required_argument,         0,   'D' },
 +  { "debug",          no_argument,               0,   't' },
 +  { "define",         required_argument,         0,   'D' },
    { "force-define",   required_argument,         0,   'F' },
 -  { "locations",      no_argument,             0, LOCATIONS_OPTION },
 +  { "locations",      no_argument,               0, LOCATIONS_OPTION },
    { "no-lines",       no_argument,               0,   'l' },
    { "raw",            no_argument,               0,     0 },
    { "skeleton",       required_argument,         0,   'S' },
@@@ -551,21 -568,21 +552,21 @@@ getargs (int argc, char *argv[]
    int c;
  
    while ((c = getopt_long (argc, argv, short_options, long_options, NULL))
 -       != -1)
 +         != -1)
      switch (c)
        {
          /* ASCII Sorting for short options (i.e., upper case then
             lower case), and then long-only options.  */
  
        case 0:
 -      /* Certain long options cause getopt_long to return 0.  */
 -      break;
 +        /* Certain long options cause getopt_long to return 0.  */
 +        break;
  
        case 'D': /* -DNAME[=VALUE]. */
        case 'F': /* -FNAME[=VALUE]. */
          {
            char* name = optarg;
 -          char* value = mbschr (optarg, '=');
 +          char* value = strchr (optarg, '=');
            if (value)
              *value++ = 0;
            muscle_percent_define_insert (name, command_line_location (),
                                          c == 'D' ? MUSCLE_PERCENT_DEFINE_D
                                                   : MUSCLE_PERCENT_DEFINE_F);
          }
 -      break;
 +        break;
  
        case 'I':
 -      include = AS_FILE_NAME (optarg);
 -      break;
 +        include = AS_FILE_NAME (optarg);
 +        break;
  
        case 'L':
 -      language_argmatch (optarg, command_line_prio,
 -                         command_line_location ());
 -      break;
 +        language_argmatch (optarg, command_line_prio,
 +                           command_line_location ());
 +        break;
  
        case 'S':
 -      skeleton_arg (AS_FILE_NAME (optarg), command_line_prio,
 -                    command_line_location ());
 -      break;
 +        skeleton_arg (AS_FILE_NAME (optarg), command_line_prio,
 +                      command_line_location ());
 +        break;
  
        case 'T':
 -      FLAGS_ARGMATCH (trace, optarg);
 -      break;
 +        FLAGS_ARGMATCH (trace, optarg, trace_all);
 +        break;
  
        case 'V':
 -      version ();
 -      exit (EXIT_SUCCESS);
 +        version ();
 +        exit (EXIT_SUCCESS);
  
        case 'W':
 -      FLAGS_ARGMATCH (warnings, optarg);
 -      break;
 +        FLAGS_ARGMATCH (warnings, optarg, Wall);
 +        break;
  
        case 'b':
 -      spec_file_prefix = AS_FILE_NAME (optarg);
 -      break;
 +        spec_file_prefix = AS_FILE_NAME (optarg);
 +        break;
  
        case 'd':
          /* Here, the -d and --defines options are differentiated.  */
          break;
  
        case 'g':
 -      graph_flag = true;
 -      if (optarg)
 +        graph_flag = true;
 +        if (optarg)
            {
              free (spec_graph_file);
              spec_graph_file = xstrdup (AS_FILE_NAME (optarg));
            }
 -      break;
 +        break;
  
        case 'h':
 -      usage (EXIT_SUCCESS);
 +        usage (EXIT_SUCCESS);
  
        case 'k':
 -      token_table_flag = true;
 -      break;
 +        token_table_flag = true;
 +        break;
  
        case 'l':
 -      no_lines_flag = true;
 -      break;
 +        no_lines_flag = true;
 +        break;
  
        case 'o':
 -      spec_outfile = AS_FILE_NAME (optarg);
 -      break;
 +        spec_outfile = AS_FILE_NAME (optarg);
 +        break;
  
        case 'p':
 -      spec_name_prefix = optarg;
 -      break;
 +        spec_name_prefix = optarg;
 +        break;
  
        case 'r':
 -      FLAGS_ARGMATCH (report, optarg);
 -      break;
 +        FLAGS_ARGMATCH (report, optarg, report_all);
 +        break;
  
        case 't':
 -      debug_flag = true;
 -      break;
 +        muscle_percent_define_insert ("parse.trace",
 +                                      command_line_location (), "",
 +                                      MUSCLE_PERCENT_DEFINE_D);
 +        break;
  
        case 'v':
 -      report_flag |= report_states;
 -      break;
 +        report_flag |= report_states;
 +        break;
  
        case 'x':
 -      xml_flag = true;
 -      if (optarg)
 +        xml_flag = true;
 +        if (optarg)
            {
              free (spec_xml_file);
              spec_xml_file = xstrdup (AS_FILE_NAME (optarg));
            }
 -      break;
 +        break;
  
        case 'y':
 -      yacc_flag = true;
 -      break;
 +        yacc_flag = true;
 +        break;
  
        case LOCATIONS_OPTION:
 -      locations_flag = true;
 -      break;
 +        muscle_percent_define_ensure ("locations",
 +                                      command_line_location (), true);
 +        break;
  
        case PRINT_LOCALEDIR_OPTION:
 -      printf ("%s\n", LOCALEDIR);
 -      exit (EXIT_SUCCESS);
 +        printf ("%s\n", LOCALEDIR);
 +        exit (EXIT_SUCCESS);
  
        case PRINT_DATADIR_OPTION:
 -      printf ("%s\n", compute_pkgdatadir ());
 -      exit (EXIT_SUCCESS);
 +        printf ("%s\n", pkgdatadir ());
 +        exit (EXIT_SUCCESS);
  
        case REPORT_FILE_OPTION:
          free (spec_verbose_file);
 -      spec_verbose_file = xstrdup (AS_FILE_NAME (optarg));
 -      break;
 +        spec_verbose_file = xstrdup (AS_FILE_NAME (optarg));
 +        break;
  
        default:
 -      usage (EXIT_FAILURE);
 +        usage (EXIT_FAILURE);
        }
  
    if (argc - optind != 1)
diff --combined src/muscle-tab.c
index 8e5698127cd81e51d3a15ad0a1ef51212ca72e69,37a0f0e8ea95b8a179f8b1be1a4103047f9ce30d..4738fdfdf9c625b49c646ad8fe5ebbba48d93b90
@@@ -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);
@@@ -157,9 -157,12 +157,9 @@@ muscle_grow (const char *key, const cha
      {
        /* Grow the current value. */
        char *new_val;
 -      obstack_sgrow (&muscle_obstack, entry->value);
 +      obstack_printf (&muscle_obstack, "%s%s%s", entry->value, separator, val);
        free (entry->storage);
 -      obstack_sgrow (&muscle_obstack, separator);
 -      obstack_sgrow (&muscle_obstack, val);
 -      obstack_1grow (&muscle_obstack, 0);
 -      new_val = obstack_finish (&muscle_obstack);
 +      new_val = obstack_finish0 (&muscle_obstack);
        entry->value = entry->storage = xstrdup (new_val);
        obstack_free (&muscle_obstack, new_val);
      }
@@@ -178,7 -181,8 +178,7 @@@ muscle_syncline_grow (char const *key, 
    obstack_quote (&muscle_obstack,
                   quotearg_style (c_quoting_style, loc.start.file));
    obstack_sgrow (&muscle_obstack, ")[");
 -  obstack_1grow (&muscle_obstack, 0);
 -  extension = obstack_finish (&muscle_obstack);
 +  extension = obstack_finish0 (&muscle_obstack);
    muscle_grow (key, extension, "");
    obstack_free (&muscle_obstack, extension);
  }
@@@ -198,7 -202,7 +198,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, "[");
    obstack_sgrow (&muscle_obstack, ", ");
    obstack_quote (&muscle_obstack, a2);
    obstack_sgrow (&muscle_obstack, "]");
 -  obstack_1grow (&muscle_obstack, 0);
 -  pair = obstack_finish (&muscle_obstack);
 +  pair = obstack_finish0 (&muscle_obstack);
    muscle_grow (muscle, pair, ",\n");
    obstack_free (&muscle_obstack, pair);
  }
@@@ -263,8 -268,13 +263,8 @@@ muscle_boundary_grow (char const *key, 
    char *extension;
    obstack_sgrow  (&muscle_obstack, "[[");
    obstack_escape (&muscle_obstack, bound.file);
 -  obstack_1grow  (&muscle_obstack, ':');
 -  obstack_printf (&muscle_obstack, "%d", bound.line);
 -  obstack_1grow  (&muscle_obstack, '.');
 -  obstack_printf (&muscle_obstack, "%d", bound.column);
 -  obstack_sgrow  (&muscle_obstack, "]]");
 -  obstack_1grow  (&muscle_obstack, '\0');
 -  extension = obstack_finish (&muscle_obstack);
 +  obstack_printf (&muscle_obstack, ":%d.%d]]", bound.line, bound.column);
 +  extension = obstack_finish0 (&muscle_obstack);
    muscle_grow (key, extension, "");
    obstack_free (&muscle_obstack, extension);
  }
@@@ -305,10 -315,11 +305,10 @@@ muscle_location_grow (char const *key, 
  static char *
  string_decode (char const *key)
  {
 -  char const *value;
 +  char const *value = muscle_find_const (key);
    char *value_decoded;
    char *result;
  
 -  value = muscle_find_const (key);
    if (!value)
      return NULL;
    do {
@@@ -347,7 -358,8 +347,7 @@@ location_decode (char const *key
            {
              char *boundary_str;
              aver (*++value == ']');
 -            obstack_1grow (&muscle_obstack, '\0');
 -            boundary_str = obstack_finish (&muscle_obstack);
 +            boundary_str = obstack_finish0 (&muscle_obstack);
              switch (*++value)
                {
                  case ',':
@@@ -384,49 -396,25 +384,49 @@@ 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, location variable_loc)
 +{
 +  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", },
 +    };
 +  char const *res = variable;
 +  int i;
 +  for (i = 0; i < ARRAY_CARDINALITY (conversion); ++i)
 +    if (STREQ (conversion[i].obsolete, variable))
 +      {
 +        res = conversion[i].updated;
 +        complain_at (variable_loc, Wdeprecated,
 +                     _("deprecated %%define variable name: %s, use %s"),
 +                     quote (variable), quote_n (1, res));
 +        break;
 +      }
 +  return res;
 +}
 +
  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, variable_loc);
  
    name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
    loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
    if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
        && muscle_find_const (name))
      {
 -      muscle_percent_define_how how_old =
 -        atoi (muscle_find_const (how_name));
 +      muscle_percent_define_how how_old = atoi (muscle_find_const (how_name));
+       unsigned i = 0;
        if (how_old == MUSCLE_PERCENT_DEFINE_F)
 -        {
 -          free (variable_tr);
 -          return;
 -        }
 -      complain_at_indent (variable_loc, &i,
 -                          _("%%define variable %s redefined"), quote (variable));
 +        return;
-       complain_at (variable_loc, complaint, _("%%define variable %s redefined"),
-                    quote (variable));
-       location loc = muscle_percent_define_get_loc (variable);
-       complain_at (loc, complaint, _("previous definition"));
++      complain_at_indent (variable_loc, complaint, &i,
++                          _("%%define variable %s redefined"),
++                          quote (variable));
+       i += SUB_INDENT;
 -      complain_at_indent (muscle_percent_define_get_loc (variable), &i,
++      complain_at_indent (muscle_percent_define_get_loc (variable),
++                          complaint, &i,
+                           _("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 = 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 *
  muscle_percent_define_get (char const *variable)
  {
 -  char const *name;
 -  char const *usage_name;
 -  char *value;
 -
 -  name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
 -  usage_name = UNIQSTR_CONCAT ("percent_define_bison_variables(",
 -                               variable, ")");
 -
 -  muscle_insert (usage_name, "");
 -  value = string_decode (name);
 +  char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
 +  char const *usage_name =
 +    UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
 +  char *value = string_decode (name);
    if (!value)
      value = xstrdup ("");
 +
 +  muscle_insert (usage_name, "");
    return value;
  }
  
  location
  muscle_percent_define_get_loc (char const *variable)
  {
 -  char const *loc_name;
 -  loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
 +  char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
    if (!muscle_find_const (loc_name))
 -    fatal(_("%s: undefined %%define variable %s"),
 -          "muscle_percent_define_get_loc", quote (variable));
 +    complain (fatal, _("%s: undefined %%define variable %s"),
 +              "muscle_percent_define_get_loc", quote (variable));
    return location_decode (loc_name);
  }
  
  char const *
  muscle_percent_define_get_syncline (char const *variable)
  {
 -  char const *syncline_name;
 -  char const *syncline;
 -  syncline_name =
 +  char const *syncline_name =
      UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
 -  syncline = muscle_find_const (syncline_name);
 +  char const *syncline = muscle_find_const (syncline_name);
    if (!syncline)
 -    fatal(_("%s: undefined %%define variable %s"),
 -          "muscle_percent_define_get_syncline", quote (variable));
 +    complain (fatal, _("%s: undefined %%define variable %s"),
 +              "muscle_percent_define_get_syncline", quote (variable));
    return syncline;
  }
  
  bool
  muscle_percent_define_ifdef (char const *variable)
  {
 -  char const *name;
 -  char const *usage_name;
 -  char const *value;
 -
 -  name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
 -  usage_name =
 +  char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
 +  char const *usage_name =
      UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
 -
 -  value = muscle_find_const (name);
 +  char const *value = muscle_find_const (name);
    if (value)
      {
        muscle_insert (usage_name, "");
  bool
  muscle_percent_define_flag_if (char const *variable)
  {
 -  char const *invalid_boolean_name;
 -  bool result = false;
 -
 -  invalid_boolean_name =
 +  char const *invalid_boolean_name =
      UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")");
 +  bool result = false;
  
    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;
  }
  void
  muscle_percent_define_default (char const *variable, char const *value)
  {
 -  char const *name;
 -  char const *loc_name;
 -  char const *syncline_name;
 -  name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
 -  loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
 -  syncline_name =
 +  char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
 +  char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
 +  char const *syncline_name =
      UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
    if (!muscle_find_const (name))
      {
@@@ -589,24 -578,30 +593,27 @@@ muscle_percent_define_check_values (cha
    for (; *values; ++values)
      {
        char const * const *variablep = values;
 -      char const *name;
 -      char *value;
 -
 -      name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
 -
 -      value = string_decode (name);
 +      char const *name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
 +      char *value = string_decode (name);
        if (value)
          {
            for (++values; *values; ++values)
              {
 -              if (0 == strcmp (value, *values))
 +              if (STREQ (value, *values))
                  break;
              }
            if (!*values)
              {
+               unsigned i = 0;
                location loc = muscle_percent_define_get_loc (*variablep);
-               complain_at (loc, complaint,
-                            _("invalid value for %%define variable %s: %s"),
-                            quote (*variablep), quote_n (1, value));
 -              complain_at_indent (loc, &i,
 -                                _("invalid value for %%define variable %s: %s"),
 -                                  quote (*variablep), quote_n (1, value));
++              complain_at_indent
++                (loc, complaint, &i,
++                 _("invalid value for %%define variable %s: %s"),
++                 quote (*variablep), quote_n (1, value));
+               i += SUB_INDENT;
                for (values = variablep + 1; *values; ++values)
-                 complain_at (loc, complaint, _("accepted value: %s"),
-                              quote (*values));
 -                complain_at_indent (loc, &i, _("accepted value: %s"),
++                complain_at_indent (loc, complaint, &i, _("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));
      }
  }
  
@@@ -625,7 -620,8 +632,7 @@@ voi
  muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
                            char const *code, location code_loc)
  {
 -  char const *name;
 -  name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
 +  char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
    muscle_code_grow (name, code, code_loc);
    muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
                                 qualifier_loc);
  static inline bool
  muscle_m4_output (muscle_entry *entry, FILE *out)
  {
 -  fprintf (out, "m4_define([b4_%s],\n", entry->key);
 -  fprintf (out, "[[%s]])\n\n\n", entry->value);
 +  fprintf (out,
 +           "m4_define([b4_%s],\n"
 +           "[[%s]])\n\n\n", entry->key, entry->value);
    return true;
  }
  
diff --combined src/reader.c
index 52c0b13983440fca9fcae407645098f8b6a58795,86fde7b2e4303b3371b233a48a9da98673e2a27b..f658e64e9f49b600e97bd80ad65f048aa55acafc
@@@ -59,7 -59,7 +59,7 @@@ voi
  grammar_start_symbol_set (symbol *sym, location loc)
  {
    if (start_flag)
 -    complain_at (loc, _("multiple %s declarations"), "%start");
 +    complain_at (loc, complaint, _("multiple %s declarations"), "%start");
    else
      {
        start_flag = true;
@@@ -94,7 -94,7 +94,7 @@@ get_merge_function (uniqstr name
        syms->next = xmalloc (sizeof syms->next[0]);
        syms->next->name = uniqstr_new (name);
        /* After all symbol type declarations have been parsed, packgram invokes
 -       record_merge_function_type to set the type.  */
 +         record_merge_function_type to set the type.  */
        syms->next->type = NULL;
        syms->next->next = NULL;
        merge_functions = head.next;
@@@ -128,18 -128,22 +128,23 @@@ record_merge_function_type (int merger
    aver (merge_function != NULL && merger_find == merger);
    if (merge_function->type != NULL && !UNIQSTR_EQ (merge_function->type, type))
      {
-       complain_at (declaration_loc, complaint,
-                    _("result type clash on merge function %s: <%s> != <%s>"),
-                    quote (merge_function->name), type, merge_function->type);
-       complain_at (merge_function->type_declaration_location, complaint,
-                    _("previous declaration"));
+       unsigned indent = 0;
 -      complain_at_indent (declaration_loc, &indent,
++      complain_at_indent (declaration_loc, complaint, &indent,
+                           _("result type clash on merge function %s: "
+                             "<%s> != <%s>"),
+                           quote (merge_function->name), type,
+                           merge_function->type);
+       indent += SUB_INDENT;
 -      complain_at_indent (merge_function->type_declaration_location, &indent,
++      complain_at_indent (merge_function->type_declaration_location, complaint,
++                          &indent,
+                           _("previous declaration"));
 -   }
 +    }
    merge_function->type = uniqstr_new (type);
    merge_function->type_declaration_location = declaration_loc;
  }
  
  /*--------------------------------------.
 -| Free all merge-function definitions.        |
 +| Free all merge-function definitions.  |
  `--------------------------------------*/
  
  void
@@@ -197,9 -201,9 +202,9 @@@ assign_named_ref (symbol_list *p, named
  
    if (name->id == sym->tag)
      {
 -      warn_at (name->loc,
 -             _("duplicated symbol name for %s ignored"),
 -             quote (sym->tag));
 +      complain_at (name->loc, Wother,
 +                   _("duplicated symbol name for %s ignored"),
 +                   quote (sym->tag));
        named_ref_free (name);
      }
    else
@@@ -220,7 -224,7 +225,7 @@@ static symbol_list *previous_rule_end 
  
  void
  grammar_current_rule_begin (symbol *lhs, location loc,
 -                          named_ref *lhs_name)
 +                            named_ref *lhs_name)
  {
    symbol_list* p;
  
        ++nvars;
      }
    else if (lhs->class == token_sym)
 -    complain_at (loc, _("rule given for %s, which is a token"), lhs->tag);
 +    complain_at (loc, complaint, _("rule given for %s, which is a token"),
 +                 lhs->tag);
  }
  
  
  static bool
  symbol_should_be_used (symbol_list const *s, bool *midrule_warning)
  {
 -  if (symbol_destructor_get (s->content.sym)->code)
 +  if (symbol_code_props_get (s->content.sym, destructor)->code)
      return true;
    if ((s->midrule && s->midrule->action_props.is_value_used)
        || (s->midrule_parent_rule
@@@ -292,19 -295,19 +297,19 @@@ grammar_rule_check (const symbol_list *
        symbol *first_rhs = r->next->content.sym;
        /* If $$ is being set in default way, report if any type mismatch.  */
        if (first_rhs)
 -      {
 -        char const *lhs_type = r->content.sym->type_name;
 -        const char *rhs_type =
 -          first_rhs->type_name ? first_rhs->type_name : "";
 -        if (!UNIQSTR_EQ (lhs_type, rhs_type))
 -          warn_at (r->location,
 -                   _("type clash on default action: <%s> != <%s>"),
 -                   lhs_type, rhs_type);
 -      }
 +        {
 +          char const *lhs_type = r->content.sym->type_name;
 +          const char *rhs_type =
 +            first_rhs->type_name ? first_rhs->type_name : "";
 +          if (!UNIQSTR_EQ (lhs_type, rhs_type))
 +            complain_at (r->location, Wother,
 +                         _("type clash on default action: <%s> != <%s>"),
 +                         lhs_type, rhs_type);
 +        }
        /* Warn if there is no default for $$ but we need one.  */
        else
 -      warn_at (r->location,
 -               _("empty rule for typed nonterminal, and no action"));
 +        complain_at (r->location, Wother,
 +                     _("empty rule for typed nonterminal, and no action"));
      }
  
    /* Check that symbol values that should be used are in fact used.  */
              /* The default action, $$ = $1, `uses' both.  */
              && (r->action_props.code || (n != 0 && n != 1)))
            {
 -            void (*warn_at_ptr)(location, char const*, ...) =
 -              midrule_warning ? midrule_value_at : warn_at;
 +            warnings warn_flag = midrule_warning ? Wmidrule_values : Wother;
              if (n)
 -              warn_at_ptr (r->location, _("unused value: $%d"), n);
 +              complain_at (r->location, warn_flag, _("unused value: $%d"), n);
              else
 -              warn_at_ptr (r->location, _("unset value: $$"));
 +              complain_at (r->location, warn_flag, _("unset value: $$"));
            }
        }
    }
       it for char literals and strings, which are always tokens.  */
    if (r->ruleprec
        && r->ruleprec->tag[0] != '\'' && r->ruleprec->tag[0] != '"'
 -      && !r->ruleprec->declared && !r->ruleprec->prec)
 -    warn_at (r->location, _("token for %%prec is not defined: %s"),
 -             r->ruleprec->tag);
 +      && r->ruleprec->status != declared && !r->ruleprec->prec)
 +    complain_at (r->location, Wother,
 +                 _("token for %%prec is not defined: %s"), r->ruleprec->tag);
  }
  
  
@@@ -384,8 -388,7 +389,8 @@@ grammar_midrule_action (void
    code_props_rule_action_init (&midrule->action_props,
                                 current_rule->action_props.code,
                                 current_rule->action_props.location,
 -                               midrule, 0);
 +                               midrule, 0,
 +                               current_rule->action_props.is_predicate);
    code_props_none_init (&current_rule->action_props);
  
    if (previous_rule_end)
@@@ -425,7 -428,7 +430,7 @@@ grammar_current_rule_prec_set (symbol *
       token.  */
    symbol_class_set (precsym, token_sym, loc, false);
    if (current_rule->ruleprec)
 -    complain_at (loc, _("only one %s allowed per rule"), "%prec");
 +    complain_at (loc, complaint, _("only one %s allowed per rule"), "%prec");
    current_rule->ruleprec = precsym;
  }
  
@@@ -435,13 -438,11 +440,13 @@@ voi
  grammar_current_rule_dprec_set (int dprec, location loc)
  {
    if (! glr_parser)
 -    warn_at (loc, _("%s affects only GLR parsers"), "%dprec");
 +    complain_at (loc, Wother, _("%s affects only GLR parsers"),
 +                 "%dprec");
    if (dprec <= 0)
 -    complain_at (loc, _("%s must be followed by positive number"), "%dprec");
 +    complain_at (loc, complaint, _("%s must be followed by positive number"),
 +                 "%dprec");
    else if (current_rule->dprec != 0)
 -    complain_at (loc, _("only one %s allowed per rule"), "%dprec");
 +    complain_at (loc, complaint, _("only one %s allowed per rule"), "%dprec");
    current_rule->dprec = dprec;
  }
  
@@@ -452,10 -453,9 +457,10 @@@ voi
  grammar_current_rule_merge_set (uniqstr name, location loc)
  {
    if (! glr_parser)
 -    warn_at (loc, _("%s affects only GLR parsers"), "%merge");
 +    complain_at (loc, Wother, _("%s affects only GLR parsers"),
 +                 "%merge");
    if (current_rule->merger != 0)
 -    complain_at (loc, _("only one %s allowed per rule"), "%merge");
 +    complain_at (loc, complaint, _("only one %s allowed per rule"), "%merge");
    current_rule->merger = get_merge_function (name);
    current_rule->merger_declaration_location = loc;
  }
  
  void
  grammar_current_rule_symbol_append (symbol *sym, location loc,
 -                                  named_ref *name)
 +                                    named_ref *name)
  {
    symbol_list *p;
    if (current_rule->action_props.code)
    p = grammar_symbol_append (sym, loc);
    if (name)
      assign_named_ref(p, name);
 +  if (sym->status == undeclared || sym->status == used)
 +    sym->status = needed;
  }
  
  /* Attach an ACTION to the current rule.  */
  
  void
  grammar_current_rule_action_append (const char *action, location loc,
 -                                  named_ref *name)
 +                                    named_ref *name, bool is_predicate)
  {
    if (current_rule->action_props.code)
      grammar_midrule_action ();
    /* After all symbol declarations have been parsed, packgram invokes
       code_props_translate_code.  */
    code_props_rule_action_init (&current_rule->action_props, action, loc,
 -                               current_rule, name);
 +                               current_rule, name, is_predicate);
  }
  
  \f
@@@ -516,7 -514,7 +521,7 @@@ packgram (void
        int rule_length = 0;
        symbol *ruleprec = p->ruleprec;
        record_merge_function_type (p->merger, p->content.sym->type_name,
 -                                p->merger_declaration_location);
 +                                  p->merger_declaration_location);
        rules[ruleno].user_number = ruleno;
        rules[ruleno].number = ruleno;
        rules[ruleno].lhs = p->content.sym;
        rules[ruleno].useful = true;
        rules[ruleno].action = p->action_props.code;
        rules[ruleno].action_location = p->action_props.location;
 +      rules[ruleno].is_predicate = p->action_props.is_predicate;
  
        /* If the midrule's $$ is set or its $n is used, remove the `$' from the
 -       symbol name so that it's a user-defined symbol so that the default
 -       %destructor and %printer apply.  */
 +         symbol name so that it's a user-defined symbol so that the default
 +         %destructor and %printer apply.  */
        if (p->midrule_parent_rule
            && (p->action_props.is_value_used
 -            || symbol_list_n_get (p->midrule_parent_rule,
 -                                  p->midrule_parent_rhs_index)
 +              || symbol_list_n_get (p->midrule_parent_rule,
 +                                    p->midrule_parent_rhs_index)
                     ->action_props.is_value_used))
 -      p->content.sym->tag += 1;
 +        p->content.sym->tag += 1;
  
        /* Don't check the generated rule 0.  It has no action, so some rhs
 -       symbols may appear unused, but the parsing algorithm ensures that
 -       %destructor's are invoked appropriately.  */
 +         symbols may appear unused, but the parsing algorithm ensures that
 +         %destructor's are invoked appropriately.  */
        if (p != grammar)
 -      grammar_rule_check (p);
 +        grammar_rule_check (p);
  
        for (p = p->next; p && p->content.sym; p = p->next)
 -      {
 -        ++rule_length;
 +        {
 +          ++rule_length;
  
 -        /* Don't allow rule_length == INT_MAX, since that might
 -           cause confusion with strtol if INT_MAX == LONG_MAX.  */
 -        if (rule_length == INT_MAX)
 -            fatal_at (rules[ruleno].location, _("rule is too long"));
 +          /* Don't allow rule_length == INT_MAX, since that might
 +             cause confusion with strtol if INT_MAX == LONG_MAX.  */
 +          if (rule_length == INT_MAX)
 +            complain_at (rules[ruleno].location, fatal, _("rule is too long"));
  
 -        /* item_number = symbol_number.
 -           But the former needs to contain more: negative rule numbers. */
 -        ritem[itemno++] =
 +          /* item_number = symbol_number.
 +             But the former needs to contain more: negative rule numbers. */
 +          ritem[itemno++] =
              symbol_number_as_item_number (p->content.sym->number);
 -        /* A rule gets by default the precedence and associativity
 -           of its last token.  */
 -        if (p->content.sym->class == token_sym && default_prec)
 -          rules[ruleno].prec = p->content.sym;
 -      }
 +          /* A rule gets by default the precedence and associativity
 +             of its last token.  */
 +          if (p->content.sym->class == token_sym && default_prec)
 +            rules[ruleno].prec = p->content.sym;
 +        }
  
        /* If this rule has a %prec,
           the specified symbol's precedence replaces the default.  */
        if (ruleprec)
 -      {
 -        rules[ruleno].precsym = ruleprec;
 -        rules[ruleno].prec = ruleprec;
 -      }
 +        {
 +          rules[ruleno].precsym = ruleprec;
 +          rules[ruleno].prec = ruleprec;
 +        }
        /* An item ends by the rule number (negated).  */
        ritem[itemno++] = rule_number_as_item_number (ruleno);
        aver (itemno < ITEM_NUMBER_MAX);
        aver (ruleno < RULE_NUMBER_MAX);
  
        if (p)
 -      p = p->next;
 +        p = p->next;
      }
  
    aver (itemno == nritems);
@@@ -643,7 -640,7 +648,7 @@@ prepare_percent_define_front_end_variab
         default.  */
      muscle_percent_define_default ("lr.type", "lalr");
      lr_type = muscle_percent_define_get ("lr.type");
 -    if (0 != strcmp (lr_type, "canonical-lr"))
 +    if (STRNEQ (lr_type, "canonical-lr"))
        muscle_percent_define_default ("lr.default-reductions", "most");
      else
        muscle_percent_define_default ("lr.default-reductions", "accepting");
  
  /*-------------------------------------------------------------.
  | Check the grammar that has just been read, and convert it to |
 -| internal form.                                             |
 +| internal form.                                               |
  `-------------------------------------------------------------*/
  
  static void
@@@ -672,7 -669,7 +677,7 @@@ check_and_convert_grammar (void
  {
    /* Grammar has been read.  Do some checking.  */
    if (nrules == 0)
 -    fatal (_("no rules in the input grammar"));
 +    complain (fatal, _("no rules in the input grammar"));
  
    /* If the user did not define her ENDTOKEN, do it now. */
    if (!endtoken)
diff --combined src/symtab.c
index 21c61255b9c39f8f033e9d34004b879d6a5d1675,2e0b92015ebbfef1b209bd3eea0bc1169d8fad12..916536ae3d05e3c12fcfb608857cbb07465e44eb
@@@ -33,7 -33,6 +33,7 @@@
  `-------------------------------------------------------------------*/
  
  static symbol **symbols_sorted = NULL;
 +static symbol **semantic_types_sorted = NULL;
  
  /*------------------------.
  | Distinguished symbols.  |
@@@ -46,6 -45,14 +46,6 @@@ symbol *accept = NULL
  symbol *startsymbol = NULL;
  location startsymbol_location;
  
 -/*---------------------------------------.
 -| Default %destructor's and %printer's.  |
 -`---------------------------------------*/
 -
 -static code_props default_tagged_destructor = CODE_PROPS_NONE_INIT;
 -static code_props default_tagless_destructor = CODE_PROPS_NONE_INIT;
 -static code_props default_tagged_printer = CODE_PROPS_NONE_INIT;
 -static code_props default_tagless_printer = CODE_PROPS_NONE_INIT;
  
  /*---------------------------------.
  | Create a new symbol, named TAG.  |
@@@ -60,16 -67,16 +60,16 @@@ symbol_new (uniqstr tag, location loc
  
    /* If the tag is not a string (starts with a double quote), check
       that it is valid for Yacc. */
 -  if (tag[0] != '\"' && tag[0] != '\'' && mbschr (tag, '-'))
 -    yacc_at (loc, _("POSIX Yacc forbids dashes in symbol names: %s"),
 -             tag);
 +  if (tag[0] != '\"' && tag[0] != '\'' && strchr (tag, '-'))
 +    complain_at (loc, Wyacc,
 +                 _("POSIX Yacc forbids dashes in symbol names: %s"), tag);
  
    res->tag = tag;
    res->location = loc;
  
    res->type_name = NULL;
 -  code_props_none_init (&res->destructor);
 -  code_props_none_init (&res->printer);
 +  for (int i = 0; i < CODE_PROPS_SIZE; ++i)
 +    code_props_none_init (&res->props[i]);
  
    res->number = NUMBER_UNDEFINED;
    res->prec = 0;
  
    res->alias = NULL;
    res->class = unknown_sym;
 -  res->declared = false;
 +  res->status = undeclared;
  
    if (nsyms == SYMBOL_NUMBER_MAXIMUM)
 -    fatal (_("too many symbols in input grammar (limit is %d)"),
 -         SYMBOL_NUMBER_MAXIMUM);
 +    complain (fatal, _("too many symbols in input grammar (limit is %d)"),
 +              SYMBOL_NUMBER_MAXIMUM);
    nsyms++;
    return res;
  }
  
 +char const *
 +code_props_type_string (code_props_type kind)
 +{
 +  switch (kind)
 +    {
 +    case destructor:
 +      return "%destructor";
 +    case printer:
 +      return "%printer";
 +    }
 +  assert (0);
 +}
 +
  /*----------------------------------------.
  | Create a new semantic type, named TAG.  |
  `----------------------------------------*/
  
  static semantic_type *
 -semantic_type_new (uniqstr tag)
 +semantic_type_new (uniqstr tag, const location *loc)
  {
    semantic_type *res = xmalloc (sizeof *res);
  
    uniqstr_assert (tag);
    res->tag = tag;
 -  code_props_none_init (&res->destructor);
 -  code_props_none_init (&res->printer);
 +  if (loc)
 +    res->location = *loc;
 +  for (int i = 0; i < CODE_PROPS_SIZE; ++i)
 +    code_props_none_init (&res->props[i]);
  
    return res;
  }
  | Print a symbol.  |
  `-----------------*/
  
 -#define SYMBOL_ATTR_PRINT(Attr)                               \
 -  if (s->Attr)                                                \
 +#define SYMBOL_ATTR_PRINT(Attr)                         \
 +  if (s->Attr)                                          \
      fprintf (f, " %s { %s }", #Attr, s->Attr)
  
 -#define SYMBOL_CODE_PRINT(Attr)                         \
 -  if (s->Attr.code)                                     \
 -    fprintf (f, " %s { %s }", #Attr, s->Attr.code)
 +#define SYMBOL_CODE_PRINT(Attr)                                         \
 +  if (s->props[Attr].code)                                              \
 +    fprintf (f, " %s { %s }", #Attr, s->props[Attr].code)
  
  void
 -symbol_print (symbol *s, FILE *f)
 +symbol_print (symbol const *s, FILE *f)
  {
    if (s)
      {
  #undef SYMBOL_ATTR_PRINT
  #undef SYMBOL_CODE_PRINT
  
 +
 +/*----------------------------------.
 +| Whether S is a valid identifier.  |
 +`----------------------------------*/
 +
 +static bool
 +is_identifier (uniqstr s)
 +{
 +  static char const alphanum[26 + 26 + 1 + 10] =
 +    "abcdefghijklmnopqrstuvwxyz"
 +    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 +    "_"
 +    "0123456789";
 +  if (!s || ! memchr (alphanum, *s, sizeof alphanum - 10))
 +    return false;
 +  for (++s; *s; ++s)
 +    if (! memchr (alphanum, *s, sizeof alphanum))
 +      return false;
 +  return true;
 +}
 +
 +
 +/*-----------------------------------------------.
 +| Get the identifier associated to this symbol.  |
 +`-----------------------------------------------*/
 +uniqstr
 +symbol_id_get (symbol const *sym)
 +{
 +  aver (sym->user_token_number != USER_NUMBER_HAS_STRING_ALIAS);
 +  if (sym->alias)
 +    sym = sym->alias;
 +  return is_identifier (sym->tag) ? sym->tag : 0;
 +}
 +
 +
  /*------------------------------------------------------------------.
  | Complain that S's WHAT is redeclared at SECOND, and was first set |
  | at FIRST.                                                         |
@@@ -193,16 -150,20 +193,24 @@@ static voi
  symbol_redeclaration (symbol *s, const char *what, location first,
                        location second)
  {
-   complain_at (second, complaint, _("%s redeclaration for %s"), what, s->tag);
-   complain_at (first, complaint, _("previous declaration"));
+   unsigned i = 0;
 -  complain_at_indent (second, &i, _("%s redeclaration for %s"), what, s->tag);
++  complain_at_indent (second, complaint, &i,
++                      _("%s redeclaration for %s"), what, s->tag);
+   i += SUB_INDENT;
 -  complain_at_indent (first, &i, _("previous declaration"));
++  complain_at_indent (first, complaint, &i,
++                      _("previous declaration"));
  }
  
  static void
  semantic_type_redeclaration (semantic_type *s, const char *what, location first,
                               location second)
  {
-   complain_at (second, complaint, _("%s redeclaration for <%s>"), what, s->tag);
-   complain_at (first, complaint, _("previous declaration"));
+   unsigned i = 0;
 -  complain_at_indent (second, &i, _("%s redeclaration for <%s>"), what, s->tag);
++  complain_at_indent (second, complaint, &i,
++                      _("%s redeclaration for <%s>"), what, s->tag);
+   i += SUB_INDENT;
 -  complain_at_indent (first, &i, _("previous declaration"));
++  complain_at_indent (first, complaint, &i,
++                      _("previous declaration"));
  }
  
  
@@@ -218,73 -179,122 +226,73 @@@ symbol_type_set (symbol *sym, uniqstr t
    if (type_name)
      {
        if (sym->type_name)
 -      symbol_redeclaration (sym, "%type", sym->type_location, loc);
 +        symbol_redeclaration (sym, "%type", sym->type_location, loc);
        uniqstr_assert (type_name);
        sym->type_name = type_name;
        sym->type_location = loc;
      }
  }
  
 -/*-----------------------------------------.
 -| Set the DESTRUCTOR associated with SYM.  |
 -`-----------------------------------------*/
 +/*--------------------------------------------------------.
 +| Set the DESTRUCTOR or PRINTER associated with the SYM.  |
 +`--------------------------------------------------------*/
  
  void
 -symbol_destructor_set (symbol *sym, code_props const *destructor)
 +symbol_code_props_set (symbol *sym, code_props_type kind,
 +                       code_props const *code)
  {
 -  if (sym->destructor.code)
 -    symbol_redeclaration (sym, "%destructor", sym->destructor.location,
 -                          destructor->location);
 -  sym->destructor = *destructor;
 +  if (sym->props[kind].code)
 +    symbol_redeclaration (sym, code_props_type_string (kind),
 +                          sym->props[kind].location,
 +                          code->location);
 +  sym->props[kind] = *code;
  }
  
 -/*------------------------------------------.
 -| Set the DESTRUCTOR associated with TYPE.  |
 -`------------------------------------------*/
 +/*-----------------------------------------------------.
 +| Set the DESTRUCTOR or PRINTER associated with TYPE.  |
 +`-----------------------------------------------------*/
  
  void
 -semantic_type_destructor_set (semantic_type *type,
 -                              code_props const *destructor)
 +semantic_type_code_props_set (semantic_type *type,
 +                              code_props_type kind,
 +                              code_props const *code)
  {
 -  if (type->destructor.code)
 -    semantic_type_redeclaration (type, "%destructor",
 -                                 type->destructor.location,
 -                                 destructor->location);
 -  type->destructor = *destructor;
 +  if (type->props[kind].code)
 +    semantic_type_redeclaration (type, code_props_type_string (kind),
 +                                 type->props[kind].location,
 +                                 code->location);
 +  type->props[kind] = *code;
  }
  
 -/*---------------------------------------.
 -| Get the computed %destructor for SYM.  |
 -`---------------------------------------*/
 +/*---------------------------------------------------.
 +| Get the computed %destructor or %printer for SYM.  |
 +`---------------------------------------------------*/
  
 -code_props const *
 -symbol_destructor_get (symbol const *sym)
 +code_props *
 +symbol_code_props_get (symbol *sym, code_props_type kind)
  {
 -  /* Per-symbol %destructor.  */
 -  if (sym->destructor.code)
 -    return &sym->destructor;
 +  /* Per-symbol code props.  */
 +  if (sym->props[kind].code)
 +    return &sym->props[kind];
  
 -  /* Per-type %destructor.  */
 +  /* Per-type code props.  */
    if (sym->type_name)
      {
 -      code_props const *destructor =
 -        &semantic_type_get (sym->type_name)->destructor;
 -      if (destructor->code)
 -        return destructor;
 +      code_props *code =
 +        &semantic_type_get (sym->type_name, NULL)->props[kind];
 +      if (code->code)
 +        return code;
      }
  
 -  /* Apply default %destructor's only to user-defined symbols.  */
 -  if (sym->tag[0] == '$' || sym == errtoken)
 -    return &code_props_none;
 -
 -  if (sym->type_name)
 -    return &default_tagged_destructor;
 -  return &default_tagless_destructor;
 -}
 -
 -/*--------------------------------------.
 -| Set the PRINTER associated with SYM.  |
 -`--------------------------------------*/
 -
 -void
 -symbol_printer_set (symbol *sym, code_props const *printer)
 -{
 -  if (sym->printer.code)
 -    symbol_redeclaration (sym, "%printer",
 -                          sym->printer.location, printer->location);
 -  sym->printer = *printer;
 -}
 -
 -/*---------------------------------------.
 -| Set the PRINTER associated with TYPE.  |
 -`---------------------------------------*/
 -
 -void
 -semantic_type_printer_set (semantic_type *type, code_props const *printer)
 -{
 -  if (type->printer.code)
 -    semantic_type_redeclaration (type, "%printer",
 -                                 type->printer.location, printer->location);
 -  type->printer = *printer;
 -}
 -
 -/*------------------------------------.
 -| Get the computed %printer for SYM.  |
 -`------------------------------------*/
 -
 -code_props const *
 -symbol_printer_get (symbol const *sym)
 -{
 -  /* Per-symbol %printer.  */
 -  if (sym->printer.code)
 -    return &sym->printer;
 -
 -  /* Per-type %printer.  */
 -  if (sym->type_name)
 +  /* Apply default code props's only to user-defined symbols.  */
 +  if (sym->tag[0] != '$' && sym != errtoken)
      {
 -      code_props const *printer = &semantic_type_get (sym->type_name)->printer;
 -      if (printer->code)
 -        return printer;
 +      code_props *code =
 +        &semantic_type_get (sym->type_name ? "*" : "", NULL)->props[kind];
 +      if (code->code)
 +        return code;
      }
 -
 -  /* Apply the default %printer only to user-defined symbols.  */
 -  if (sym->tag[0] == '$' || sym == errtoken)
 -    return &code_props_none;
 -
 -  if (sym->type_name)
 -    return &default_tagged_printer;
 -  return &default_tagless_printer;
 +  return &code_props_none;
  }
  
  /*-----------------------------------------------------------------.
@@@ -298,7 -308,7 +306,7 @@@ symbol_precedence_set (symbol *sym, in
    if (a != undef_assoc)
      {
        if (sym->prec != 0)
 -      symbol_redeclaration (sym, assoc_to_string (a), sym->prec_location,
 +        symbol_redeclaration (sym, assoc_to_string (a), sym->prec_location,
                                loc);
        sym->prec = prec;
        sym->assoc = a;
  void
  symbol_class_set (symbol *sym, symbol_class class, location loc, bool declaring)
  {
 +  bool warned = false;
    if (sym->class != unknown_sym && sym->class != class)
      {
 -      complain_at (loc, _("symbol %s redefined"), sym->tag);
 -      sym->declared = false;
 +      complain_at (loc, complaint, _("symbol %s redefined"), sym->tag);
 +      // Don't report both "redefined" and "redeclared".
 +      warned = true;
      }
  
    if (class == nterm_sym && sym->class != nterm_sym)
  
    if (declaring)
      {
 -      if (sym->declared)
 -      warn_at (loc, _("symbol %s redeclared"), sym->tag);
 -      sym->declared = true;
 +      if (sym->status == declared && !warned)
 +        complain_at (loc, Wother, _("symbol %s redeclared"), sym->tag);
 +      sym->status = declared;
      }
  }
  
@@@ -356,8 -364,7 +364,8 @@@ symbol_user_token_number_set (symbol *s
      user_token_numberp = &sym->alias->user_token_number;
    if (*user_token_numberp != USER_NUMBER_UNDEFINED
        && *user_token_numberp != user_token_number)
 -    complain_at (loc, _("redefining user token number of %s"), sym->tag);
 +    complain_at (loc, complaint, _("redefining user token number of %s"),
 +                 sym->tag);
  
    *user_token_numberp = user_token_number;
    /* User defined $end token? */
      {
        endtoken = sym;
        /* It is always mapped to 0, so it was already counted in
 -       NTOKENS.  */
 +         NTOKENS.  */
        if (endtoken->number != NUMBER_UNDEFINED)
          --ntokens;
        endtoken->number = 0;
@@@ -383,51 -390,14 +391,51 @@@ symbol_check_defined (symbol *sym
  {
    if (sym->class == unknown_sym)
      {
 -      complain_at
 -      (sym->location,
 -       _("symbol %s is used, but is not defined as a token and has no rules"),
 -       sym->tag);
 +      assert (sym->status != declared);
 +      complain_at (sym->location,
 +                   sym->status == needed ? complaint : Wother,
 +                   _("symbol %s is used, but is not defined as a token"
 +                     " and has no rules"),
 +                   sym->tag);
        sym->class = nterm_sym;
        sym->number = nvars++;
      }
  
 +  for (int i = 0; i < 2; ++i)
 +    symbol_code_props_get (sym, i)->is_used = true;
 +
 +  /* Set the semantic type status associated to the current symbol to
 +     'declared' so that we could check semantic types unnecessary uses. */
 +  if (sym->type_name)
 +    {
 +      semantic_type *sem_type = semantic_type_get (sym->type_name, NULL);
 +      if (sem_type)
 +        sem_type->status = declared;
 +    }
 +
 +  return true;
 +}
 +
 +static inline bool
 +semantic_type_check_defined (semantic_type *sem_type)
 +{
 +  // <*> and <> do not have to be "declared".
 +  if (sem_type->status == declared
 +      || !*sem_type->tag
 +      || STREQ(sem_type->tag, "*"))
 +    {
 +      for (int i = 0; i < 2; ++i)
 +        if (sem_type->props[i].kind != CODE_PROPS_NONE
 +            && ! sem_type->props[i].is_used)
 +          complain_at (sem_type->location, Wother,
 +                       _("useless %s for type <%s>"),
 +                       code_props_type_string (i), sem_type->tag);
 +    }
 +  else
 +    complain_at (sem_type->location, Wother,
 +                 _("type <%s> is used, but is not associated to any symbol"),
 +                 sem_type->tag);
 +
    return true;
  }
  
@@@ -437,23 -407,16 +445,23 @@@ symbol_check_defined_processor (void *s
    return symbol_check_defined (sym);
  }
  
 +static bool
 +semantic_type_check_defined_processor (void *sem_type,
 +                                       void *null ATTRIBUTE_UNUSED)
 +{
 +  return semantic_type_check_defined (sem_type);
 +}
 +
  
  void
  symbol_make_alias (symbol *sym, symbol *str, location loc)
  {
    if (str->alias)
 -    warn_at (loc, _("symbol %s used more than once as a literal string"),
 -             str->tag);
 +    complain_at (loc, Wother,
 +              _("symbol %s used more than once as a literal string"), str->tag);
    else if (sym->alias)
 -    warn_at (loc, _("symbol %s given more than one literal string"),
 -             sym->tag);
 +    complain_at (loc, Wother,
 +              _("symbol %s given more than one literal string"), sym->tag);
    else
      {
        str->class = token_sym;
@@@ -486,32 -449,42 +494,32 @@@ symbol_check_alias_consistency (symbol 
    if (str->type_name != sym->type_name)
      {
        if (str->type_name)
 -      symbol_type_set (sym, str->type_name, str->type_location);
 +        symbol_type_set (sym, str->type_name, str->type_location);
        else
 -      symbol_type_set (str, sym->type_name, sym->type_location);
 +        symbol_type_set (str, sym->type_name, sym->type_location);
      }
  
  
 -  if (str->destructor.code || sym->destructor.code)
 -    {
 -      if (str->destructor.code)
 -      symbol_destructor_set (sym, &str->destructor);
 -      else
 -      symbol_destructor_set (str, &sym->destructor);
 -    }
 -
 -  if (str->printer.code || sym->printer.code)
 -    {
 -      if (str->printer.code)
 -      symbol_printer_set (sym, &str->printer);
 -      else
 -      symbol_printer_set (str, &sym->printer);
 -    }
 +  for (int i = 0; i < CODE_PROPS_SIZE; ++i)
 +    if (str->props[i].code)
 +      symbol_code_props_set (sym, i, &str->props[i]);
 +    else if (sym->props[i].code)
 +      symbol_code_props_set (str, i, &sym->props[i]);
  
    if (sym->prec || str->prec)
      {
        if (str->prec)
 -      symbol_precedence_set (sym, str->prec, str->assoc,
 -                             str->prec_location);
 +        symbol_precedence_set (sym, str->prec, str->assoc,
 +                               str->prec_location);
        else
 -      symbol_precedence_set (str, sym->prec, sym->assoc,
 -                             sym->prec_location);
 +        symbol_precedence_set (str, sym->prec, sym->assoc,
 +                               sym->prec_location);
      }
  }
  
  static bool
  symbol_check_alias_consistency_processor (void *this,
 -                                        void *null ATTRIBUTE_UNUSED)
 +                                          void *null ATTRIBUTE_UNUSED)
  {
    symbol_check_alias_consistency (this);
    return true;
@@@ -546,6 -519,7 +554,7 @@@ symbol_pack_processor (void *this, voi
  static void
  user_token_number_redeclaration (int num, symbol *first, symbol *second)
  {
+   unsigned i = 0;
    /* User token numbers are not assigned during the parsing, but in a
       second step, via a traversal of the symbol table sorted on tag.
  
        first = second;
        second = tmp;
      }
-   complain_at (second->location, complaint,
-                _("user token number %d redeclaration for %s"),
-                num, second->tag);
-   complain_at (first->location, complaint, _("previous declaration for %s"),
-                first->tag);
 -  complain_at_indent (second->location, &i,
++  complain_at_indent (second->location, complaint, &i,
+                       _("user token number %d redeclaration for %s"),
+                       num, second->tag);
 -  complain_at_indent (first->location, &i,
++  complain_at_indent (first->location, complaint, &i,
+                       _("previous declaration for %s"),
+                       first->tag);
  }
  
  /*--------------------------------------------------.
@@@ -577,7 -552,7 +587,7 @@@ symbol_translation (symbol *this
      {
        /* A token which translation has already been set? */
        if (token_translations[this->user_token_number] != undeftoken->number)
 -      user_token_number_redeclaration
 +        user_token_number_redeclaration
            (this->user_token_number,
             symbols[token_translations[this->user_token_number]],
             this);
@@@ -665,15 -640,15 +675,15 @@@ voi
  symbols_new (void)
  {
    symbol_table = hash_initialize (HT_INITIAL_CAPACITY,
 -                                NULL,
 -                                hash_symbol_hasher,
 -                                hash_symbol_comparator,
 -                                free);
 +                                  NULL,
 +                                  hash_symbol_hasher,
 +                                  hash_symbol_comparator,
 +                                  free);
    semantic_type_table = hash_initialize (HT_INITIAL_CAPACITY,
 -                                       NULL,
 -                                       hash_semantic_type_hasher,
 -                                       hash_semantic_type_comparator,
 -                                       free);
 +                                         NULL,
 +                                         hash_semantic_type_hasher,
 +                                         hash_semantic_type_comparator,
 +                                         free);
  }
  
  
@@@ -709,7 -684,7 +719,7 @@@ symbol_from_uniqstr (const uniqstr key
  `-----------------------------------------------------------------------*/
  
  semantic_type *
 -semantic_type_from_uniqstr (const uniqstr key)
 +semantic_type_from_uniqstr (const uniqstr key, const location *loc)
  {
    semantic_type probe;
    semantic_type *entry;
    if (!entry)
      {
        /* First insertion in the hash. */
 -      entry = semantic_type_new (key);
 +      entry = semantic_type_new (key, loc);
        if (!hash_insert (semantic_type_table, entry))
          xalloc_die ();
      }
@@@ -746,9 -721,9 +756,9 @@@ symbol_get (const char *key, location l
  `-----------------------------------------------------------------------*/
  
  semantic_type *
 -semantic_type_get (const char *key)
 +semantic_type_get (const char *key, const location *loc)
  {
 -  return semantic_type_from_uniqstr (uniqstr_new (key));
 +  return semantic_type_from_uniqstr (uniqstr_new (key), loc);
  }
  
  
@@@ -811,20 -786,20 +821,20 @@@ symbols_cmp_qsort (void const *a, void 
  }
  
  static void
 -symbols_do (Hash_processor processor, void *processor_data)
 +symbols_do (Hash_processor processor, void *processor_data,
 +            struct hash_table *table, symbol **sorted)
  {
 -  size_t count = hash_get_n_entries (symbol_table);
 -  if (!symbols_sorted)
 +  size_t count = hash_get_n_entries (table);
 +  if (!sorted)
      {
 -      symbols_sorted = xnmalloc (count, sizeof *symbols_sorted);
 -      hash_get_entries (symbol_table, (void**)symbols_sorted, count);
 -      qsort (symbols_sorted, count, sizeof *symbols_sorted,
 -             symbols_cmp_qsort);
 +      sorted = xnmalloc (count, sizeof *sorted);
 +      hash_get_entries (table, (void**)sorted, count);
 +      qsort (sorted, count, sizeof *sorted, symbols_cmp_qsort);
      }
    {
      size_t i;
      for (i = 0; i < count; ++i)
 -      processor (symbols_sorted[i], processor_data);
 +      processor (sorted[i], processor_data);
    }
  }
  
  void
  symbols_check_defined (void)
  {
 -  symbols_do (symbol_check_defined_processor, NULL);
 +  symbols_do (symbol_check_defined_processor, NULL,
 +              symbol_table, symbols_sorted);
 +  symbols_do (semantic_type_check_defined_processor, NULL,
 +              semantic_type_table, semantic_types_sorted);
  }
  
  /*------------------------------------------------------------------.
@@@ -860,12 -832,12 +870,12 @@@ symbols_token_translations_init (void
      {
        symbol *this = symbols[i];
        if (this->user_token_number != USER_NUMBER_UNDEFINED)
 -      {
 -        if (this->user_token_number > max_user_token_number)
 -          max_user_token_number = this->user_token_number;
 -        if (this->user_token_number == 256)
 -          num_256_available_p = false;
 -      }
 +        {
 +          if (this->user_token_number > max_user_token_number)
 +            max_user_token_number = this->user_token_number;
 +          if (this->user_token_number == 256)
 +            num_256_available_p = false;
 +        }
      }
  
    /* If 256 is not used, assign it to error, to follow POSIX.  */
      {
        symbol *this = symbols[i];
        if (this->user_token_number == USER_NUMBER_UNDEFINED)
 -      this->user_token_number = ++max_user_token_number;
 +        this->user_token_number = ++max_user_token_number;
        if (this->user_token_number > max_user_token_number)
 -      max_user_token_number = this->user_token_number;
 +        max_user_token_number = this->user_token_number;
      }
  
    token_translations = xnmalloc (max_user_token_number + 1,
 -                               sizeof *token_translations);
 +                                 sizeof *token_translations);
  
 -  /* Initialize all entries for literal tokens to 2, the internal
 -     token number for $undefined, which represents all invalid inputs.
 -     */
 +  /* Initialize all entries for literal tokens to the internal token
 +     number for $undefined, which represents all invalid inputs.  */
    for (i = 0; i < max_user_token_number + 1; i++)
      token_translations[i] = undeftoken->number;
 -  symbols_do (symbol_translation_processor, NULL);
 +  symbols_do (symbol_translation_processor, NULL,
 +              symbol_table, symbols_sorted);
  }
  
  
  void
  symbols_pack (void)
  {
 -  symbols_do (symbol_check_alias_consistency_processor, NULL);
 +  symbols_do (symbol_check_alias_consistency_processor, NULL,
 +              symbol_table, symbols_sorted);
  
    symbols = xcalloc (nsyms, sizeof *symbols);
 -  symbols_do (symbol_pack_processor, NULL);
 +  symbols_do (symbol_pack_processor, NULL, symbol_table, symbols_sorted);
  
    /* Aliases leave empty slots in symbols, so remove them.  */
    {
    symbols_token_translations_init ();
  
    if (startsymbol->class == unknown_sym)
 -    fatal_at (startsymbol_location,
 -            _("the start symbol %s is undefined"),
 -            startsymbol->tag);
 +    complain_at (startsymbol_location, fatal,
 +                 _("the start symbol %s is undefined"),
 +                 startsymbol->tag);
    else if (startsymbol->class == token_sym)
 -    fatal_at (startsymbol_location,
 -            _("the start symbol %s is a token"),
 -            startsymbol->tag);
 -}
 -
 -
 -/*--------------------------------------------------.
 -| Set default tagged/tagless %destructor/%printer.  |
 -`--------------------------------------------------*/
 -
 -void
 -default_tagged_destructor_set (code_props const *destructor)
 -{
 -  if (default_tagged_destructor.code)
 -    {
 -      unsigned i = 0;
 -      complain_at_indent (destructor->location, &i,
 -                          _("redeclaration for default tagged %%destructor"));
 -      i += SUB_INDENT;
 -      complain_at_indent (default_tagged_destructor.location, &i,
 -                        _("previous declaration"));
 -    }
 -  default_tagged_destructor = *destructor;
 -}
 -
 -void
 -default_tagless_destructor_set (code_props const *destructor)
 -{
 -  if (default_tagless_destructor.code)
 -    {
 -      unsigned i = 0;
 -      complain_at_indent (destructor->location, &i,
 -                          _("redeclaration for default tagless %%destructor"));
 -      i += SUB_INDENT;
 -      complain_at_indent (default_tagless_destructor.location, &i,
 -                          _("previous declaration"));
 -    }
 -  default_tagless_destructor = *destructor;
 -}
 -
 -void
 -default_tagged_printer_set (code_props const *printer)
 -{
 -  if (default_tagged_printer.code)
 -    {
 -      unsigned i = 0;
 -      complain_at_indent (printer->location, &i,
 -                          _("redeclaration for default tagged %%printer"));
 -      i += SUB_INDENT;
 -      complain_at_indent (default_tagged_printer.location, &i,
 -                        _("previous declaration"));
 -    }
 -  default_tagged_printer = *printer;
 -}
 -
 -void
 -default_tagless_printer_set (code_props const *printer)
 -{
 -  if (default_tagless_printer.code)
 -    {
 -      unsigned i = 0;
 -      complain_at_indent (printer->location, &i,
 -                          _("redeclaration for default tagless %%printer"));
 -      i += SUB_INDENT;
 -      complain_at_indent (default_tagless_printer.location, &i,
 -                        _("previous declaration"));
 -    }
 -  default_tagless_printer = *printer;
 +    complain_at (startsymbol_location, fatal,
 +                 _("the start symbol %s is a token"),
 +                 startsymbol->tag);
  }
diff --combined tests/conflicts.at
index 83ef1286a84cc13b1967b4b375c9b9a132ab6245,3934a6cf13b4bb97a5d87017eeb6cc48940498e8..b3f67098afa2bf6deaced4029f85d685900fe93d
@@@ -1,6 -1,7 +1,6 @@@
  # Exercising Bison on conflicts.                         -*- Autotest -*-
  
 -# Copyright (C) 2002-2005, 2007, 2009-2012 Free Software Foundation,
 -# Inc.
 +# Copyright (C) 2002-2005, 2007-2012 Free Software Foundation, Inc.
  
  # This program is free software: you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
@@@ -37,7 -38,7 +37,7 @@@ e: 'e' | /* Nothing. */
  ]])
  
  AT_BISON_CHECK([-o input.c input.y], 0, [],
 -[[input.y:4.9: warning: rule useless in parser due to conflicts: e: /* empty */
 +[[input.y:4.9: warning: rule useless in parser due to conflicts: e: /* empty */ [-Wother]
  ]])
  
  AT_CLEANUP
@@@ -141,11 -142,11 +141,11 @@@ AT_CLEANU
  
  
  
 -## -------------------------------------- ##
 -## %error-verbose and consistent errors.  ##
 -## -------------------------------------- ##
 +## ------------------------------------------- ##
 +## parse.error=verbose and consistent errors.  ##
 +## ------------------------------------------- ##
  
 -AT_SETUP([[%error-verbose and consistent errors]])
 +AT_SETUP([[parse.error=verbose and consistent errors]])
  
  m4_pushdef([AT_CONSISTENT_ERRORS_CHECK], [
  
@@@ -163,6 -164,7 +163,6 @@@ AT_SKEL_JAVA_IF([AT_DATA], [AT_DATA_GRA
  }]], [[
  
  %code {]AT_SKEL_CC_IF([[
 -  #include <cassert>
    #include <string>]], [[
    #include <assert.h>
    #include <stdio.h>
  
  ]$1[
  
 -%error-verbose
 +%define parse.error verbose
  
  %%
  
@@@ -370,7 -372,7 +370,7 @@@ error-reduce
  ;
  
  consistent-reduction: /*empty*/ {
 -  assert (yychar == ]AT_SKEL_CC_IF([[yyempty_]], [[YYEMPTY]])[);
 +  assert (yychar == YYEMPTY);
    yylval = 0;
    yychar = 'b';
  } ;
@@@ -394,7 -396,11 +394,7 @@@ AT_CONSISTENT_ERRORS_CHECK([[%glr-parse
                             [AT_USER_ACTION_GRAMMAR],
                             [AT_USER_ACTION_INPUT],
                             [['b']], [[none]])
 -AT_CONSISTENT_ERRORS_CHECK([[%language "c++"]],
 -                           [AT_USER_ACTION_GRAMMAR],
 -                           [AT_USER_ACTION_INPUT],
 -                           [['b']], [[none]])
 -# No Java test because yychar cannot be manipulated by users.
 +# No C++ or Java test because yychar cannot be manipulated by users.
  
  AT_CONSISTENT_ERRORS_CHECK([[%define lr.default-reductions consistent]],
                             [AT_USER_ACTION_GRAMMAR],
@@@ -498,7 -504,7 +498,7 @@@ AT_BISON_OPTION_POPDEF
  # Show canonical LR's failure.
  AT_BISON_CHECK([[-Dlr.type=canonical-lr -o input.c input.y]],
                 [[0]], [[]],
 -[[input.y: conflicts: 2 shift/reduce
 +[[input.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
  ]])
  AT_COMPILE([[input]])
  AT_PARSER_CHECK([[./input]], [[1]], [[]],
  # It's corrected by LAC.
  AT_BISON_CHECK([[-Dlr.type=canonical-lr -Dparse.lac=full \
                   -o input.c input.y]], [[0]], [[]],
 -[[input.y: conflicts: 2 shift/reduce
 +[[input.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
  ]])
  AT_COMPILE([[input]])
  AT_PARSER_CHECK([[./input]], [[1]], [[]],
  # IELR is sufficient when LAC is used.
  AT_BISON_CHECK([[-Dlr.type=ielr -Dparse.lac=full -o input.c input.y]],
                 [[0]], [[]],
 -[[input.y: conflicts: 2 shift/reduce
 +[[input.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
  ]])
  AT_COMPILE([[input]])
  AT_PARSER_CHECK([[./input]], [[1]], [[]],
@@@ -542,8 -548,8 +542,8 @@@ exp: exp OP exp | NUM
  ]])
  
  AT_BISON_CHECK([-o input.c --report=all input.y], 0, [],
 -[input.y: conflicts: 1 shift/reduce
 -])
 +[[input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 +]])
  
  # Check the contents of the report.
  AT_CHECK([cat input.output], [],
@@@ -735,62 -741,6 +735,62 @@@ state 
  AT_CLEANUP
  
  
 +## ---------------------- ##
 +## %precedence suffices.  ##
 +## ---------------------- ##
 +
 +AT_SETUP([%precedence suffices])
 +
 +AT_DATA([input.y],
 +[[%precedence "then"
 +%precedence "else"
 +%%
 +stmt:
 +  "if" cond "then" stmt
 +| "if" cond "then" stmt "else" stmt
 +| "stmt"
 +;
 +
 +cond:
 +  "exp"
 +;
 +]])
 +
 +AT_BISON_CHECK([-o input.c input.y])
 +
 +AT_CLEANUP
 +
 +
 +## ------------------------------ ##
 +## %precedence does not suffice.  ##
 +## ------------------------------ ##
 +
 +AT_SETUP([%precedence does not suffice])
 +
 +AT_DATA([input.y],
 +[[%precedence "then"
 +%precedence "else"
 +%%
 +stmt:
 +  "if" cond "then" stmt
 +| "if" cond "then" stmt "else" stmt
 +| "stmt"
 +;
 +
 +cond:
 +  "exp"
 +| cond "then" cond
 +;
 +]])
 +
 +AT_BISON_CHECK([-o input.c input.y], 0, [],
 +[[input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 +input.y:12.3-18: warning: rule useless in parser due to conflicts: cond: cond "then" cond [-Wother]
 +]])
 +
 +AT_CLEANUP
 +
 +
  ## -------------------------------- ##
  ## Defaulted Conflicted Reduction.  ##
  ## -------------------------------- ##
@@@ -828,8 -778,8 +828,8 @@@ id : '0'
  ]])
  
  AT_BISON_CHECK([-o input.c --report=all input.y], 0, [],
 -[[input.y: conflicts: 1 reduce/reduce
 -input.y:4.6-8: warning: rule useless in parser due to conflicts: id: '0'
 +[[input.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +input.y:4.6-8: warning: rule useless in parser due to conflicts: id: '0' [-Wother]
  ]])
  
  # Check the contents of the report.
@@@ -945,8 -895,9 +945,8 @@@ exp: exp OP exp | NUM
  ]])
  
  AT_BISON_CHECK([-o input.c input.y], 1, [],
- [[input.y: shift/reduce conflicts: 1 found, 0 expected
 -[input.y: conflicts: 1 shift/reduce
 -input.y: error: expected 0 shift/reduce conflicts
 -])
++[[input.y: error: shift/reduce conflicts: 1 found, 0 expected
 +]])
  AT_CLEANUP
  
  
@@@ -981,8 -932,9 +981,8 @@@ exp: exp OP exp | NUM
  ]])
  
  AT_BISON_CHECK([-o input.c input.y], 1, [],
- [[input.y: shift/reduce conflicts: 1 found, 2 expected
 -[input.y: conflicts: 1 shift/reduce
 -input.y: error: expected 2 shift/reduce conflicts
 -])
++[[input.y: error: shift/reduce conflicts: 1 found, 2 expected
 +]])
  AT_CLEANUP
  
  
@@@ -1000,8 -952,9 +1000,8 @@@ a: 'a'
  ]])
  
  AT_BISON_CHECK([-o input.c input.y], 1, [],
- [[input.y: reduce/reduce conflicts: 1 found, 0 expected
 -[input.y: conflicts: 1 reduce/reduce
 -input.y: error: expected 0 reduce/reduce conflicts
 -])
++[[input.y: error: reduce/reduce conflicts: 1 found, 0 expected
 +]])
  AT_CLEANUP
  
  
@@@ -1043,7 -996,7 +1043,7 @@@ e:   e '+' 
  ]])
  
  AT_BISON_CHECK([-o input.c input.y], 0, [],
 -[[input.y: conflicts: 4 shift/reduce
 +[[input.y: warning: 4 shift/reduce conflicts [-Wconflicts-sr]
  ]])
  AT_CLEANUP
  
@@@ -1145,15 -1098,14 +1145,15 @@@ reported_conflicts
  ]])
  
  AT_BISON_CHECK([[--report=all input.y]], 0, [],
 -[[input.y: conflicts: 1 shift/reduce, 1 reduce/reduce
 -input.y:12.5-20: warning: rule useless in parser due to conflicts: resolved_conflict: 'a' unreachable1
 -input.y:20.5-20: warning: rule useless in parser due to conflicts: unreachable1: 'a' unreachable2
 -input.y:21.4: warning: rule useless in parser due to conflicts: unreachable1: /* empty */
 -input.y:25.13: warning: rule useless in parser due to conflicts: unreachable2: /* empty */
 -input.y:25.16: warning: rule useless in parser due to conflicts: unreachable2: /* empty */
 -input.y:31.5-7: warning: rule useless in parser due to conflicts: reported_conflicts: 'a'
 -input.y:32.4: warning: rule useless in parser due to conflicts: reported_conflicts: /* empty */
 +[[input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 +input.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +input.y:12.5-20: warning: rule useless in parser due to conflicts: resolved_conflict: 'a' unreachable1 [-Wother]
 +input.y:20.5-20: warning: rule useless in parser due to conflicts: unreachable1: 'a' unreachable2 [-Wother]
 +input.y:21.4: warning: rule useless in parser due to conflicts: unreachable1: /* empty */ [-Wother]
 +input.y:25.13: warning: rule useless in parser due to conflicts: unreachable2: /* empty */ [-Wother]
 +input.y:25.16: warning: rule useless in parser due to conflicts: unreachable2: /* empty */ [-Wother]
 +input.y:31.5-7: warning: rule useless in parser due to conflicts: reported_conflicts: 'a' [-Wother]
 +input.y:32.4: warning: rule useless in parser due to conflicts: reported_conflicts: /* empty */ [-Wother]
  ]])
  
  AT_CHECK([[cat input.output]], 0,
@@@ -1298,12 -1250,11 +1298,12 @@@ AT_DATA([[input-keep.y]]
  AT_CHECK([[cat input.y >> input-keep.y]])
  
  AT_BISON_CHECK([[input-keep.y]], 0, [],
 -[[input-keep.y: conflicts: 2 shift/reduce, 2 reduce/reduce
 -input-keep.y:22.4: warning: rule useless in parser due to conflicts: unreachable1: /* empty */
 -input-keep.y:26.16: warning: rule useless in parser due to conflicts: unreachable2: /* empty */
 -input-keep.y:32.5-7: warning: rule useless in parser due to conflicts: reported_conflicts: 'a'
 -input-keep.y:33.4: warning: rule useless in parser due to conflicts: reported_conflicts: /* empty */
 +[[input-keep.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
 +input-keep.y: warning: 2 reduce/reduce conflicts [-Wconflicts-rr]
 +input-keep.y:22.4: warning: rule useless in parser due to conflicts: unreachable1: /* empty */ [-Wother]
 +input-keep.y:26.16: warning: rule useless in parser due to conflicts: unreachable2: /* empty */ [-Wother]
 +input-keep.y:32.5-7: warning: rule useless in parser due to conflicts: reported_conflicts: 'a' [-Wother]
 +input-keep.y:33.4: warning: rule useless in parser due to conflicts: reported_conflicts: /* empty */ [-Wother]
  ]])
  
  AT_CLEANUP
@@@ -1458,40 -1409,9 +1458,40 @@@ state 
  AT_CLEANUP
  
  
 -## --------------------------------- ##
 -## -W versus %expect and %expect-rr  ##
 -## --------------------------------- ##
 +## -------------------- ##
 +## %expect-rr non GLR.  ##
 +## -------------------- ##
 +
 +AT_SETUP([[%expect-rr non GLR]])
 +
 +AT_DATA([[1.y]],
 +[[%expect-rr 0
 +%%
 +exp: 'a'
 +]])
 +
 +AT_BISON_CHECK([[1.y]], [[0]], [],
 +[[1.y: warning: %expect-rr applies only to GLR parsers [-Wother]
 +]])
 +
 +AT_DATA([[2.y]],
 +[[%expect-rr 1
 +%%
 +exp: 'a' | 'a';
 +]])
 +
 +AT_BISON_CHECK([[2.y]], [[0]], [],
 +[[2.y: warning: %expect-rr applies only to GLR parsers [-Wother]
 +2.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +2.y:3.12-14: warning: rule useless in parser due to conflicts: exp: 'a' [-Wother]
 +]])
 +
 +AT_CLEANUP
 +
 +
 +## ---------------------------------- ##
 +## -W versus %expect and %expect-rr.  ##
 +## ---------------------------------- ##
  
  AT_SETUP([[-W versus %expect and %expect-rr]])
  
@@@ -1517,27 -1437,17 +1517,27 @@@ B: 
  ]])
  
  AT_BISON_CHECK([[sr-rr.y]], [[0]], [[]],
 -[[sr-rr.y: conflicts: 1 shift/reduce, 1 reduce/reduce
 +[[sr-rr.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 +sr-rr.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
  ]])
  AT_BISON_CHECK([[-Wno-conflicts-sr sr-rr.y]], [[0]], [[]],
 -[[sr-rr.y: conflicts: 1 reduce/reduce
 +[[sr-rr.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
  ]])
  AT_BISON_CHECK([[-Wno-conflicts-rr sr-rr.y]], [[0]], [[]],
 -[[sr-rr.y: conflicts: 1 shift/reduce
 +[[sr-rr.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
  ]])
  
 -[for gram in sr-rr sr rr; do
 +[
 +# This is piece of code is rather complex for a simple task: try every
 +# combinaison of (0 or 1 real SR) x (0 or 1 real RR) x (don't %expect
 +# or %expect 0, 1, or 2 SR) x (don't %expect-rr or %expect-rr 0, 1, or 2
 +# RR).
 +
 +# Number and types of genuine conflicts in the grammar.
 +for gram in sr-rr sr rr; do
 +  # Number of expected s/r conflicts.
    for sr_exp_i in '' 0 1 2; do
 +    # Number of expected r/r conflicts.
      for rr_exp_i in '' 0 1 2; do
        test -z "$sr_exp_i" && test -z "$rr_exp_i" && continue
  
        echo "$directives" > $file
        cat $gram.y >> $file
  
 -      # Count actual conflicts.
 -      conflicts=
 -      sr_count=0
 -      rr_count=0
 -      if test $gram = sr || test $gram = sr-rr; then
 -        conflicts="1 shift/reduce"
 -        sr_count=1
 -      fi
 -      if test $gram = rr || test $gram = sr-rr; then
 -        if test -n "$conflicts"; then
 -          conflicts="$conflicts, "
 -        fi
 -        conflicts="${conflicts}1 reduce/reduce"
 -        rr_count=1
 -      fi
 +      # Number of found conflicts.
 +      case $gram in
 +        (sr)    sr_count=1; rr_count=0;;
 +        (rr)    sr_count=0; rr_count=1;;
 +        (sr-rr) sr_count=1; rr_count=1;;
 +      esac
 +
 +      # Update number of expected conflicts: if %expect is given then
 +      # %expect-rr defaults to 0, and vice-versa.  Leave empty if
 +      # nothing expected.
 +      case $sr_exp_i:$rr_exp_i in
 +        ?:) rr_exp_i=0;;
 +        :?) sr_exp_i=0;;
 +      esac
  
        # Run tests.
        if test $sr_count -eq $sr_exp && test $rr_count -eq $rr_exp; then
          ]AT_BISON_CHECK([[-Wnone $file]])[
          ]AT_BISON_CHECK([[-Werror $file]])[
        else
 -        echo "$file: conflicts: $conflicts" > experr
 -        if test $sr_count -ne $sr_exp; then
 -          if test $sr_exp -ne 1; then s=s; else s= ; fi
 -          echo "$file: error: expected $sr_exp shift/reduce conflict$s" >> experr
 -        fi
 -        if test $rr_count -ne $rr_exp; then
 -          if test $rr_exp -ne 1; then s=s; else s= ; fi
 -          echo "$file: error: expected $rr_exp reduce/reduce conflict$s" >> experr
 -        fi
 +        {
 +          if test -z "$sr_exp_i" && test "$sr_count" -ne 0; then
 +            echo "warning: $sr_count shift/reduce conflicts"
 +          elif test "$sr_exp_i" -ne "$sr_count"; then
-             echo "shift/reduce conflicts: $sr_count found, $sr_exp_i expected"
++            echo "error: shift/reduce conflicts: $sr_count found, $sr_exp_i expected"
 +          fi
 +          if test -z "$rr_exp_i" && test "$rr_count" -ne 0; then
 +            echo "warning: $rr_count reduce/reduce conflicts"
 +          elif test "$rr_exp_i" -ne "$rr_count"; then
-             echo "reduce/reduce conflicts: $rr_count found, $rr_exp_i expected"
++            echo "error: reduce/reduce conflicts: $rr_count found, $rr_exp_i expected"
 +          fi
 +        } | sed -e "s/^/$file: /" > experr
          ]AT_BISON_CHECK([[-Wnone $file]], [[1]], [[]], [[experr]])[
          ]AT_BISON_CHECK([[-Werror $file]], [[1]], [[]], [[experr]])[
        fi
diff --combined tests/glr-regression.at
index 98ebdfa6d5c26742cdda049e35bc4269631bc5c7,aacc57c842eaf07acd05479da4fe8006f8515180..b376c1c05ea771bdadfa0beef1c4f033b478a07b
@@@ -93,8 -93,8 +93,8 @@@ yylex (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr1.c glr-regr1.y]], 0, [],
 -[glr-regr1.y: conflicts: 1 shift/reduce
 -])
 +[[glr-regr1.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 +]])
  AT_COMPILE([glr-regr1])
  AT_PARSER_CHECK([[echo BPBPB | ./glr-regr1]], 0,
  [[E -> 'B'
@@@ -208,8 -208,8 +208,8 @@@ main (int argc, char **argv
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr2a.c glr-regr2a.y]], 0, [],
 -[glr-regr2a.y: conflicts: 2 shift/reduce
 -])
 +[[glr-regr2a.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
 +]])
  AT_COMPILE([glr-regr2a])
  
  AT_PARSER_CHECK([[echo s VARIABLE_1 t v x q | ./glr-regr2a]], 0,
@@@ -325,9 -325,8 +325,9 @@@ main(int argc, char* argv[]
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr3.c glr-regr3.y]], 0, [],
 -[glr-regr3.y: conflicts: 1 shift/reduce, 1 reduce/reduce
 -])
 +[[glr-regr3.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 +glr-regr3.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr3])
  
  AT_PARSER_CHECK([[echo p1 t4 o2 p1 p1 t1 o1 t2 p2 o1 t3 p2 p2 | ./glr-regr3]],
@@@ -418,8 -417,8 +418,8 @@@ merge (YYSTYPE s1, YYSTYPE s2
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr4.c glr-regr4.y]], 0, [],
 -[glr-regr4.y: conflicts: 1 reduce/reduce
 -])
 +[[glr-regr4.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr4])
  
  AT_PARSER_CHECK([[./glr-regr4]], 0,
@@@ -478,8 -477,8 +478,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr5.c glr-regr5.y]], 0, [],
 -[glr-regr5.y: conflicts: 1 reduce/reduce
 -])
 +[[glr-regr5.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr5])
  
  AT_PARSER_CHECK([[./glr-regr5]], 0, [],
@@@ -530,8 -529,8 +530,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr6.c glr-regr6.y]], 0, [],
 -[glr-regr6.y: conflicts: 1 reduce/reduce
 -])
 +[[glr-regr6.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr6])
  
  AT_PARSER_CHECK([[./glr-regr6]], 0,
@@@ -619,8 -618,8 +619,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr7.c glr-regr7.y]], 0, [],
 -[glr-regr7.y: conflicts: 2 reduce/reduce
 -])
 +[[glr-regr7.y: warning: 2 reduce/reduce conflicts [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr7])
  
  AT_PARSER_CHECK([[./glr-regr7]], 2, [],
@@@ -713,8 -712,8 +713,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr8.c glr-regr8.y]], 0, [],
 -[glr-regr8.y: conflicts: 1 reduce/reduce
 -])
 +[[glr-regr8.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr8])
  
  AT_PARSER_CHECK([[./glr-regr8]], 0,
@@@ -793,8 -792,8 +793,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr9.c glr-regr9.y]], 0, [],
 -[glr-regr9.y: conflicts: 1 reduce/reduce
 -])
 +[[glr-regr9.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr9])
  
  AT_PARSER_CHECK([[./glr-regr9]], 0, [],
@@@ -849,8 -848,8 +849,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr10.c glr-regr10.y]], 0, [],
 -[glr-regr10.y: conflicts: 1 reduce/reduce
 -])
 +[[glr-regr10.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr10])
  
  AT_PARSER_CHECK([[./glr-regr10]], 0, [], [])
@@@ -907,8 -906,8 +907,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr11.c glr-regr11.y]], 0, [],
 -[glr-regr11.y: conflicts: 1 reduce/reduce
 -])
 +[[glr-regr11.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr11])
  
  AT_PARSER_CHECK([[./glr-regr11]], 0, [], [])
@@@ -1028,9 -1027,8 +1028,9 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr12.c glr-regr12.y]], 0, [],
 -[glr-regr12.y: conflicts: 1 shift/reduce, 1 reduce/reduce
 -])
 +[[glr-regr12.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 +glr-regr12.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr12])
  
  AT_PARSER_CHECK([[./glr-regr12]], 0, [], [])
@@@ -1359,8 -1357,8 +1359,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr14.c glr-regr14.y]], 0, [],
 -[glr-regr14.y: conflicts: 3 reduce/reduce
 -])
 +[[glr-regr14.y: warning: 3 reduce/reduce conflicts [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr14])
  
  AT_PARSER_CHECK([[./glr-regr14]], 0,
@@@ -1452,8 -1450,8 +1452,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr15.c glr-regr15.y]], 0, [],
 -[glr-regr15.y: conflicts: 2 reduce/reduce
 -])
 +[[glr-regr15.y: warning: 2 reduce/reduce conflicts [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr15])
  
  AT_PARSER_CHECK([[./glr-regr15]], 0, [],
@@@ -1512,8 -1510,8 +1512,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr16.c glr-regr16.y]], 0, [],
 -[glr-regr16.y: conflicts: 1 reduce/reduce
 -])
 +[[glr-regr16.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr16])
  
  AT_PARSER_CHECK([[./glr-regr16]], 0, [],
@@@ -1597,8 -1595,8 +1597,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr17.c glr-regr17.y]], 0, [],
 -[glr-regr17.y: conflicts: 3 reduce/reduce
 -])
 +[[glr-regr17.y: warning: 3 reduce/reduce conflicts [-Wconflicts-rr]
 +]])
  AT_COMPILE([glr-regr17])
  
  AT_PARSER_CHECK([[./glr-regr17]], 0, [],
@@@ -1652,11 -1650,11 +1652,11 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o glr-regr18.c glr-regr18.y]], 1, [],
- [glr-regr18.y:26.18-24: result type clash on merge function 'merge': <type2> != <type1>
- glr-regr18.y:25.18-24: previous declaration
- glr-regr18.y:27.13-19: result type clash on merge function 'merge': <type3> != <type2>
- glr-regr18.y:26.18-24: previous declaration
- ])
 -[glr-regr18.y:26.18-24: error: result type clash on merge function 'merge': <type2> != <type1>
++[[glr-regr18.y:26.18-24: error: result type clash on merge function 'merge': <type2> != <type1>
+ glr-regr18.y:25.18-24:     previous declaration
+ glr-regr18.y:27.13-19: error: result type clash on merge function 'merge': <type3> != <type2>
+ glr-regr18.y:26.18-24:     previous declaration
 -])
++]])
  
  AT_CLEANUP
  
@@@ -1700,8 -1698,8 +1700,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o input.c input.y]], 0, [],
 -[input.y: conflicts: 1 reduce/reduce
 -])
 +[[input.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
 +]])
  AT_COMPILE([input])
  
  AT_PARSER_CHECK([[./input]], 1, [],
diff --combined tests/input.at
index 056e57852ba922edc5d8f182d68deb533b9c4583,50c1050603615392028fe3764f9e2b4e1f1e5d91..5bb707e7619c7b5654fc4ccd17c23663f46d0fb8
@@@ -33,8 -33,8 +33,8 @@@ exp: { @$ = @1 ; }
  ]])
  
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:2.13-14: integer out of range: '$1'
- input.y:3.13-14: integer out of range: '@1'
+ [[input.y:2.13-14: error: integer out of range: '$1'
+ input.y:3.13-14: error: integer out of range: '@1'
  ]])
  
  AT_CLEANUP
@@@ -58,11 -58,11 +58,11 @@@ exp: foo { $$; } foo { $2; } fo
  ]])
  
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:5.12-13: $$ for the midrule at $2 of 'exp' has no declared type
- input.y:5.24-25: $2 of 'exp' has no declared type
+ [[input.y:5.12-13: error: $$ for the midrule at $2 of 'exp' has no declared type
+ input.y:5.24-25: error: $2 of 'exp' has no declared type
 -input.y:5.6-32: warning: type clash on default action: <bar> != <>
 -input.y:6.6-8: warning: type clash on default action: <bar> != <>
 -input.y:7.5: warning: empty rule for typed nonterminal, and no action
 +input.y:5.6-32: warning: type clash on default action: <bar> != <> [-Wother]
 +input.y:6.6-8: warning: type clash on default action: <bar> != <> [-Wother]
 +input.y:7.5: warning: empty rule for typed nonterminal, and no action [-Wother]
  ]])
  
  AT_CLEANUP
@@@ -72,6 -72,7 +72,6 @@@
  # --------------------------------
  # Generate the token, type, and destructor
  # declarations for the unused values tests.
 -
  m4_define([_AT_UNUSED_VALUES_DECLARATIONS],
  [[[%token <integer> INT;
  %type <integer> a b c d e f g h i j k l;
  
  
  # AT_CHECK_UNUSED_VALUES(DECLARATIONS_AFTER, CHECK_MIDRULE_VALUES)
 -# ------------------------------------------------------------------
 -# Generate a grammar to test unused values,
 -# compile it, run it.  If DECLARATIONS_AFTER
 -# is set, then the token, type, and destructor
 -# declarations are generated after the rules
 -# rather than before.  If CHECK_MIDRULE_VALUES
 -# is set, then --warnings=midrule-values is
 -# set.
 -
 +# ----------------------------------------------------------------
 +# Generate a grammar to test unused values, compile it, run it.  If
 +# DECLARATIONS_AFTER is set, then the token, type, and destructor
 +# declarations are generated after the rules rather than before.  If
 +# CHECK_MIDRULE_VALUES is set, then --warnings=midrule-values is set.
  m4_define([AT_CHECK_UNUSED_VALUES],
  [AT_DATA([input.y],
  m4_ifval($1, [
@@@ -113,39 -118,39 +113,39 @@@ _AT_UNUSED_VALUES_DECLARATIONS]
  )
  
  AT_BISON_CHECK(m4_ifval($2, [ --warnings=midrule-values ])[ input.y], [0], [],
 -[[input.y:11.10-32: warning: unset value: $]$[
 -input.y:11.10-32: warning: unused value: $]1[
 -input.y:11.10-32: warning: unused value: $]3[
 -input.y:11.10-32: warning: unused value: $]5[
 -input.y:12.9: warning: empty rule for typed nonterminal, and no action
 -]]m4_ifval($2, [[[input.y:13.14-20: warning: unset value: $$
 -input.y:13.26-41: warning: unset value: $$
 -]]])[[input.y:13.10-62: warning: unset value: $]$[
 -input.y:13.10-62: warning: unused value: $]3[
 -input.y:13.10-62: warning: unused value: $]5[
 -]]m4_ifval($2, [[[input.y:14.14-16: warning: unset value: $$
 -]]])[[input.y:14.10-49: warning: unset value: $]$[
 -input.y:14.10-49: warning: unused value: $]3[
 -input.y:14.10-49: warning: unused value: $]5[
 -input.y:15.10-37: warning: unset value: $]$[
 -input.y:15.10-37: warning: unused value: $]3[
 -input.y:15.10-37: warning: unused value: $]5[
 -input.y:17.10-58: warning: unset value: $]$[
 -input.y:17.10-58: warning: unused value: $]1[
 -]]m4_ifval($2, [[[input.y:17.10-58: warning: unused value: $]2[
 -]]])[[input.y:17.10-58: warning: unused value: $]3[
 -]]m4_ifval($2, [[[input.y:17.10-58: warning: unused value: $]4[
 -]]])[[input.y:17.10-58: warning: unused value: $]5[
 -input.y:18.10-72: warning: unset value: $]$[
 -input.y:18.10-72: warning: unused value: $]1[
 -input.y:18.10-72: warning: unused value: $]3[
 -]]m4_ifval($2, [[[input.y:18.10-72: warning: unused value: $]4[
 -]]])[[input.y:18.10-72: warning: unused value: $]5[
 -]]m4_ifval($2, [[[input.y:20.10-55: warning: unused value: $]3[
 -]]])[[input.y:21.10-68: warning: unset value: $]$[
 -input.y:21.10-68: warning: unused value: $]1[
 -input.y:21.10-68: warning: unused value: $]2[
 -]]m4_ifval($2, [[[input.y:21.10-68: warning: unused value: $]4[
 +[[input.y:11.10-32: warning: unset value: $]$[ [-Wother]
 +input.y:11.10-32: warning: unused value: $]1[ [-Wother]
 +input.y:11.10-32: warning: unused value: $]3[ [-Wother]
 +input.y:11.10-32: warning: unused value: $]5[ [-Wother]
 +input.y:12.9: warning: empty rule for typed nonterminal, and no action [-Wother]
 +]]m4_ifval($2, [[[input.y:13.14-20: warning: unset value: $$ [-Wmidrule-values]
 +input.y:13.26-41: warning: unset value: $$ [-Wmidrule-values]
 +]]])[[input.y:13.10-62: warning: unset value: $]$[ [-Wother]
 +input.y:13.10-62: warning: unused value: $]3[ [-Wother]
 +input.y:13.10-62: warning: unused value: $]5[ [-Wother]
 +]]m4_ifval($2, [[[input.y:14.14-16: warning: unset value: $$ [-Wmidrule-values]
 +]]])[[input.y:14.10-49: warning: unset value: $]$[ [-Wother]
 +input.y:14.10-49: warning: unused value: $]3[ [-Wother]
 +input.y:14.10-49: warning: unused value: $]5[ [-Wother]
 +input.y:15.10-37: warning: unset value: $]$[ [-Wother]
 +input.y:15.10-37: warning: unused value: $]3[ [-Wother]
 +input.y:15.10-37: warning: unused value: $]5[ [-Wother]
 +input.y:17.10-58: warning: unset value: $]$[ [-Wother]
 +input.y:17.10-58: warning: unused value: $]1[ [-Wother]
 +]]m4_ifval($2, [[[input.y:17.10-58: warning: unused value: $]2[ [-Wmidrule-values]
 +]]])[[input.y:17.10-58: warning: unused value: $]3[ [-Wother]
 +]]m4_ifval($2, [[[input.y:17.10-58: warning: unused value: $]4[ [-Wmidrule-values]
 +]]])[[input.y:17.10-58: warning: unused value: $]5[ [-Wother]
 +input.y:18.10-72: warning: unset value: $]$[ [-Wother]
 +input.y:18.10-72: warning: unused value: $]1[ [-Wother]
 +input.y:18.10-72: warning: unused value: $]3[ [-Wother]
 +]]m4_ifval($2, [[[input.y:18.10-72: warning: unused value: $]4[ [-Wmidrule-values]
 +]]])[[input.y:18.10-72: warning: unused value: $]5[ [-Wother]
 +]]m4_ifval($2, [[[input.y:20.10-55: warning: unused value: $]3[ [-Wmidrule-values]
 +]]])[[input.y:21.10-68: warning: unset value: $]$[ [-Wother]
 +input.y:21.10-68: warning: unused value: $]1[ [-Wother]
 +input.y:21.10-68: warning: unused value: $]2[ [-Wother]
 +]]m4_ifval($2, [[[input.y:21.10-68: warning: unused value: $]4[ [-Wmidrule-values]
  ]]]))])
  
  
@@@ -200,30 -205,30 +200,30 @@@ start: 
  ]])
  
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:1.13-29: %destructor redeclaration for <*>
- input.y:1.13-29: previous declaration
- input.y:2.10-24: %printer redeclaration for <*>
- input.y:2.10-24: previous declaration
- input.y:4.13-29: %destructor redeclaration for <*>
- input.y:1.13-29: previous declaration
- input.y:5.10-24: %printer redeclaration for <*>
- input.y:2.10-24: previous declaration
- input.y:7.13-29: %destructor redeclaration for <>
- input.y:7.13-29: previous declaration
- input.y:8.10-24: %printer redeclaration for <>
- input.y:8.10-24: previous declaration
- input.y:10.13-29: %destructor redeclaration for <>
- input.y:7.13-29: previous declaration
- input.y:11.10-24: %printer redeclaration for <>
- input.y:8.10-24: previous declaration
- input.y:17.13-29: %destructor redeclaration for <*>
- input.y:4.13-29: previous declaration
- input.y:18.10-24: %printer redeclaration for <*>
- input.y:5.10-24: previous declaration
- input.y:20.13-29: %destructor redeclaration for <>
- input.y:10.13-29: previous declaration
- input.y:21.10-24: %printer redeclaration for <>
- input.y:11.10-24: previous declaration
 -[[input.y:1.13-29: error: redeclaration for default tagged %destructor
++[[input.y:1.13-29: error: %destructor redeclaration for <*>
+ input.y:1.13-29:     previous declaration
 -input.y:2.10-24: error: redeclaration for default tagged %printer
++input.y:2.10-24: error: %printer redeclaration for <*>
+ input.y:2.10-24:     previous declaration
 -input.y:4.13-29: error: redeclaration for default tagged %destructor
++input.y:4.13-29: error: %destructor redeclaration for <*>
+ input.y:1.13-29:     previous declaration
 -input.y:5.10-24: error: redeclaration for default tagged %printer
++input.y:5.10-24: error: %printer redeclaration for <*>
+ input.y:2.10-24:     previous declaration
 -input.y:7.13-29: error: redeclaration for default tagless %destructor
++input.y:7.13-29: error: %destructor redeclaration for <>
+ input.y:7.13-29:     previous declaration
 -input.y:8.10-24: error: redeclaration for default tagless %printer
++input.y:8.10-24: error: %printer redeclaration for <>
+ input.y:8.10-24:     previous declaration
 -input.y:10.13-29: error: redeclaration for default tagless %destructor
++input.y:10.13-29: error: %destructor redeclaration for <>
+ input.y:7.13-29:      previous declaration
 -input.y:11.10-24: error: redeclaration for default tagless %printer
++input.y:11.10-24: error: %printer redeclaration for <>
+ input.y:8.10-24:      previous declaration
 -input.y:17.13-29: error: redeclaration for default tagged %destructor
++input.y:17.13-29: error: %destructor redeclaration for <*>
+ input.y:4.13-29:      previous declaration
 -input.y:18.10-24: error: redeclaration for default tagged %printer
++input.y:18.10-24: error: %printer redeclaration for <*>
+ input.y:5.10-24:      previous declaration
 -input.y:20.13-29: error: redeclaration for default tagless %destructor
++input.y:20.13-29: error: %destructor redeclaration for <>
+ input.y:10.13-29:     previous declaration
 -input.y:21.10-24: error: redeclaration for default tagless %printer
++input.y:21.10-24: error: %printer redeclaration for <>
+ input.y:11.10-24:     previous declaration
  ]])
  
  AT_CLEANUP
@@@ -251,143 -256,26 +251,143 @@@ start: 
  ]])
  
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:4.13-29: %destructor redeclaration for <field1>
- input.y:1.13-29: previous declaration
- input.y:4.13-29: %destructor redeclaration for <field1>
- input.y:4.13-29: previous declaration
- input.y:5.10-24: %printer redeclaration for <field2>
- input.y:2.10-24: previous declaration
- input.y:5.10-24: %printer redeclaration for <field2>
- input.y:5.10-24: previous declaration
- input.y:11.13-29: %destructor redeclaration for <field1>
- input.y:4.13-29: previous declaration
- input.y:11.13-29: %destructor redeclaration for <field2>
- input.y:1.13-29: previous declaration
- input.y:12.10-24: %printer redeclaration for <field1>
- input.y:2.10-24: previous declaration
- input.y:12.10-24: %printer redeclaration for <field2>
- input.y:5.10-24: previous declaration
+ [[input.y:4.13-29: error: %destructor redeclaration for <field1>
+ input.y:1.13-29:     previous declaration
+ input.y:4.13-29: error: %destructor redeclaration for <field1>
+ input.y:4.13-29:     previous declaration
+ input.y:5.10-24: error: %printer redeclaration for <field2>
+ input.y:2.10-24:     previous declaration
+ input.y:5.10-24: error: %printer redeclaration for <field2>
+ input.y:5.10-24:     previous declaration
+ input.y:11.13-29: error: %destructor redeclaration for <field1>
+ input.y:4.13-29:      previous declaration
+ input.y:11.13-29: error: %destructor redeclaration for <field2>
+ input.y:1.13-29:      previous declaration
+ input.y:12.10-24: error: %printer redeclaration for <field1>
+ input.y:2.10-24:      previous declaration
+ input.y:12.10-24: error: %printer redeclaration for <field2>
+ input.y:5.10-24:      previous declaration
  ]])
  
  AT_CLEANUP
  
- [[input.y:2.16-18: symbol bar is used, but is not defined as a token and has no rules
 +## ------------------- ##
 +## Undefined symbols.  ##
 +## ------------------- ##
 +
 +AT_SETUP([Undefined symbols])
 +
 +AT_DATA([[input.y]],
 +[[%printer {} foo baz
 +%destructor {} bar
 +%type <foo> qux
 +%%
 +exp: bar;
 +]])
 +
 +AT_BISON_CHECK([input.y], [1], [],
++[[input.y:2.16-18: error: symbol bar is used, but is not defined as a token and has no rules
 +input.y:1.17-19: warning: symbol baz is used, but is not defined as a token and has no rules [-Wother]
 +input.y:1.13-15: warning: symbol foo is used, but is not defined as a token and has no rules [-Wother]
 +input.y:3.13-15: warning: symbol qux is used, but is not defined as a token and has no rules [-Wother]
 +]])
 +
 +AT_CLEANUP
 +
 +
 +## ----------------------------------------------------- ##
 +## Unassociated types used for a printer or destructor.  ##
 +## ----------------------------------------------------- ##
 +
 +AT_SETUP([Unassociated types used for a printer or destructor])
 +
 +AT_DATA([[input.y]],
 +[[%token <type1> tag1
 +%type <type2> tag2
 +
 +%printer { } <type1> <type3>
 +%destructor { } <type2> <type4>
 +
 +%%
 +
 +exp: tag1 { $1; }
 +   | tag2 { $1; }
 +
 +tag2: "a" { $$; }
 +]])
 +
 +AT_BISON_CHECK([input.y], [0], [],
 +[[input.y:4.22-28: warning: type <type3> is used, but is not associated to any symbol [-Wother]
 +input.y:5.25-31: warning: type <type4> is used, but is not associated to any symbol [-Wother]
 +]])
 +
 +AT_CLEANUP
 +
 +
 +## --------------------------------- ##
 +## Useless printers or destructors.  ##
 +## --------------------------------- ##
 +
 +AT_SETUP([Useless printers or destructors])
 +
 +# AT_TEST([INPUT], [STDERR])
 +# --------------------------
 +m4_pushdef([AT_TEST],
 +[AT_DATA([[input.y]],
 +[$1
 +])
 +AT_BISON_CHECK([input.y], [0], [], [$2
 +])])
 +
 +AT_TEST([[%token <type1> token1
 +%token <type2> token2
 +%token <type3> token3
 +%token <type4> token4
 +%token <type5> token51 token52
 +%token <type6> token61 token62
 +%token <type7> token7
 +
 +%printer {} token1
 +%destructor {} token2
 +%printer {} token51
 +%destructor {} token61
 +
 +%printer {} token7
 +
 +%printer {} <type1>
 +%destructor {} <type2>
 +%printer {} <type3>
 +%destructor {} <type4>
 +
 +%printer {} <type5>
 +%destructor {} <type6>
 +
 +%destructor {} <type7>
 +
 +%%
 +exp: "a";]],
 +[[input.y:16.13-19: warning: useless %printer for type <type1> [-Wother]
 +input.y:17.16-22: warning: useless %destructor for type <type2> [-Wother]]])
 +
 +# If everybody is typed, <> is useless.
 +AT_TEST([[%type <type> exp
 +%token <type> a
 +%printer {} <> <*>
 +%%
 +exp: a;]],
 +[[input.y:3.13-14: warning: useless %printer for type <> [-Wother]]])
 +
 +# If nobody is typed, <*> is useless.
 +AT_TEST([[%token a
 +%printer {} <> <*>
 +%%
 +exp: a;]],
 +[[input.y:2.16-18: warning: useless %printer for type <*> [-Wother]]])
 +
 +m4_popdef([AT_TEST])
 +
 +AT_CLEANUP
 +
  
  ## ---------------------------------------- ##
  ## Unused values with default %destructor.  ##
@@@ -407,9 -295,9 +407,9 @@@ tagged: { } 
  ]])
  
  AT_BISON_CHECK([input.y], [0], [],
 -[[input.y:6.8-45: warning: unset value: $$
 -input.y:6.8-45: warning: unused value: $2
 -input.y:7.6-8: warning: unset value: $$
 +[[input.y:6.8-45: warning: unset value: $$ [-Wother]
 +input.y:6.8-45: warning: unused value: $2 [-Wother]
 +input.y:7.6-8: warning: unset value: $$ [-Wother]
  ]])
  
  AT_DATA([[input.y]],
@@@ -424,8 -312,8 +424,8 @@@ tagged: { } 
  ]])
  
  AT_BISON_CHECK([input.y], [0], [],
 -[[input.y:6.8-45: warning: unused value: $4
 -input.y:8.9-11: warning: unset value: $$
 +[[input.y:6.8-45: warning: unused value: $4 [-Wother]
 +input.y:8.9-11: warning: unset value: $$ [-Wother]
  ]])
  
  AT_CLEANUP
@@@ -448,9 -336,9 +448,9 @@@ end: { }  
  ]])
  
  AT_BISON_CHECK([input.y], [0], [],
 -[[input.y:6.8-22: warning: unset value: $$
 -input.y:6.8-22: warning: unused value: $2
 -input.y:7.6-8: warning: unset value: $$
 +[[input.y:6.8-22: warning: unset value: $$ [-Wother]
 +input.y:6.8-22: warning: unused value: $2 [-Wother]
 +input.y:7.6-8: warning: unset value: $$ [-Wother]
  ]])
  
  AT_CLEANUP
@@@ -480,14 -368,14 +480,14 @@@ exp: foo
  ]])
  
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:8.7-11: %type redeclaration for foo
- input.y:3.7-11: previous declaration
- input.y:10.13-17: %destructor redeclaration for foo
- input.y:5.13-17: previous declaration
- input.y:9.10-14: %printer redeclaration for foo
- input.y:4.10-14: previous declaration
- input.y:11.1-5: %left redeclaration for foo
- input.y:6.1-5: previous declaration
+ [[input.y:8.7-11: error: %type redeclaration for foo
+ input.y:3.7-11:     previous declaration
+ input.y:10.13-17: error: %destructor redeclaration for foo
+ input.y:5.13-17:      previous declaration
+ input.y:9.10-14: error: %printer redeclaration for foo
+ input.y:4.10-14:     previous declaration
+ input.y:11.1-5: error: %left redeclaration for foo
+ input.y:6.1-5:      previous declaration
  ]])
  
  AT_CLEANUP
@@@ -506,7 -394,7 +506,7 @@@ AT_SETUP([Torturing the Scanner]
  AT_BISON_OPTION_PUSHDEFS
  AT_DATA([input.y], [])
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:1.1: syntax error, unexpected end of file
+ [[input.y:1.1: error: syntax error, unexpected end of file
  ]])
  
  
@@@ -514,7 -402,7 +514,7 @@@ AT_DATA([input.y]
  [{}
  ])
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:1.1-2: syntax error, unexpected {...}
+ [[input.y:1.1-2: error: syntax error, unexpected {...}
  ]])
  
  
@@@ -628,7 -516,7 +628,7 @@@ yylex (void
  }
  ]])
  
 -# Pacify Emacs' font-lock-mode: "
 +# Pacify Emacs'font-lock-mode: "
  
  AT_DATA([main.c],
  [[typedef int value;
@@@ -707,8 -595,8 +707,8 @@@ AT_CHECK_REQUIRE(100.0, 63
  
  AT_SETUP([String aliases for character tokens])
  
 -# Bison once thought a character token and its alias were different symbols
 -# with the same user token number.
 +# Bison once thought a character token and its alias were different
 +# symbols with the same user token number.
  
  AT_DATA_GRAMMAR([input.y],
  [[%token 'a' "a"
@@@ -752,14 -640,14 +752,14 @@@ AT_BISON_OPTION_POPDEF
  
  # POSIX Yacc accept periods, but not dashes.
  AT_BISON_CHECK([--yacc input.y], [1], [],
 -[[input.y:9.8-16: POSIX Yacc forbids dashes in symbol names: WITH-DASH
 -input.y:18.8-16: POSIX Yacc forbids dashes in symbol names: with-dash
 +[[input.y:9.8-16: POSIX Yacc forbids dashes in symbol names: WITH-DASH [-Wyacc]
 +input.y:18.8-16: POSIX Yacc forbids dashes in symbol names: with-dash [-Wyacc]
  ]])
  
  # So warn about them.
  AT_BISON_CHECK([-Wyacc input.y], [], [],
 -[[input.y:9.8-16: warning: POSIX Yacc forbids dashes in symbol names: WITH-DASH
 -input.y:18.8-16: warning: POSIX Yacc forbids dashes in symbol names: with-dash
 +[[input.y:9.8-16: warning: POSIX Yacc forbids dashes in symbol names: WITH-DASH [-Wyacc]
 +input.y:18.8-16: warning: POSIX Yacc forbids dashes in symbol names: with-dash [-Wyacc]
  ]])
  
  # Dashes are fine for GNU Bison.
@@@ -780,9 -668,9 +780,9 @@@ AT_DATA_GRAMMAR([input.y]
  start: .GOOD GOOD
  ]])
  AT_BISON_CHECK([-o input.c input.y], [1], [],
- [[input.y:10.10: invalid character: '-'
- input.y:11.10-16: invalid identifier: '1NV4L1D'
- input.y:12.10: invalid character: '-'
+ [[input.y:10.10: error: invalid character: '-'
+ input.y:11.10-16: error: invalid identifier: '1NV4L1D'
+ input.y:12.10: error: invalid character: '-'
  ]])
  
  AT_CLEANUP
@@@ -804,9 -692,9 +804,9 @@@ start: DECIMAL_1 HEXADECIMAL_2
  ]])
  
  AT_BISON_CHECK([redecl.y], [1], [],
- [[redecl.y:10.10-22: user token number 11259375 redeclaration for HEXADECIMAL_1
- redecl.y:9.8-16: previous declaration for DECIMAL_1
- redecl.y:12.10-18: user token number 16702650 redeclaration for DECIMAL_2
+ [[redecl.y:10.10-22: error: user token number 11259375 redeclaration for HEXADECIMAL_1
+ redecl.y:9.8-16:   previous declaration for DECIMAL_1
+ redecl.y:12.10-18: error: user token number 16702650 redeclaration for DECIMAL_2
  redecl.y:11.10-22: previous declaration for HEXADECIMAL_2
  ]])
  
@@@ -819,8 -707,8 +819,8 @@@ start: TOO_LARGE_DEC TOO_LARGE_HE
  ]])
  
  AT_BISON_CHECK([too-large.y], [1], [],
- [[too-large.y:9.22-42: integer out of range: '999999999999999999999'
- too-large.y:10.24-44: integer out of range: '0xFFFFFFFFFFFFFFFFFFF'
+ [[too-large.y:9.22-42: error: integer out of range: '999999999999999999999'
+ too-large.y:10.24-44: error: integer out of range: '0xFFFFFFFFFFFFFFFFFFF'
  ]])
  
  AT_CLEANUP
  
  AT_SETUP([Unclosed constructs])
  
 -# Bison's scan-gram.l once forgot to STRING_FINISH some unclosed constructs, so
 -# they were prepended to whatever it STRING_GROW'ed next.  It also threw them
 -# away rather than returning them to the parser.  The effect was confusing
 -# subsequent error messages.
 +# Bison's scan-gram.l once forgot to STRING_FINISH some unclosed
 +# constructs, so they were prepended to whatever it STRING_GROW'ed
 +# next.  It also threw them away rather than returning them to the
 +# parser.  The effect was confusing subsequent error messages.
  
  AT_DATA([input.y],
  [[%token A "a
@@@ -860,12 -748,12 +860,12 @@@ start: 
  ]])
  
  AT_BISON_CHECK([-o input.c input.y], 1, [],
- [[input.y:1.10-2.0: missing '"' at end of line
- input.y:4.10-5.0: missing "'" at end of line
- input.y:14.11-15.0: missing "'" at end of line
- input.y:16.11-17.0: missing '"' at end of line
- input.y:19.13-20.0: missing '}' at end of file
- input.y:20.1: syntax error, unexpected end of file
+ [[input.y:1.10-2.0: error: missing '"' at end of line
+ input.y:4.10-5.0: error: missing "'" at end of line
+ input.y:14.11-15.0: error: missing "'" at end of line
+ input.y:16.11-17.0: error: missing '"' at end of line
+ input.y:19.13-20.0: error: missing '}' at end of file
+ input.y:20.1: error: syntax error, unexpected end of file
  ]])
  
  AT_CLEANUP
  
  AT_SETUP([%start after first rule])
  
 -# Bison once complained that a %start after the first rule was a redeclaration
 -# of the start symbol.
 +# Bison once complained that a %start after the first rule was a
 +# redeclaration of the start symbol.
  
  AT_DATA([input.y],
  [[%%
@@@ -907,7 -795,7 +907,7 @@@ PREC: 
  ]])
  
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:3.1-4: rule given for PREC, which is a token
+ [[input.y:3.1-4: error: rule given for PREC, which is a token
  ]])
  
  AT_CLEANUP
@@@ -927,7 -815,7 +927,7 @@@ start: %prec PREC 
  ]])
  
  AT_BISON_CHECK([[input.y]], [[0]], [],
 -[[input.y:2.8-17: warning: token for %prec is not defined: PREC
 +[[input.y:2.8-17: warning: token for %prec is not defined: PREC [-Wother]
  ]])
  
  AT_CLEANUP
@@@ -948,10 -836,10 +948,10 @@@ AT_DATA([input-c.y]
  start: ;
  ]])
  AT_BISON_CHECK([[input-c.y]], [[1]], [],
- [[input-c.y:1.7: %code qualifier 'q' is not used
- input-c.y:2.7-9: %code qualifier 'bad' is not used
- input-c.y:3.7-9: %code qualifier 'bad' is not used
- input-c.y:4.7-12: %code qualifier 'format' is not used
+ [[input-c.y:1.7: error: %code qualifier 'q' is not used
+ input-c.y:2.7-9: error: %code qualifier 'bad' is not used
+ input-c.y:3.7-9: error: %code qualifier 'bad' is not used
+ input-c.y:4.7-12: error: %code qualifier 'format' is not used
  ]])
  
  AT_DATA([input-c-glr.y],
  start: ;
  ]])
  AT_BISON_CHECK([[input-c-glr.y]], [[1]], [],
- [[input-c-glr.y:1.7: %code qualifier 'q' is not used
- input-c-glr.y:2.7-9: %code qualifier 'bad' is not used
- input-c-glr.y:3.8-10: %code qualifier 'bad' is not used
+ [[input-c-glr.y:1.7: error: %code qualifier 'q' is not used
+ input-c-glr.y:2.7-9: error: %code qualifier 'bad' is not used
+ input-c-glr.y:3.8-10: error: %code qualifier 'bad' is not used
  ]])
  
  AT_DATA([input-c++.y],
  start: ;
  ]])
  AT_BISON_CHECK([[input-c++.y]], [[1]], [],
- [[input-c++.y:1.7: %code qualifier 'q' is not used
- input-c++.y:2.7-9: %code qualifier 'bad' is not used
- input-c++.y:3.8: %code qualifier 'q' is not used
+ [[input-c++.y:1.7: error: %code qualifier 'q' is not used
+ input-c++.y:2.7-9: error: %code qualifier 'bad' is not used
+ input-c++.y:3.8: error: %code qualifier 'q' is not used
  ]])
  
  AT_DATA([input-c++-glr.y],
  start: ;
  ]])
  AT_BISON_CHECK([[input-c++-glr.y]], [[1]], [],
- [[input-c++-glr.y:1.7-9: %code qualifier 'bad' is not used
- input-c++-glr.y:2.7: %code qualifier 'q' is not used
- input-c++-glr.y:3.7: %code qualifier 'q' is not used
+ [[input-c++-glr.y:1.7-9: error: %code qualifier 'bad' is not used
+ input-c++-glr.y:2.7: error: %code qualifier 'q' is not used
+ input-c++-glr.y:3.7: error: %code qualifier 'q' is not used
  ]])
  
  AT_DATA([special-char-@@.y],
  start: ;
  ]])
  AT_BISON_CHECK([[special-char-@@.y]], [[1]], [],
- [[special-char-@@.y:1.7-9: %code qualifier 'bad' is not used
- special-char-@@.y:2.7: %code qualifier 'q' is not used
- special-char-@@.y:3.7: %code qualifier 'q' is not used
+ [[special-char-@@.y:1.7-9: error: %code qualifier 'bad' is not used
+ special-char-@@.y:2.7: error: %code qualifier 'q' is not used
+ special-char-@@.y:3.7: error: %code qualifier 'q' is not used
  ]])
  
  AT_DATA([special-char-@:>@.y],
  start: ;
  ]])
  AT_BISON_CHECK([[special-char-@:>@.y]], [[1]], [],
- [[special-char-@:>@.y:1.7-9: %code qualifier 'bad' is not used
- special-char-@:>@.y:2.7: %code qualifier 'q' is not used
- special-char-@:>@.y:3.7: %code qualifier 'q' is not used
+ [[special-char-@:>@.y:1.7-9: error: %code qualifier 'bad' is not used
+ special-char-@:>@.y:2.7: error: %code qualifier 'q' is not used
+ special-char-@:>@.y:3.7: error: %code qualifier 'q' is not used
  ]])
  
  AT_CLEANUP
@@@ -1039,10 -927,10 +1039,10 @@@ start: 
  ]])
  
  AT_BISON_CHECK([[input-redefined.y]], [[1]], [],
- [[input-redefined.y:2.9-11: %define variable 'var' redefined
- input-redefined.y:1.9-11: previous definition
- input-redefined.y:3.10-12: %define variable 'var' redefined
- input-redefined.y:2.9-11: previous definition
+ [[input-redefined.y:2.9-11: error: %define variable 'var' redefined
+ input-redefined.y:1.9-11:     previous definition
+ input-redefined.y:3.10-12: error: %define variable 'var' redefined
+ input-redefined.y:2.9-11:      previous definition
  ]])
  
  AT_DATA([input-unused.y],
@@@ -1052,7 -940,7 +1052,7 @@@ start: 
  ]])
  
  AT_BISON_CHECK([[input-unused.y]], [[1]], [],
- [[input-unused.y:1.9-11: %define variable 'var' is not used
+ [[input-unused.y:1.9-11: error: %define variable 'var' is not used
  ]])
  
  AT_CLEANUP
@@@ -1096,8 -984,8 +1096,8 @@@ AT_DATA([[input-dg.y]]
  start: ;
  ]])
  AT_BISON_CHECK([[-Dvar=cmd-d input-dg.y]], [[1]], [],
- [[input-dg.y:1.9-11: %define variable 'var' redefined
- <command line>:2: previous definition
+ [[input-dg.y:1.9-11: error: %define variable 'var' redefined
+ <command line>:2:      previous definition
  ]])
  
  AT_DATA([[input-unused.y]],
  start: ;
  ]])
  AT_BISON_CHECK([[-Dunused-d -Funused-f input-unused.y]], [[1]], [],
- [[<command line>:2: %define variable 'unused-d' is not used
- <command line>:3: %define variable 'unused-f' is not used
+ [[<command line>:2: error: %define variable 'unused-d' is not used
+ <command line>:3: error: %define variable 'unused-f' is not used
  ]])
  
  AT_CLEANUP
@@@ -1126,7 -1014,7 +1126,7 @@@ start: 
  ]])
  
  AT_BISON_CHECK([[Input.y]], [1], [],
- [[Input.y:2.9-14: invalid value for %define Boolean variable 'public'
+ [[Input.y:2.9-14: error: invalid value for %define Boolean variable 'public'
  ]])
  
  AT_CLEANUP
@@@ -1144,23 -1032,24 +1144,24 @@@ AT_DATA([[input.y]]
  start: ;
  ]])
  AT_BISON_CHECK([[input.y]], [[1]], [[]],
- [[input.y:1.9-29: invalid value for %define variable 'lr.default-reductions': 'bogus'
- input.y:1.9-29: accepted value: 'most'
- input.y:1.9-29: accepted value: 'consistent'
- input.y:1.9-29: accepted value: 'accepting'
+ [[input.y:1.9-29: error: invalid value for %define variable 'lr.default-reductions': 'bogus'
+ input.y:1.9-29:     accepted value: 'most'
+ input.y:1.9-29:     accepted value: 'consistent'
+ input.y:1.9-29:     accepted value: 'accepting'
  ]])
  
  # Back-end.
+ # FIXME: these should be indented, but we shouldn't mess with the m4 yet
  AT_DATA([[input.y]],
  [[%define api.push-pull neither
  %%
  start: ;
  ]])
  AT_BISON_CHECK([[input.y]], [1], [],
- [[input.y:1.9-21: invalid value for %define variable 'api.push-pull': 'neither'
- input.y:1.9-21: accepted value: 'pull'
- input.y:1.9-21: accepted value: 'push'
- input.y:1.9-21: accepted value: 'both'
+ [[input.y:1.9-21: error: invalid value for %define variable 'api.push-pull': 'neither'
+ input.y:1.9-21: error: accepted value: 'pull'
+ input.y:1.9-21: error: accepted value: 'push'
+ input.y:1.9-21: error: accepted value: 'both'
  ]])
  
  AT_CLEANUP
@@@ -1180,11 -1069,10 +1181,11 @@@ AT_DATA([[input.y]]
  start: ;
  ]])
  AT_BISON_CHECK([[input.y]], [1], [],
 -[[input.y:1.9-21: error: invalid value for %define variable 'api.push-pull': 'neither'
 +[[input.y:1.9-21: warning: deprecated %define variable name: 'api.push_pull', use 'api.push-pull' [-Wdeprecated]
- input.y:1.9-21: invalid value for %define variable 'api.push-pull': 'neither'
- input.y:1.9-21: accepted value: 'pull'
- input.y:1.9-21: accepted value: 'push'
- input.y:1.9-21: accepted value: 'both'
++input.y:1.9-21: error: invalid value for %define variable 'api.push-pull': 'neither'
+ input.y:1.9-21: error: accepted value: 'pull'
+ input.y:1.9-21: error: accepted value: 'push'
+ input.y:1.9-21: error: accepted value: 'both'
  ]])
  
  AT_DATA([[input.y]],
  start: ;
  ]])
  AT_BISON_CHECK([[input.y]], [1], [],
 -[[input.y:1.9-34: error: invalid value for %define Boolean variable 'lr.keep-unreachable-states'
 +[[input.y:1.9-34: warning: deprecated %define variable name: 'lr.keep_unreachable_states', use 'lr.keep-unreachable-states' [-Wdeprecated]
- input.y:1.9-34: invalid value for %define Boolean variable 'lr.keep-unreachable-states'
++input.y:1.9-34: error: invalid value for %define Boolean variable 'lr.keep-unreachable-states'
 +]])
 +
 +AT_DATA([[input.y]],
 +[[%define namespace "foo"
 +%define api.namespace "foo"
 +%%
 +start: ;
 +]])
 +AT_BISON_CHECK([[input.y]], [1], [],
 +[[input.y:1.9-17: warning: deprecated %define variable name: 'namespace', use 'api.namespace' [-Wdeprecated]
- input.y:2.9-21: %define variable 'api.namespace' redefined
- input.y:1.9-17: previous definition
++input.y:2.9-21: error: %define variable 'api.namespace' redefined
++input.y:1.9-17:     previous definition
  ]])
  
  AT_DATA([[input.y]],
  start: ;
  ]])
  AT_BISON_CHECK([[input.y]], [[1]], [],
- [[input.y:1.9-15: %define variable 'foo_bar' is not used
+ [[input.y:1.9-15: error: %define variable 'foo_bar' is not used
  ]])
  
  AT_CLEANUP
@@@ -1240,7 -1115,7 +1241,7 @@@ start: 
  ]])
  
  AT_BISON_CHECK([[input.y]], [[1]], [],
- [[input.y:1.9-16: %define variable 'api.pure' is not used
+ [[input.y:1.9-16: error: %define variable 'api.pure' is not used
  ]])
  ])
  
@@@ -1267,14 -1142,14 +1268,14 @@@ m4_define([AT_CHECK_NAMESPACE_ERROR]
  AT_DATA([[input.y]],
  [[%language "C++"
  %defines
 -%define namespace "]$1["
 +%define api.namespace "]$1["
  %%
  start: ;
  ]])
  
  AT_BISON_CHECK([[input.y]], [1], [],
  [m4_foreach([b4_arg], m4_dquote(m4_shift($@)),
- [[input.y:3.9-21: ]b4_arg[
 -[[input.y:3.9-17: error: ]b4_arg[
++[[input.y:3.9-21: error: ]b4_arg[
  ]])])
  ])
  
@@@ -1323,11 -1198,11 +1324,11 @@@ start: 
  AT_CHECK([[perl -e "print 'start: \'';" >> empty.y || exit 77]])
  
  AT_BISON_CHECK([empty.y], [1], [],
 -[[empty.y:2.8-9: warning: empty character literal
 -empty.y:3.8-4.0: warning: empty character literal
 +[[empty.y:2.8-9: warning: empty character literal [-Wother]
 +empty.y:3.8-4.0: warning: empty character literal [-Wother]
- empty.y:3.8-4.0: missing "'" at end of line
+ empty.y:3.8-4.0: error: missing "'" at end of line
 -empty.y:4.8: warning: empty character literal
 +empty.y:4.8: warning: empty character literal [-Wother]
- empty.y:4.8: missing "'" at end of file
+ empty.y:4.8: error: missing "'" at end of file
  ]])
  
  AT_DATA([two.y],
@@@ -1338,11 -1213,11 +1339,11 @@@ start: 'a
  AT_CHECK([[perl -e "print 'start: \'ab';" >> two.y || exit 77]])
  
  AT_BISON_CHECK([two.y], [1], [],
 -[[two.y:2.8-11: warning: extra characters in character literal
 -two.y:3.8-4.0: warning: extra characters in character literal
 +[[two.y:2.8-11: warning: extra characters in character literal [-Wother]
 +two.y:3.8-4.0: warning: extra characters in character literal [-Wother]
- two.y:3.8-4.0: missing "'" at end of line
+ two.y:3.8-4.0: error: missing "'" at end of line
 -two.y:4.8-10: warning: extra characters in character literal
 +two.y:4.8-10: warning: extra characters in character literal [-Wother]
- two.y:4.8-10: missing "'" at end of file
+ two.y:4.8-10: error: missing "'" at end of file
  ]])
  
  AT_DATA([three.y],
@@@ -1353,11 -1228,11 +1354,11 @@@ start: 'ab
  AT_CHECK([[perl -e "print 'start: \'abc';" >> three.y || exit 77]])
  
  AT_BISON_CHECK([three.y], [1], [],
 -[[three.y:2.8-12: warning: extra characters in character literal
 -three.y:3.8-4.0: warning: extra characters in character literal
 +[[three.y:2.8-12: warning: extra characters in character literal [-Wother]
 +three.y:3.8-4.0: warning: extra characters in character literal [-Wother]
- three.y:3.8-4.0: missing "'" at end of line
+ three.y:3.8-4.0: error: missing "'" at end of line
 -three.y:4.8-11: warning: extra characters in character literal
 +three.y:4.8-11: warning: extra characters in character literal [-Wother]
- three.y:4.8-11: missing "'" at end of file
+ three.y:4.8-11: error: missing "'" at end of file
  ]])
  
  AT_CLEANUP
@@@ -1383,30 -1258,30 +1384,30 @@@ AT_CHECK([[perl -e 'print "start: \"\\\
             || exit 77]])
  
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:2.9-12: invalid number after \-escape: 777
+ [[input.y:2.9-12: error: invalid number after \-escape: 777
 -input.y:2.8-13: warning: empty character literal
 +input.y:2.8-13: warning: empty character literal [-Wother]
- input.y:2.16-17: invalid number after \-escape: 0
+ input.y:2.16-17: error: invalid number after \-escape: 0
 -input.y:2.15-18: warning: empty character literal
 +input.y:2.15-18: warning: empty character literal [-Wother]
- input.y:2.21-25: invalid number after \-escape: xfff
+ input.y:2.21-25: error: invalid number after \-escape: xfff
 -input.y:2.20-26: warning: empty character literal
 +input.y:2.20-26: warning: empty character literal [-Wother]
- input.y:2.29-31: invalid number after \-escape: x0
+ input.y:2.29-31: error: invalid number after \-escape: x0
 -input.y:2.28-32: warning: empty character literal
 +input.y:2.28-32: warning: empty character literal [-Wother]
- input.y:3.9-14: invalid number after \-escape: uffff
+ input.y:3.9-14: error: invalid number after \-escape: uffff
 -input.y:3.8-15: warning: empty character literal
 +input.y:3.8-15: warning: empty character literal [-Wother]
- input.y:3.18-23: invalid number after \-escape: u0000
+ input.y:3.18-23: error: invalid number after \-escape: u0000
 -input.y:3.17-24: warning: empty character literal
 +input.y:3.17-24: warning: empty character literal [-Wother]
- input.y:3.27-36: invalid number after \-escape: Uffffffff
+ input.y:3.27-36: error: invalid number after \-escape: Uffffffff
 -input.y:3.26-37: warning: empty character literal
 +input.y:3.26-37: warning: empty character literal [-Wother]
- input.y:3.40-49: invalid number after \-escape: U00000000
+ input.y:3.40-49: error: invalid number after \-escape: U00000000
 -input.y:3.39-50: warning: empty character literal
 +input.y:3.39-50: warning: empty character literal [-Wother]
- input.y:4.9-10: invalid character after \-escape: ' '
+ input.y:4.9-10: error: invalid character after \-escape: ' '
 -input.y:4.8-11: warning: empty character literal
 +input.y:4.8-11: warning: empty character literal [-Wother]
- input.y:4.14-15: invalid character after \-escape: A
+ input.y:4.14-15: error: invalid character after \-escape: A
 -input.y:4.13-16: warning: empty character literal
 +input.y:4.13-16: warning: empty character literal [-Wother]
- input.y:5.9-16: invalid character after \-escape: \t
- input.y:5.17: invalid character after \-escape: \f
- input.y:5.18: invalid character after \-escape: \0
- input.y:5.19: invalid character after \-escape: \001
+ input.y:5.9-16: error: invalid character after \-escape: \t
+ input.y:5.17: error: invalid character after \-escape: \f
+ input.y:5.18: error: invalid character after \-escape: \0
+ input.y:5.19: error: invalid character after \-escape: \001
  ]])
  
  AT_CLEANUP
@@@ -1425,11 -1300,11 +1426,11 @@@ start: 
  # parse.lac.* options are useless if LAC isn't actually activated.
  AT_BISON_CHECK([[-Dparse.lac.es-capacity-initial=1 input.y]],
                 [[1]], [],
- [[<command line>:2: %define variable 'parse.lac.es-capacity-initial' is not used
+ [[<command line>:2: error: %define variable 'parse.lac.es-capacity-initial' is not used
  ]])
  AT_BISON_CHECK([[-Dparse.lac.memory-trace=full input.y]],
                 [[1]], [],
- [[<command line>:2: %define variable 'parse.lac.memory-trace' is not used
+ [[<command line>:2: error: %define variable 'parse.lac.memory-trace' is not used
  ]])
  
  AT_CLEANUP
@@@ -1447,20 -1322,20 +1448,20 @@@ foo-bar: 
  
  # -Werror is not enabled by -Wall or equivalent.
  AT_BISON_CHECK([[-Wall input.y]], [[0]], [[]],
 -[[input.y:2.1-7: warning: POSIX Yacc forbids dashes in symbol names: foo-bar
 +[[input.y:2.1-7: warning: POSIX Yacc forbids dashes in symbol names: foo-bar [-Wyacc]
  ]])
  AT_BISON_CHECK([[-W input.y]], [[0]], [[]],
 -[[input.y:2.1-7: warning: POSIX Yacc forbids dashes in symbol names: foo-bar
 +[[input.y:2.1-7: warning: POSIX Yacc forbids dashes in symbol names: foo-bar [-Wyacc]
  ]])
  AT_BISON_CHECK([[-Wno-none input.y]], [[0]], [[]],
 -[[input.y:2.1-7: warning: POSIX Yacc forbids dashes in symbol names: foo-bar
 +[[input.y:2.1-7: warning: POSIX Yacc forbids dashes in symbol names: foo-bar [-Wyacc]
  ]])
  
  # -Werror is not disabled by -Wnone or equivalent.
  AT_BISON_CHECK([[-Werror,none,yacc input.y]], [[1]], [[]], [[stderr]])
  AT_CHECK([[sed 's/^.*bison:/bison:/' stderr]], [[0]],
  [[bison: warnings being treated as errors
 -input.y:2.1-7: warning: POSIX Yacc forbids dashes in symbol names: foo-bar
 +input.y:2.1-7: warning: POSIX Yacc forbids dashes in symbol names: foo-bar [-Wyacc]
  ]])
  [mv stderr experr]
  AT_BISON_CHECK([[-Werror,no-all,yacc input.y]], [[1]], [[]], [[experr]])
@@@ -1483,7 -1358,7 +1484,7 @@@ m4_pushdef([AT_TEST]
  exp:;
  ]])
  AT_BISON_CHECK([[$2 input.y]], [[1]], [[]],
- [[$3: '%name-prefix' and '%define api.prefix' cannot be used together
+ [[$3: error: '%name-prefix' and '%define api.prefix' cannot be used together
  ]])
  ])
  
@@@ -1507,8 -1382,7 +1508,8 @@@ AT_SETUP([[Stray $ or @]]
  # check that the warnings are reported once, not three times.
  
  AT_DATA_GRAMMAR([[input.y]],
 -[[%token TOK
 +[[%type <TYPE> exp
 +%token <TYPE> TOK TOK2
  %destructor     { $%; @%; } <*> exp TOK;
  %initial-action { $%; @%; };
  %printer        { $%; @%; } <*> exp TOK;
@@@ -1517,14 -1391,14 +1518,14 @@@ exp: TOK        { $%; @%; $$ = $1; }
  ]])
  
  AT_BISON_CHECK([[input.y]], 0, [],
 -[[input.y:10.19: warning: stray '$'
 -input.y:10.23: warning: stray '@'
 -input.y:11.19: warning: stray '$'
 -input.y:11.23: warning: stray '@'
 -input.y:12.19: warning: stray '$'
 -input.y:12.23: warning: stray '@'
 -input.y:14.19: warning: stray '$'
 -input.y:14.23: warning: stray '@'
 +[[input.y:11.19: warning: stray '$' [-Wother]
 +input.y:11.23: warning: stray '@' [-Wother]
 +input.y:12.19: warning: stray '$' [-Wother]
 +input.y:12.23: warning: stray '@' [-Wother]
 +input.y:13.19: warning: stray '$' [-Wother]
 +input.y:13.23: warning: stray '@' [-Wother]
 +input.y:15.19: warning: stray '$' [-Wother]
 +input.y:15.23: warning: stray '@' [-Wother]
  ]])
  
  AT_CLEANUP
@@@ -1547,7 -1421,6 +1548,7 @@@ m4_pushdef([AT_TEST]
  [AT_DATA([[input.y]],
  [[%type <$1(DEAD %type)> exp
  %token <$1(DEAD %token)> a
 +%token b
  %initial-action
  {
    $$;
  };
  %%
  exp:
 -  a a[last]
 +  a a[name] b
    {
      $$;
      $][1;
      $<$1(DEAD action 1)>$
      $<$1(DEAD action 2)>1
 -    $<$1(DEAD action 3)>last
 +    $<$1(DEAD action 3)>name
      $<$1(DEAD action 4)>0
      ;
    };
diff --combined tests/named-refs.at
index f9e48a572c6b3f1a952e7fea94164fd41296982a,d76e75f3a26164fb1e59d55518fd2c2b6b4a2591..1cd55b31df18de191f3aec51578e5062b569aa01
@@@ -46,10 -46,10 +46,10 @@@ static int power (int base, int exponen
  %token <ival> NUM "number"
  %type  <ival> exp
  
 -%nonassoc '='   /* comparison        */
 +%nonassoc '='   /* comparison          */
  %left '-' '+'
  %left '*' '/'
 -%left NEG /* negation--unary minus */
 +%precedence NEG /* negation--unary minus */
  %right '^'      /* exponentiation        */
  
  %%
@@@ -211,10 -211,10 +211,10 @@@ static int power (int base, int exponen
  %token <ival> NUM "number"
  %type  <ival> exp
  
 -%nonassoc '='   /* comparison        */
 +%nonassoc '='   /* comparison          */
  %left '-' '+'
  %left '*' '/'
 -%left NEG /* negation--unary minus */
 +%precedence NEG /* negation--unary minus */
  %right '^'      /* exponentiation        */
  
  %%
@@@ -251,16 -251,16 +251,16 @@@ exp
  ]])
  
  AT_BISON_CHECK([-o test.c test.y], 1, [],
- [[test.y:50.51-60: invalid reference: '$<ival>lo9'
+ [[test.y:50.51-60: error: invalid reference: '$<ival>lo9'
  test.y:50.3-68:      symbol not found in production: lo9
 -test.y:51.51-60: warning: misleading reference: '$<ival>exp'
 -test.y:42.1-3:       refers to: $exp at $$
 -test.y:51.7:         possibly meant: $x, hiding $exp at $1
 -test.y:51.41:        possibly meant: $r, hiding $exp at $4
 +test.y:51.51-60: warning: misleading reference: '$<ival>exp' [-Wother]
- test.y:42.1-3:       warning: refers to: $exp at $$ [-Wother]
- test.y:51.7:         warning: possibly meant: $x, hiding $exp at $1 [-Wother]
- test.y:51.41:        warning: possibly meant: $r, hiding $exp at $4 [-Wother]
- test.y:52.51-52: $l of 'exp' has no declared type
- test.y:55.46-49: invalid reference: '$r12'
++test.y:42.1-3:       refers to: $exp at $$ [-Wother]
++test.y:51.7:         possibly meant: $x, hiding $exp at $1 [-Wother]
++test.y:51.41:        possibly meant: $r, hiding $exp at $4 [-Wother]
+ test.y:52.51-52: error: $l of 'exp' has no declared type
+ test.y:55.46-49: error: invalid reference: '$r12'
  test.y:55.3-53:      symbol not found in production: r12
- test.y:56.29-33: invalid reference: '$expo'
+ test.y:56.29-33: error: invalid reference: '$expo'
  test.y:56.3-46:      symbol not found in production: expo
  ]])
  AT_BISON_OPTION_POPDEFS
@@@ -277,9 -277,9 +277,9 @@@ foo: '1
  foo.bar: '2'
  ]])
  AT_BISON_CHECK([-o test.c test.y], 0, [],
 -[[test.y:11.22-29: warning: misleading reference: '$foo.bar'
 -test.y:11.8-10:      refers to: $foo at $1
 -test.y:11.12-18:     possibly meant: $[foo.bar] at $2
 +[[test.y:11.22-29: warning: misleading reference: '$foo.bar' [-Wother]
- test.y:11.8-10:      warning: refers to: $foo at $1 [-Wother]
- test.y:11.12-18:     warning: possibly meant: $[foo.bar] at $2 [-Wother]
++test.y:11.8-10:      refers to: $foo at $1 [-Wother]
++test.y:11.12-18:     possibly meant: $[foo.bar] at $2 [-Wother]
  ]])
  AT_CLEANUP
  
@@@ -353,43 -353,43 +353,43 @@@ factor:     '(' expr ')'  { $$ = $2; 
      ;
  ]])
  AT_BISON_CHECK([-o test.c test.y], 1, [],
- [[test.y:24.36-41: invalid reference: '$cond1'
+ [[test.y:24.36-41: error: invalid reference: '$cond1'
  test.y:23.11-24.62:  symbol not found in production: cond1
- test.y:26.43-53: invalid reference: '$stmt.field'
+ test.y:26.43-53: error: invalid reference: '$stmt.field'
  test.y:25.11-26.60:  symbol not found in production: stmt
  test.y:25.35-38:     possibly meant: $then.field, hiding $stmt.field at $4
- test.y:28.43-52: invalid reference: '$stmt.list'
+ test.y:28.43-52: error: invalid reference: '$stmt.list'
  test.y:27.11-28.59:  symbol not found in production: stmt
  test.y:27.30-38:     possibly meant: $[stmt.list] at $4
- test.y:30.43-46: ambiguous reference: '$xyz'
+ test.y:30.43-46: error: ambiguous reference: '$xyz'
  test.y:29.35-37:     refers to: $xyz at $4
  test.y:29.50-52:     refers to: $xyz at $6
- test.y:32.43-52: invalid reference: '$stmt.list'
+ test.y:32.43-52: error: invalid reference: '$stmt.list'
  test.y:31.11-32.63:  symbol not found in production: stmt
  test.y:31.40-43:     possibly meant: $then, hiding $[stmt.list] at $4
  test.y:31.61-64:     possibly meant: $else, hiding $[stmt.list] at $6
- test.y:34.43-58: invalid reference: '$stmt.list.field'
+ test.y:34.43-58: error: invalid reference: '$stmt.list.field'
  test.y:33.11-34.69:  symbol not found in production: stmt
  test.y:33.40-43:     possibly meant: $then.field, hiding $[stmt.list].field at $4
  test.y:33.61-64:     possibly meant: $else.field, hiding $[stmt.list].field at $6
- test.y:36.43-54: invalid reference: '$[stmt.list]'
+ test.y:36.43-54: error: invalid reference: '$[stmt.list]'
  test.y:35.11-36.71:  symbol not found in production: stmt.list
  test.y:35.40-43:     possibly meant: $then, hiding $[stmt.list] at $4
  test.y:35.61-64:     possibly meant: $else, hiding $[stmt.list] at $6
- test.y:38.43-49: invalid reference: '$then.1'
+ test.y:38.43-49: error: invalid reference: '$then.1'
  test.y:37.11-38.60:  symbol not found in production: then
  test.y:37.40-45:     possibly meant: $[then.1] at $4
- test.y:40.43-55: invalid reference: '$then.1.field'
+ test.y:40.43-55: error: invalid reference: '$then.1.field'
  test.y:39.11-40.66:  symbol not found in production: then
  test.y:39.40-45:     possibly meant: $[then.1].field at $4
- test.y:42.44-50: invalid reference: '$stmt.x'
+ test.y:42.44-50: error: invalid reference: '$stmt.x'
  test.y:41.12-42.57:  symbol not found in production: stmt
  test.y:41.36-41:     possibly meant: $[stmt.x].x, hiding $stmt.x at $4
  test.y:41.36-41:     possibly meant: $[stmt.x] at $4
- test.y:44.13-22: invalid reference: '$if-stmt-a'
+ test.y:44.13-22: error: invalid reference: '$if-stmt-a'
  test.y:43.12-44.59:  symbol not found in production: if
  test.y:43.1-9:       possibly meant: $[if-stmt-a] at $$
- test.y:46.46-54: invalid reference: '$then-a.f'
+ test.y:46.46-54: error: invalid reference: '$then-a.f'
  test.y:45.12-46.65:  symbol not found in production: then
  test.y:45.41-46:     possibly meant: $[then-a].f at $4
  ]])
@@@ -405,7 -405,7 +405,7 @@@ start: foo[] ba
    { s = $foo; }
  ]])
  AT_BISON_CHECK([-o test.c test.y], 1, [],
- [[test.y:11.12: an identifier expected
+ [[test.y:11.12: error: an identifier expected
  ]])
  AT_CLEANUP
  
@@@ -419,7 -419,7 +419,7 @@@ start: foo[ a d ] ba
    { s = $foo; }
  ]])
  AT_BISON_CHECK([-o test.c test.y], 1, [],
- [[test.y:11.15: unexpected identifier in bracketed name: 'd'
+ [[test.y:11.15: error: unexpected identifier in bracketed name: 'd'
  ]])
  AT_CLEANUP
  
@@@ -433,7 -433,7 +433,7 @@@ start: foo[/* comment */] ba
    { s = $foo; }
  ]])
  AT_BISON_CHECK([-o test.c test.y], 1, [],
- [[test.y:11.25: an identifier expected
+ [[test.y:11.25: error: an identifier expected
  ]])
  AT_CLEANUP
  
@@@ -447,10 -447,10 +447,10 @@@ start: foo[ /* aaa */ *&-.+ ] ba
    { s = $foo; }
  ]])
  AT_BISON_CHECK([-o test.c test.y], 1, [],
- [[test.y:11.23: invalid character in bracketed name: '*'
- test.y:11.24: invalid character in bracketed name: '&'
- test.y:11.25: invalid character in bracketed name: '-'
- test.y:11.27: invalid character in bracketed name: '+'
+ [[test.y:11.23: error: invalid character in bracketed name: '*'
+ test.y:11.24: error: invalid character in bracketed name: '&'
+ test.y:11.25: error: invalid character in bracketed name: '-'
+ test.y:11.27: error: invalid character in bracketed name: '+'
  ]])
  AT_CLEANUP
  
@@@ -463,7 -463,7 +463,7 @@@ AT_DATA_GRAMMAR([test.y]
  start[a s]: foo;
  ]])
  AT_BISON_CHECK([-o test.c test.y], 1, [],
- [[test.y:11.9: unexpected identifier in bracketed name: 's'
+ [[test.y:11.9: error: unexpected identifier in bracketed name: 's'
  ]])
  AT_CLEANUP
  
@@@ -510,37 -510,37 +510,37 @@@ sym_a: 'a'
  sym_b: 'b';
  ]])
  AT_BISON_CHECK([-o test.c test.y], 1, [],
- [[test.y:12.22-31: invalid reference: '$sym.field'
+ [[test.y:12.22-31: error: invalid reference: '$sym.field'
  test.y:12.3-35:      symbol not found in production: sym
- test.y:13.22-35: invalid reference: '$<aa>sym.field'
+ test.y:13.22-35: error: invalid reference: '$<aa>sym.field'
  test.y:13.3-39:      symbol not found in production: sym
- test.y:14.22-33: invalid reference: '$[sym.field]'
+ test.y:14.22-33: error: invalid reference: '$[sym.field]'
  test.y:14.3-37:      symbol not found in production: sym.field
- test.y:15.22-37: invalid reference: '$<aa>[sym.field]'
+ test.y:15.22-37: error: invalid reference: '$<aa>[sym.field]'
  test.y:15.3-41:      symbol not found in production: sym.field
- test.y:16.22-25: invalid reference: '$sym'
+ test.y:16.22-25: error: invalid reference: '$sym'
  test.y:16.3-29:      symbol not found in production: sym
- test.y:17.22-29: invalid reference: '$<aa>sym'
+ test.y:17.22-29: error: invalid reference: '$<aa>sym'
  test.y:17.3-33:      symbol not found in production: sym
- test.y:18.22-27: invalid reference: '$[sym]'
+ test.y:18.22-27: error: invalid reference: '$[sym]'
  test.y:18.3-65:      symbol not found in production before $3: sym
- test.y:18.52-61: invalid reference: '$<aa>[sym]'
+ test.y:18.52-61: error: invalid reference: '$<aa>[sym]'
  test.y:18.3-65:      symbol not found in production: sym
- test.y:22.22-31: invalid reference: '$sym-field'
+ test.y:22.22-31: error: invalid reference: '$sym-field'
  test.y:22.3-35:      symbol not found in production: sym
- test.y:23.22-35: invalid reference: '$<aa>sym-field'
+ test.y:23.22-35: error: invalid reference: '$<aa>sym-field'
  test.y:23.3-39:      symbol not found in production: sym
- test.y:24.22-33: invalid reference: '$[sym-field]'
+ test.y:24.22-33: error: invalid reference: '$[sym-field]'
  test.y:24.3-37:      symbol not found in production: sym-field
- test.y:25.22-37: invalid reference: '$<aa>[sym-field]'
+ test.y:25.22-37: error: invalid reference: '$<aa>[sym-field]'
  test.y:25.3-41:      symbol not found in production: sym-field
- test.y:26.22-25: invalid reference: '$sym'
+ test.y:26.22-25: error: invalid reference: '$sym'
  test.y:26.3-29:      symbol not found in production: sym
- test.y:27.22-29: invalid reference: '$<aa>sym'
+ test.y:27.22-29: error: invalid reference: '$<aa>sym'
  test.y:27.3-33:      symbol not found in production: sym
- test.y:28.22-27: invalid reference: '$[sym]'
+ test.y:28.22-27: error: invalid reference: '$[sym]'
  test.y:28.3-65:      symbol not found in production before $3: sym
- test.y:28.52-61: invalid reference: '$<aa>[sym]'
+ test.y:28.52-61: error: invalid reference: '$<aa>[sym]'
  test.y:28.3-65:      symbol not found in production: sym
  ]])
  AT_CLEANUP
@@@ -558,10 -558,10 +558,10 @@@ start
  .field: ;
  ]])
  AT_BISON_CHECK([[test.y]], [[1]], [],
- [[test.y:4.12-18: invalid reference: '$.field'
+ [[test.y:4.12-18: error: invalid reference: '$.field'
  test.y:4.13:        syntax error after '$', expecting integer, letter, '_', '@<:@', or '$'
  test.y:4.3-8:       possibly meant: $[.field] at $1
- test.y:5.12-18: invalid reference: '@.field'
+ test.y:5.12-18: error: invalid reference: '@.field'
  test.y:5.13:        syntax error after '@', expecting integer, letter, '_', '@<:@', or '$'
  ]])
  AT_DATA([[test.y]],
@@@ -573,7 -573,7 +573,7 @@@ start
  ;
  ]])
  AT_BISON_CHECK([[test.y]], [[0]], [],
 -[[test.y:4.9: warning: stray '$'
 -test.y:5.9: warning: stray '@'
 +[[test.y:4.9: warning: stray '$' [-Wother]
 +test.y:5.9: warning: stray '@' [-Wother]
  ]])
  AT_CLEANUP
diff --combined tests/output.at
index cce330e87e62d13d64e70d5b140026ee777fdd9e,9f1bd11533dd3706b43e8882fbb4b127cba370c1..3a13fd3ecf3580e727d048cee3e52a9c3ab8c52d
@@@ -22,91 -22,85 +22,91 @@@ AT_BANNER([[Output file names.]]
  #                 [ADDITIONAL-TESTS], [PRE-TESTS])
  # -----------------------------------------------------------------------------
  m4_define([AT_CHECK_OUTPUT],
 -[AT_SETUP([[Output files: $2 $3 $5]])
 -$7
 -for file in $1 $4; do
 -  case "$file" in
 -    */*) mkdir -p `echo "$file" | sed 's,/.*,,'`;;
 +[AT_SETUP([[Output files: ]$2 $3 $5])[
 +]$7[
 +for file in ]$1 $4[; do
 +  case $file in
 +    */*) mkdir -p `echo "$file" | sed 's,/[^/]*,,'`;;
    esac
  done
 -AT_DATA([$1],
 -[[$2
 +]AT_DATA([$1],
 +[$2[
  %%
  foo: {};
 +]])[
 +
 +]AT_BISON_CHECK([$3 $1 $5], 0)[
 +# Ignore the files non-generated files
 +]AT_CHECK([find . -type f -and -not -path './$1' -and -not -path './testsuite.log' |
 +           sed 's,\./,,' |
 +           sort |
 +           xargs echo],
 +          [], [$4
 +])[
 +]$6[
 +]AT_CLEANUP[
  ]])
  
 -AT_BISON_CHECK([$3 $1 $5], 0)
 -AT_CHECK([ls $4], [], [ignore])
 -$6
 -AT_CLEANUP
 -])
 -
  AT_CHECK_OUTPUT([foo.y], [], [-dv],
 -              [foo.output foo.tab.c foo.tab.h])
 +                [foo.output foo.tab.c foo.tab.h])
  
  # Some versions of Valgrind (at least valgrind-3.6.0.SVN-Debian) report
  # "fgrep: write error: Bad file descriptor" when stdout is closed, so we
  # skip this test group during maintainer-check-valgrind.
  AT_CHECK_OUTPUT([foo.y], [], [-dv],
 -              [foo.output foo.tab.c foo.tab.h],
 -              [>&-], [],
 -              [AT_CHECK([[case "$PREBISON" in *valgrind*) exit 77;; esac]])])
 +                [foo.output foo.tab.c foo.tab.h],
 +                [>&-], [],
 +                [AT_CHECK([[case "$PREBISON" in *valgrind*) exit 77;; esac]])])
  
  AT_CHECK_OUTPUT([foo.y], [], [-dv -o foo.c],
 -              [foo.c foo.h foo.output])
 +                [foo.c foo.h foo.output])
  AT_CHECK_OUTPUT([foo.y], [], [-dv -o foo.tab.c],
 -              [foo.output foo.tab.c foo.tab.h])
 +                [foo.output foo.tab.c foo.tab.h])
  AT_CHECK_OUTPUT([foo.y], [], [-dv -y],
 -              [y.output y.tab.c y.tab.h])
 +                [y.output y.tab.c y.tab.h])
  AT_CHECK_OUTPUT([foo.y], [], [-dv -b bar],
 -              [bar.output bar.tab.c bar.tab.h])
 +                [bar.output bar.tab.c bar.tab.h])
  AT_CHECK_OUTPUT([foo.y], [], [-dv -g -o foo.c],
 -              [foo.c foo.dot foo.h foo.output])
 +                [foo.c foo.dot foo.h foo.output])
  
  
  AT_CHECK_OUTPUT([foo.y], [%defines %verbose],      [],
 -              [foo.output foo.tab.c foo.tab.h])
 +                [foo.output foo.tab.c foo.tab.h])
  AT_CHECK_OUTPUT([foo.y], [%defines %verbose %yacc],[],
 -              [y.output y.tab.c y.tab.h])
 +                [y.output y.tab.c y.tab.h])
  
  AT_CHECK_OUTPUT([foo.yy], [%defines %verbose %yacc],[],
 -              [y.output y.tab.c y.tab.h])
 +                [y.output y.tab.c y.tab.h])
  
  # Exercise %output and %file-prefix including deprecated '='
  AT_CHECK_OUTPUT([foo.y], [%file-prefix "bar" %defines %verbose],      [],
 -              [bar.output bar.tab.c bar.tab.h])
 +                [bar.output bar.tab.c bar.tab.h])
  AT_CHECK_OUTPUT([foo.y], [%output="bar.c" %defines %verbose %yacc],[],
 -              [bar.output bar.c bar.h])
 +                [bar.c bar.h bar.output])
  AT_CHECK_OUTPUT([foo.y],
 -              [%file-prefix="baz" %output "bar.c" %defines %verbose %yacc],
 -              [],
 -              [bar.output bar.c bar.h])
 +                [%file-prefix="baz" %output "bar.c" %defines %verbose %yacc],
 +                [],
 +                [bar.c bar.h bar.output])
  
  
  # Check priorities of extension control.
  AT_CHECK_OUTPUT([foo.yy], [%defines %verbose], [],
 -              [foo.output foo.tab.cc foo.tab.hh])
 +                [foo.output foo.tab.cc foo.tab.hh])
  
  AT_CHECK_OUTPUT([foo.yy], [%defines %verbose ], [-o foo.c],
 -              [foo.c foo.h foo.output])
 +                [foo.c foo.h foo.output])
  
  AT_CHECK_OUTPUT([foo.yy], [],
 -              [--defines=foo.hpp -o foo.c++],
 -              [foo.c++ foo.hpp])
 +                [--defines=foo.hpp -o foo.c++],
 +                [foo.c++ foo.hpp])
  
  AT_CHECK_OUTPUT([foo.yy], [%defines "foo.hpp"],
 -              [-o foo.c++],
 -              [foo.c++ foo.hpp])
 +                [-o foo.c++],
 +                [foo.c++ foo.hpp])
  
  AT_CHECK_OUTPUT([foo.yy], [],
 -              [-o foo.c++ --graph=foo.gph],
 -              [foo.c++ foo.gph])
 +                [-o foo.c++ --graph=foo.gph],
 +                [foo.c++ foo.gph])
  
  
  ## ------------ ##
@@@ -119,36 -113,22 +119,36 @@@ AT_CHECK([grep 'include .subdir/' $1.cc
  AT_CHECK([grep 'include .subdir/' $1.hh], 1, [])
  ])
  
 +AT_CHECK_OUTPUT([foo.yy], [%skeleton "lalr1.cc" %verbose], [],
 +                [foo.output foo.tab.cc])
 +
  AT_CHECK_OUTPUT([foo.yy], [%skeleton "lalr1.cc" %defines %verbose], [],
 -              [foo.tab.cc foo.tab.hh foo.output location.hh stack.hh position.hh])
 +                [foo.output foo.tab.cc foo.tab.hh stack.hh])
 +
 +AT_CHECK_OUTPUT([foo.yy], [%skeleton "lalr1.cc" %verbose %locations], [],
 +                [foo.output foo.tab.cc])
 +
 +AT_CHECK_OUTPUT([foo.yy], [%skeleton "lalr1.cc" %defines %verbose %locations], [],
 +                [foo.output foo.tab.cc foo.tab.hh location.hh position.hh stack.hh])
  
  AT_CHECK_OUTPUT([subdir/foo.yy], [%skeleton "lalr1.cc" %defines %verbose], [],
 -              [foo.tab.cc foo.tab.hh foo.output location.hh stack.hh position.hh],
 -              [], [AT_CHECK_NO_SUBDIR_PART([foo.tab])])
 +                [foo.output foo.tab.cc foo.tab.hh stack.hh],
 +                [], [AT_CHECK_NO_SUBDIR_PART([foo.tab])])
  
 -AT_CHECK_OUTPUT([subdir/foo.yy], [%skeleton "lalr1.cc" %defines %verbose],
 -              [-o subdir/foo.cc],
 -              [subdir/foo.cc subdir/foo.hh subdir/foo.output subdir/location.hh subdir/stack.hh subdir/position.hh],
 -              [], [AT_CHECK_NO_SUBDIR_PART([subdir/foo])])
 +AT_CHECK_OUTPUT([subdir/foo.yy], [%skeleton "lalr1.cc" %defines %verbose %locations],
 +                [-o subdir/foo.cc],
 +                [subdir/foo.cc subdir/foo.hh subdir/foo.output subdir/location.hh subdir/position.hh subdir/stack.hh],
 +                [], [AT_CHECK_NO_SUBDIR_PART([subdir/foo])])
  
  AT_CHECK_OUTPUT([gram_dir/foo.yy],
                  [%skeleton "lalr1.cc" %defines %verbose %file-prefix "output_dir/foo"],
                  [],
 -              [output_dir/foo.tab.cc output_dir/foo.tab.hh output_dir/foo.output output_dir/location.hh output_dir/stack.hh output_dir/position.hh])
 +                [output_dir/foo.output output_dir/foo.tab.cc output_dir/foo.tab.hh output_dir/stack.hh])
 +
 +AT_CHECK_OUTPUT([gram_dir/foo.yy],
 +                [%skeleton "lalr1.cc" %defines %locations %verbose %file-prefix "output_dir/foo"],
 +                [],
 +                [output_dir/foo.output output_dir/foo.tab.cc output_dir/foo.tab.hh output_dir/location.hh output_dir/position.hh output_dir/stack.hh])
  
  
  # AT_CHECK_CONFLICTING_OUTPUT(INPUT-FILE, DIRECTIVES, FLAGS, STDERR,
@@@ -177,22 -157,22 +177,22 @@@ AT_CLEANU
  
  AT_CHECK_CONFLICTING_OUTPUT([foo.y],
  [], [--graph="foo.tab.c"],
 -[foo.y: warning: conflicting outputs to file 'foo.tab.c'
 -])
 +[[foo.y: warning: conflicting outputs to file 'foo.tab.c' [-Wother]
 +]])
  
  AT_CHECK_CONFLICTING_OUTPUT([foo.y],
  [%defines "foo.output"], [-v],
 -[foo.y: warning: conflicting outputs to file 'foo.output'
 -])
 +[[foo.y: warning: conflicting outputs to file 'foo.output' [-Wother]
 +]])
  
  AT_CHECK_CONFLICTING_OUTPUT([foo.y],
 -[%skeleton "lalr1.cc" %defines], [--graph="location.hh"],
 -[foo.y: warning: conflicting outputs to file 'location.hh'
 -])
 +[%skeleton "lalr1.cc" %defines %locations], [--graph="location.hh"],
 +[[foo.y: warning: conflicting outputs to file 'location.hh' [-Wother]
 +]])
  
  AT_CHECK_CONFLICTING_OUTPUT([foo.y], [], [-o foo.y],
- [[foo.y: refusing to overwrite the input file 'foo.y'
 -[foo.y: error: refusing to overwrite the input file 'foo.y'
 -], 1)
++[[foo.y: error: refusing to overwrite the input file 'foo.y'
 +]], 1)
  
  
  # AT_CHECK_OUTPUT_FILE_NAME(FILE-NAME-PREFIX, [ADDITIONAL-TESTS])
diff --combined tests/regression.at
index 5911c5377f9e1700d42b65df859dd07fc3c08fa8,617a6752727ab7150993a927e5901abc81399d82..2fb180e90678c72614a0117c0c76240e9923f925
@@@ -209,7 -209,7 +209,7 @@@ exp: '(' exp ')' | NUM 
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([-v -o input.c input.y], 0, [],
 -[[input.y:6.8-14: warning: symbol "<=" used more than once as a literal string
 +[[input.y:6.8-14: warning: symbol "<=" used more than once as a literal string [-Wother]
  ]])
  
  AT_CLEANUP
@@@ -401,15 -401,15 +401,15 @@@ default: 'a' 
  ]])
  
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:2.1: invalid character: '?'
- input.y:3.14: invalid character: '}'
- input.y:4.1: invalid character: '%'
- input.y:4.2: invalid character: '&'
- input.y:5.1-17: invalid directive: '%a-does-not-exist'
- input.y:6.1: invalid character: '%'
- input.y:6.2: invalid character: '-'
- input.y:7.1-8.0: missing '%}' at end of file
- input.y:7.1-8.0: syntax error, unexpected %{...%}
+ [[input.y:2.1: error: invalid character: '?'
+ input.y:3.14: error: invalid character: '}'
+ input.y:4.1: error: invalid character: '%'
+ input.y:4.2: error: invalid character: '&'
+ input.y:5.1-17: error: invalid directive: '%a-does-not-exist'
+ input.y:6.1: error: invalid character: '%'
+ input.y:6.2: error: invalid character: '-'
+ input.y:7.1-8.0: error: missing '%}' at end of file
+ input.y:7.1-8.0: error: syntax error, unexpected %{...%}
  ]])
  
  AT_CLEANUP
@@@ -428,7 -428,7 +428,7 @@@ AT_DATA([input.y]
  ]])
  
  AT_BISON_CHECK([input.y], [1], [],
- [[input.y:3.1-15: syntax error, unexpected %initial-action, expecting {...}
+ [[input.y:3.1-15: error: syntax error, unexpected %initial-action, expecting {...}
  ]])
  
  AT_CLEANUP
@@@ -478,8 -478,8 +478,8 @@@ AT_BISON_OPTION_POPDEF
  # C-string literal.  Also notice that unnecessary escaping, such as "\?", from
  # the user specification is eliminated.
  AT_BISON_CHECK([-o input.c input.y], [[0]], [[]],
 -[[input.y:22.8-14: warning: symbol SPECIAL redeclared
 -input.y:22.8-63: warning: symbol "\\'?\"\a\b\f\n\r\t\v\001\201\001\201??!" used more than once as a literal string
 +[[input.y:22.8-14: warning: symbol SPECIAL redeclared [-Wother]
 +input.y:22.8-63: warning: symbol "\\'?\"\a\b\f\n\r\t\v\001\201\001\201??!" used more than once as a literal string [-Wother]
  ]])
  AT_COMPILE([input])
  
@@@ -538,7 -538,7 +538,7 @@@ AT_SETUP([Web2c Report]
  AT_KEYWORDS([report])
  
  AT_DATA([input.y],
 -[[%token      undef_id_tok const_id_tok
 +[[%token        undef_id_tok const_id_tok
  
  %start CONST_DEC_PART
  \f
@@@ -548,12 -548,12 +548,12 @@@ CONST_DEC_PART
          ;
  
  CONST_DEC_LIST:
 -        CONST_DEC
 +          CONST_DEC
          | CONST_DEC_LIST CONST_DEC
          ;
  
  CONST_DEC:
 -        { } undef_id_tok '=' const_id_tok ';'
 +          { } undef_id_tok '=' const_id_tok ';'
          ;
  %%
  ]])
@@@ -759,6 -759,15 +759,6 @@@ AT_CHECK([[cat tables.c]], 0
         2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
         5,     6
  };
 -static const yytype_uint8 yyprhs[] =
 -{
 -       0,     0,     3,     5,     6,     9,    14
 -};
 -static const yytype_int8 yyrhs[] =
 -{
 -       8,     0,    -1,     9,    -1,    -1,    10,    11,    -1,     3,
 -       4,     5,     8,    -1,     6,     8,    -1
 -};
  static const yytype_uint8 yyrline[] =
  {
         0,     2,     2,     3,     3,     4,     5
@@@ -772,24 -781,32 +772,24 @@@ static const yytype_uint16 yytoknum[] 
  {
         0,   256,   257,   258,   259,   260,   261
  };
 -static const yytype_uint8 yyr1[] =
 -{
 -       0,     7,     8,     9,     9,    10,    11
 -};
 -static const yytype_uint8 yyr2[] =
 +static const yytype_int8 yypact[] =
  {
 -       0,     2,     1,     0,     2,     4,     2
 +      -2,    -1,     4,    -8,     0,     2,    -8,    -2,    -8,    -2,
 +      -8,    -8
  };
  static const yytype_uint8 yydefact[] =
  {
         3,     0,     0,     2,     0,     0,     1,     3,     4,     3,
         6,     5
  };
 -static const yytype_int8 yydefgoto[] =
 -{
 -      -1,     2,     3,     4,     8
 -};
 -static const yytype_int8 yypact[] =
 -{
 -      -2,    -1,     4,    -8,     0,     2,    -8,    -2,    -8,    -2,
 -      -8,    -8
 -};
  static const yytype_int8 yypgoto[] =
  {
        -8,    -7,    -8,    -8,    -8
  };
 +static const yytype_int8 yydefgoto[] =
 +{
 +      -1,     2,     3,     4,     8
 +};
  static const yytype_uint8 yytable[] =
  {
        10,     1,    11,     5,     6,     0,     7,     9
@@@ -803,14 -820,6 +803,14 @@@ static const yytype_uint8 yystos[] 
         0,     3,     8,     9,    10,     4,     0,     6,    11,     5,
         8,     8
  };
 +static const yytype_uint8 yyr1[] =
 +{
 +       0,     7,     8,     9,     9,    10,    11
 +};
 +static const yytype_uint8 yyr2[] =
 +{
 +       0,     2,     1,     0,     2,     4,     2
 +};
  ]])
  
  AT_CLEANUP
@@@ -930,11 -939,11 +930,11 @@@ AT_CHECK_DANCER([%skeleton "lalr1.cc"]
  # --------------------------------
  m4_define([_AT_DATA_EXPECT2_Y],
  [AT_DATA_GRAMMAR([expect2.y],
 -[[%{
 -static int yylex (]AT_LALR1_CC_IF([int *], [void]));
 -AT_LALR1_CC_IF([],
 -[[#include <stdio.h>
 -#include <stdlib.h>
 +[%{
 +static int yylex (AT_LALR1_CC_IF([int *], [void]));
 +AT_LALR1_CC_IF([[#include <cstdlib>]],
 +[[#include <stdlib.h>
 +#include <stdio.h>
  ]AT_YYERROR_DECLARE])[
  %}
  $1
@@@ -1029,7 -1038,7 +1029,7 @@@ AT_DATA_GRAMMAR([input.y]
  start:
    {
      printf ("Bison would once convert this action to a midrule because of the"
 -          " subsequent braced code.\n");
 +            " subsequent braced code.\n");
    }
    ;
  
@@@ -1182,8 -1191,8 +1182,8 @@@ main (void
  AT_BISON_OPTION_POPDEFS
  
  AT_BISON_CHECK([[-o input.c input.y]], [[0]],,
 -[[input.y:23.5-19: warning: rule useless in parser due to conflicts: start: start
 -input.y:27.5-19: warning: rule useless in parser due to conflicts: sr_conflict: TK2 "tok alias"
 +[[input.y:23.5-19: warning: rule useless in parser due to conflicts: start: start [-Wother]
 +input.y:27.5-19: warning: rule useless in parser due to conflicts: sr_conflict: TK2 "tok alias" [-Wother]
  ]])
  AT_COMPILE([[input]])
  AT_PARSER_CHECK([[./input]])
@@@ -1201,9 -1210,8 +1201,9 @@@ AT_CLEANU
  
  AT_SETUP([[parse-gram.y: LALR = IELR]])
  
 -# Avoid differences in synclines by telling bison that the output files
 -# have the same name.
 +# Avoid tests/bison's dark magic by processing a local copy of the
 +# grammar.  Avoid differences in synclines by telling bison that the
 +# output files have the same name.
  [cp $abs_top_srcdir/src/parse-gram.y input.y]
  AT_BISON_CHECK([[-o input.c -Dlr.type=lalr input.y]])
  [mv input.c lalr.c]
@@@ -1217,11 -1225,11 +1217,11 @@@ AT_CLEANU
  
  
  
 -## --------------------------------------- ##
 -## %error-verbose and YYSTACK_USE_ALLOCA.  ##
 -## --------------------------------------- ##
 +## -------------------------------------------- ##
 +## parse.error=verbose and YYSTACK_USE_ALLOCA.  ##
 +## -------------------------------------------- ##
  
 -AT_SETUP([[%error-verbose and YYSTACK_USE_ALLOCA]])
 +AT_SETUP([[parse.error=verbose and YYSTACK_USE_ALLOCA]])
  
  AT_BISON_OPTION_PUSHDEFS
  AT_DATA_GRAMMAR([input.y],
    #define YYSTACK_USE_ALLOCA 1
  }
  
 -%error-verbose
 +%define parse.error verbose
  
  %%
  
@@@ -1265,9 -1273,9 +1265,9 @@@ syntax_error
  %%
  
  ]AT_YYERROR_DEFINE[
 -/* Induce two syntax error messages (which requires full error
 -   recovery by shifting 3 tokens) in order to detect any loss of the
 -   reallocated buffer.  */
 +  /* Induce two syntax error messages (which requires full error
 +     recovery by shifting 3 tokens) in order to detect any loss of the
 +     reallocated buffer.  */
  ]AT_YYLEX_DEFINE(["abc"])[
  int
  main (void)
@@@ -1288,9 -1296,9 +1288,9 @@@ AT_CLEANU
  
  
  
 -## ------------------------- ##
 -## %error-verbose overflow.  ##
 -## ------------------------- ##
 +## ------------------------------ ##
 +## parse.error=verbose overflow.  ##
 +## ------------------------------ ##
  
  # Imagine the case where YYSTACK_ALLOC_MAXIMUM = YYSIZE_MAXIMUM and an
  # invocation of yysyntax_error has caused yymsg_alloc to grow to exactly
  # size calculation would return YYSIZE_MAXIMUM to yyparse.  Then,
  # yyparse would invoke yyerror using the old contents of yymsg.
  
 -AT_SETUP([[%error-verbose overflow]])
 +AT_SETUP([[parse.error=verbose overflow]])
 +
  AT_BISON_OPTION_PUSHDEFS
  AT_DATA_GRAMMAR([input.y],
  [[%code {
    #define YYMAXDEPTH 100
  }
  
 -%error-verbose
 +%define parse.error verbose
  
  %%
  
@@@ -1374,8 -1381,8 +1374,8 @@@ syntax_error2
  %%
  
  ]AT_YYERROR_DEFINE[
 -/* Induce two syntax error messages (which requires full error
 -   recovery by shifting 3 tokens).  */
 +  /* Induce two syntax error messages (which requires full error
 +     recovery by shifting 3 tokens).  */
  ]AT_YYLEX_DEFINE(["abc"])[
  int
  main (void)
@@@ -1425,7 -1432,7 +1425,7 @@@ AT_DATA_GRAMMAR([input.y]
  }
  
  ]$1[
 -%error-verbose
 +%define parse.error verbose
  %token 'c'
  
  %%
@@@ -1461,7 -1468,7 +1461,7 @@@ main (void
  AT_BISON_CHECK([[-Dparse.lac=full -Dparse.lac.es-capacity-initial=1 \
                   -Dparse.lac.memory-trace=full \
                   -t -o input.c input.y]], [[0]], [],
 -[[input.y: conflicts: 21 shift/reduce
 +[[input.y: warning: 21 shift/reduce conflicts [-Wconflicts-sr]
  ]])
  AT_COMPILE([[input]])
  AT_PARSER_CHECK([[./input > stdout.txt 2> stderr.txt]], [[1]])
@@@ -1537,7 -1544,7 +1537,7 @@@ main (void
  
  AT_BISON_CHECK([[-Dparse.lac=full -Dparse.lac.es-capacity-initial=1 \
                   -t -o input.c input.y]], [[0]], [],
 -[[input.y: conflicts: 8 shift/reduce
 +[[input.y: warning: 8 shift/reduce conflicts [-Wconflicts-sr]
  ]])
  AT_COMPILE([[input]])
  AT_BISON_OPTION_POPDEFS
diff --combined tests/skeletons.at
index ce32e88b371d96f561d12e101bc1512f0ec84b70,ec8170ca72391cb60a5ec97326dffae318fa7b0b..ce079d62924fa369d0c27dc69e7c3741145a7d08
@@@ -157,7 -157,7 +157,7 @@@ start: 
  ]])
  
  AT_BISON_CHECK([[input.y]], [[1]], [[]],
- [[<skeleton default value>: invalid value for %define Boolean variable 'foo'
+ [[<skeleton default value>: error: invalid value for %define Boolean variable 'foo'
  ]])
  
  AT_CLEANUP
@@@ -191,10 -191,10 +191,10 @@@ start: 
  ]])
  
  AT_BISON_CHECK([[input1.y]], [[1]], [[]],
 -[[input1.y: warning: foow fubar
 -foow.y:2.3-5.3: warning: foowat fubar
 +[[input1.y: warning: foow fubar [-Wother]
 +foow.y:2.3-5.3: warning: foowat fubar [-Wother]
- input1.y: fooc fubar
- fooc.y:1.1-10.5: foocat fubar
+ input1.y: error: fooc fubar
+ fooc.y:1.1-10.5: error: foocat fubar
  input1.y: fatal error: foof fubar
  ]])
  
@@@ -264,7 -264,7 +264,7 @@@ start: 
  ]])
  
  AT_BISON_CHECK([[input1.y]], [[1]], [[]],
- [[input1.y: non-fatal error
+ [[input1.y: error: non-fatal error
  input1.y: fatal error: M4 should exit immediately here
  ]])
  
@@@ -281,7 -281,7 +281,7 @@@ start: 
  ]])
  
  AT_BISON_CHECK([[input2.y]], [[1]], [[]],
 -[[input2.y: warning: morning
 +[[input2.y: warning: morning [-Wother]
  foo.y:1.5-6: fatal error: M4 should exit immediately here
  ]])