Merge branch 'maint'
authorAkim Demaille <akim@lrde.epita.fr>
Wed, 10 Oct 2012 15:31:25 +0000 (17:31 +0200)
committerAkim Demaille <akim@lrde.epita.fr>
Thu, 11 Oct 2012 07:12:43 +0000 (09:12 +0200)
* origin/maint:
  NEWS: warnings with clang
  warnings: avoid warnings from clang
  tests: no longer disable -O compiler options
  yacc.c: initialize yylval in pure-parser mode
  skeletons: style changes
  lalr1.cc: document exception safety
  lalr1.cc: check exception safety of error handling
  lalr1.cc: check (and fix) %printer exception safety
  lalr1.cc: check (and fix) %initial-action exception safety
  lalr1.cc: fix exception safety
  lalr1.cc: check exception safety.
  lalr1.cc: indentation fixes.
  lalr1.cc: don't leave macros define to nothing
  tests: minor improvements
  tests: use $PERL instead of perl
  build: look for Perl in configure.
  tests: fix sed portability issues
  tests: diff -u is not portable

Conflicts:
data/c.m4
data/glr.c
data/lalr1.cc
data/yacc.c
doc/Makefile.am
tests/atlocal.in
tests/calc.at

15 files changed:
1  2 
NEWS
THANKS
data/c.m4
data/glr.c
data/lalr1.cc
data/yacc.c
doc/bison.texi
tests/atlocal.in
tests/c++.at
tests/calc.at
tests/existing.at
tests/input.at
tests/local.at
tests/regression.at
tests/skeletons.at

diff --cc NEWS
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -2,245 -2,9 +2,245 @@@ 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
 +
 +*** Enhancements of the -Werror option
 +
 +  The -Werror=CATEGORY option is now recognized, and will treat specified
 +  warnings as errors. The warnings need not have been explictly activated
 +  using the -W option, this is similar to what gcc 4.7 does.
 +
 +  For example, given the following command line, Bison will treat both
 +  warnings related to POSIX Yacc incompatiblities and S/R conflicts as
 +  errors (and only those):
 +
 +    $ bison -Werror=yacc,error=conflicts-sr input.y
 +
 +  If no categories are specified, -Werror will make all active warnings into
 +  errors. For example, the following line does the same the previous example:
 +
 +    $ bison -Werror -Wnone -Wyacc -Wconflicts-sr input.y
 +
 +  (By default -Wconflicts-sr,conflicts-rr,deprecated,other is enabled.)
 +
 +  Note that the categories in this -Werror option may not be prefixed with
 +  "no-". However, -Wno-error[=CATEGORY] is valid.
 +
 +  Note that -y enables -Werror=yacc. Therefore it is now possible to require
 +  Yacc-like behavior (e.g., always generate y.tab.c), but to report
 +  incompatibilities as warnings: "-y -Wno-error=yacc".
 +
 +*** The display of warnings is now richer
 +
 +  The option that controls a given warning is now displayed:
 +
 +    foo.y:4.6: warning: type clash on default action: <foo> != <bar> [-Wother]
 +
 +  In the case of warnings treated as errors, the prefix is changed from
 +  "warning: " to "error: ", and the suffix is displayed, in a manner similar
 +  to gcc, as [-Werror=CATEGORY].
 +
 +  For instance, where the previous version of Bison would report (and exit
 +  with failure):
 +
 +    bison: warnings being treated as errors
 +    input.y:1.1: warning: stray ',' treated as white space
 +
 +  it now reports:
 +
 +    input.y:1.1: error: stray ',' treated as white space [-Werror=other]
 +
 +*** 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.
 +
 +*** 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
 +    foo.y: error: 1 shift/reduce conflict [-Werror=conflicts-sr]
 +    foo.y: error: 2 reduce/reduce conflicts [-Werror=conflicts-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: error: shift/reduce conflicts: 1 found, 0 expected
 +    bar.y: error: 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.
+   Bugs and portability issues in the test suite have been fixed.
  
    Some errors in translations have been addressed, and --help now directs
    users to the appropriate place to report them.
diff --cc THANKS
Simple merge
diff --cc data/c.m4
+++ b/data/c.m4
@@@ -201,8 -183,8 +201,8 @@@ m4_define([b4_int_type_for]
  m4_define([b4_table_value_equals],
  [m4_if(m4_eval($3 < m4_indir([b4_]$1[_min])
                 || m4_indir([b4_]$1[_max]) < $3), [1],
 -       [[YYID (0)]],
 +       [[0]],
-        [[((]$2[) == (]$3[))]])])
+        [(!!(($2) == ($3)))])])
  
  
  ## ---------##
diff --cc data/glr.c
@@@ -259,12 -250,22 +259,12 @@@ b4_percent_code_get[]dn
  #endif
  
  /* Suppress unused-variable warnings by "using" E.  */
 -#if ! defined lint || defined __GNUC__
 +#ifdef __GNUC__
- # define YYUSE(e) ((void) (e))
+ # define YYUSE(E) ((void) (E))
  #else
- # define YYUSE(e) /* empty */
+ # define YYUSE(E) /* empty */
  #endif
  
 -/* Identity function, used to suppress warnings about constant conditions.  */
 -#ifndef lint
 -# define YYID(N) (N)
 -#else
 -]b4_c_function_def([YYID], [static int], [[int i], [i]])[
 -{
 -  return i;
 -}
 -#endif
 -
  #ifndef YYFREE
  # define YYFREE free
  #endif
@@@ -406,7 -458,19 +407,7 @@@ dnl We probably ought to introduce a ty
  {
    ]b4_conflicting_rules[
  };
\f
 -static const ]b4_int_type_for([b4_check])[ yycheck[] =
 -{
 -  ]b4_check[
 -};
 -
 -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
 -   symbol of state STATE-NUM.  */
 -static const ]b4_int_type_for([b4_stos])[ yystos[] =
 -{
 -  ]b4_stos[
 -};
 -
  /* Error token number */
  #define YYTERROR 1
  
@@@ -913,10 -973,10 +914,10 @@@ yylhsNonterm (yyRuleNum yyrule
    return yyr1[yyrule];
  }
  
- #define yypact_value_is_default(yystate) \
-   ]b4_table_value_equals([[pact]], [[yystate]], [b4_pact_ninf])[
+ #define yypact_value_is_default(Yystate) \
+   ]b4_table_value_equals([[pact]], [[Yystate]], [b4_pact_ninf])[
  
 -/** True iff LR state STATE has only a default reduction (regardless
 +/** True iff LR state YYSTATE has only a default reduction (regardless
   *  of token).  */
  static inline yybool
  yyisDefaultedState (yyStateNum yystate)
diff --cc data/lalr1.cc
@@@ -671,18 -521,24 +671,22 @@@ m4_if(b4_prefix, [yy], []
      int yynerrs_ = 0;
      int yyerrstatus_ = 0;
  
 -    /// Semantic value of the lookahead.
 -    semantic_type yylval;
 -    /// Location of the lookahead.
 -    location_type yylloc;
 +    /// The lookahead symbol.
 +    symbol_type yyla;]b4_locations_if([[
 +
      /// The locations where the error started and ended.
 -    location_type yyerror_range[3];
 +    stack_symbol_type yyerror_range[3];]])[
  
 -    /// $$.
 -    semantic_type yyval;
 -    /// @@$.
 -    location_type yyloc;
 +    /// $$ and @@$.
 +    stack_symbol_type yylhs;
  
 +    /// The return value of parse ().
      int yyresult;
  
+     // FIXME: This shoud be completely indented.  It is not yet to
+     // avoid gratuitous conflicts when merging into the master branch.
+     try
+       {
      YYCDEBUG << "Starting parse" << std::endl;
  
  ]m4_ifdef([b4_initial_action], [
@@@ -955,22 -830,44 +959,39 @@@ m4_ifdef([b4_lex_param], [, ]b4_lex_par
      /* Do not reclaim the symbols of the rule which action triggered
         this YYABORT or YYACCEPT.  */
      yypop_ (yylen);
-     while (yystack_.size () != 1)
 -    while (1 < yystate_stack_.height ())
++    while (1 < yystack_.size ())
        {
 -        yydestruct_ ("Cleanup: popping",
 -                     yystos_[yystate_stack_[0]],
 -                     &yysemantic_stack_[0],
 -                     &yylocation_stack_[0]);
 +        yy_destroy_ ("Cleanup: popping", yystack_[0]);
          yypop_ ();
        }
  
      return yyresult;
 -    }
 +  }
+     catch (...)
+       {
+         YYCDEBUG << "Exception caught: cleaning lookahead and stack"
+                  << std::endl;
+         // Do not try to display the values of the reclaimed symbols,
+         // as their printer might throw an exception.
 -        if (yychar != yyempty_)
 -          {
 -            /* Make sure we have latest lookahead translation.  See
 -               comments at user semantic actions for why this is
 -               necessary.  */
 -            yytoken = yytranslate_ (yychar);
 -            yydestruct_ (YY_NULL, yytoken, &yylval, &yylloc);
 -          }
++        if (!yyempty)
++          yy_destroy_ (YY_NULL, yyla);
 -        while (1 < yystate_stack_.height ())
++        while (1 < yystack_.size ())
+           {
 -            yydestruct_ (YY_NULL,
 -                         yystos_[yystate_stack_[0]],
 -                         &yysemantic_stack_[0],
 -                         &yylocation_stack_[0]);
++            yy_destroy_ (YY_NULL, yystack_[0]);
+             yypop_ ();
+           }
+         throw;
+       }
+   }
  
 +  void
 +  ]b4_parser_class_name[::error (const syntax_error& yyexc)
 +  {
 +    error (]b4_join(b4_locations_if([yyexc.location]),
 +                    [[yyexc.what()]])[);
 +  }
 +
    // Generate an error message.
    std::string
    ]b4_parser_class_name[::yysyntax_error_ (]dnl
diff --cc data/yacc.c
@@@ -406,12 -435,22 +428,12 @@@ typedef short int yytype_int16
  #endif
  
  /* Suppress unused-variable warnings by "using" E.  */
 -#if ! defined lint || defined __GNUC__
 +#ifdef __GNUC__
- # define YYUSE(e) ((void) (e))
+ # define YYUSE(E) ((void) (E))
  #else
- # define YYUSE(e) /* empty */
+ # define YYUSE(E) /* empty */
  #endif
  
 -/* Identity function, used to suppress warnings about constant conditions.  */
 -#ifndef lint
 -# define YYID(N) (N)
 -#else
 -]b4_c_function_def([YYID], [static int], [[int yyi], [yyi]])[
 -{
 -  return yyi;
 -}
 -#endif
 -
  #if ]b4_lac_if([[1]], [[! defined yyoverflow || YYERROR_VERBOSE]])[
  
  /* The parser invokes alloca or malloc; define the necessary symbols.  */]dnl
@@@ -600,27 -653,97 +622,27 @@@ static const ]b4_int_type_for([b4_toknu
  };
  # endif
  
 -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 -static const ]b4_int_type_for([b4_r1])[ yyr1[] =
 -{
 -  ]b4_r1[
 -};
 -
 -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 -static const ]b4_int_type_for([b4_r2])[ yyr2[] =
 -{
 -  ]b4_r2[
 -};
 -
 -/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
 -   Performed when YYTABLE doesn't specify something else to do.  Zero
 -   means the default is an error.  */
 -static const ]b4_int_type_for([b4_defact])[ yydefact[] =
 -{
 -  ]b4_defact[
 -};
 -
 -/* YYDEFGOTO[NTERM-NUM].  */
 -static const ]b4_int_type_for([b4_defgoto])[ yydefgoto[] =
 -{
 -  ]b4_defgoto[
 -};
 -
 -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
 -   STATE-NUM.  */
  #define YYPACT_NINF ]b4_pact_ninf[
 -static const ]b4_int_type_for([b4_pact])[ yypact[] =
 -{
 -  ]b4_pact[
 -};
 -
 -/* YYPGOTO[NTERM-NUM].  */
 -static const ]b4_int_type_for([b4_pgoto])[ yypgoto[] =
 -{
 -  ]b4_pgoto[
 -};
 -
 -/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
 -   positive, shift that token.  If negative, reduce the rule which
 -   number is the opposite.  If YYTABLE_NINF, syntax error.  */
 -#define YYTABLE_NINF ]b4_table_ninf[
 -static const ]b4_int_type_for([b4_table])[ yytable[] =
 -{
 -  ]b4_table[
 -};
  
- #define yypact_value_is_default(yystate) \
-   ]b4_table_value_equals([[pact]], [[yystate]], [b4_pact_ninf])[
+ #define yypact_value_is_default(Yystate) \
+   ]b4_table_value_equals([[pact]], [[Yystate]], [b4_pact_ninf])[
  
- #define yytable_value_is_error(yytable_value) \
-   ]b4_table_value_equals([[table]], [[yytable_value]], [b4_table_ninf])[
 +#define YYTABLE_NINF ]b4_table_ninf[
 +
+ #define yytable_value_is_error(Yytable_value) \
+   ]b4_table_value_equals([[table]], [[Yytable_value]], [b4_table_ninf])[
  
 -static const ]b4_int_type_for([b4_check])[ yycheck[] =
 -{
 -  ]b4_check[
 -};
 +]b4_parser_tables_define[
  
 -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
 -   symbol of state STATE-NUM.  */
 -static const ]b4_int_type_for([b4_stos])[ yystos[] =
 -{
 -  ]b4_stos[
 -};
 +#define yyerrok         (yyerrstatus = 0)
 +#define yyclearin       (yychar = YYEMPTY)
 +#define YYEMPTY         (-2)
 +#define YYEOF           0
 +
 +#define YYACCEPT        goto yyacceptlab
 +#define YYABORT         goto yyabortlab
 +#define YYERROR         goto yyerrorlab
  
 -#define yyerrok               (yyerrstatus = 0)
 -#define yyclearin     (yychar = YYEMPTY)
 -#define YYEMPTY               (-2)
 -#define YYEOF         0
 -
 -#define YYACCEPT      goto yyacceptlab
 -#define YYABORT               goto yyabortlab
 -#define YYERROR               goto yyerrorlab
 -
 -
 -/* Like YYERROR except do call yyerror.  This remains here temporarily
 -   to ease the transition to the new meaning of YYERROR, for GCC.
 -   Once GCC version 2 has supplanted version 1, this can go.  However,
 -   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
 -   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
 -   discussed.  */
 -
 -#define YYFAIL                goto yyerrlab
 -#if defined YYFAIL
 -  /* This is here to suppress warnings from the GCC cpp's
 -     -Wunused-macros.  Normally we don't worry about that warning, but
 -     some users do, and we want to make it easy for users to remove
 -     YYFAIL uses, which will produce warnings from Bison 2.5.  */
 -#endif
  
  #define YYRECOVERING()  (!!yyerrstatus)
  
diff --cc doc/bison.texi
@@@ -9881,13 -9417,13 +9885,18 @@@ Build a new parser object.  There are n
  @samp{%parse-param @{@var{type1} @var{arg1}@}} was used.
  @end deftypemethod
  
 +@deftypemethod {syntax_error} {} syntax_error (const location_type& @var{l}, const std::string& @var{m})
 +@deftypemethodx {syntax_error} {} syntax_error (const std::string& @var{m})
 +Instantiate a syntax-error exception.
 +@end deftypemethod
 +
  @deftypemethod {parser} {int} parse ()
  Run the syntactic analysis, and return 0 on success, 1 otherwise.
+ @cindex exceptions
+ The whole function is wrapped in a @code{try}/@code{catch} block, so that
+ when an exception is thrown, the @code{%destructor}s are called to release
+ the lookahead symbol, and the symbols pushed on the stack.
  @end deftypemethod
  
  @deftypemethod {parser} {std::ostream&} debug_stream ()
@@@ -75,20 -62,20 +62,26 @@@ CONF_JAVAC='@CONF_JAVAC@
  # Empty if no Java VM was found
  CONF_JAVA='@CONF_JAVA@'
  
- # Empty if no xsltproc was found
- : ${XSLTPROC='@XSLTPROC@'}
 -# We need egrep.
 +# We need egrep and perl.
  : ${EGREP='@EGREP@'}
 +: ${PERL='@PERL@'}
  
  # Use simple quotes (lib/quote.c).
  LC_CTYPE=C
  export LC_CTYPE
  
 -: ${PERL='@PERL@'}
+ # Are special link options needed?
+ LDFLAGS='@LDFLAGS@'
+ # Are special libraries needed?
+ LIBS="$abs_top_builddir/lib/libbison.a @LIBS@ @INTLLIBS@"
+ # Empty if no xsltproc was found
+ : ${XSLTPROC='@XSLTPROC@'}
 +
 +# Handle --compile-c-with-cxx here, once CXX and CXXFLAGS are known.
 +if "$at_arg_compile_c_with_cxx"; then
 +  CC=$CXX
 +  CFLAGS=$CXXFLAGS
 +fi
diff --cc tests/c++.at
@@@ -1,6 -1,7 +1,6 @@@
- # Checking the output filenames.                    -*- Autotest -*-
+ # Checking the C++ Features.                    -*- Autotest -*-
  
 -# Copyright (C) 2004-2005, 2007, 2009-2012 Free Software Foundation,
 -# Inc.
 +# Copyright (C) 2004-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
@@@ -213,9 -27,10 +213,10 @@@ m4_define([AT_CHECK_DOXYGEN]
  [m4_case([$1],
           [Public],  [m4_pushdef([AT_DOXYGEN_PRIVATE], [NO])],
           [Private], [m4_pushdef([AT_DOXYGEN_PRIVATE], [YES])],
 -       [m4_fatal([invalid argument: $1])])
 +         [m4_fatal([invalid argument: $1])])
  AT_SETUP([Doxygen $1 Documentation])
  
+ AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"])
  AT_DATA([input.yy],
  [[%skeleton "lalr1.cc"
  %locations
@@@ -368,166 -179,239 +367,399 @@@ AT_CHECK_NAMESPACE([[foo: :bar]], [[-]]
  # contains single occurrences of `:'.
  AT_CHECK_NAMESPACE([[foo[3]::bar::baz]], [[-]])
  AT_CHECK_NAMESPACE([[foo::bar,baz]], [[-]])
 -AT_CHECK_NAMESPACE([[foo::bar::(baz]], [[-]])
 +AT_CHECK_NAMESPACE([[foo::bar::(baz /* Pacify Emacs ) */]], [[-]])
 +AT_CLEANUP
 +
 +
 +## -------------------------------------- ##
 +## Syntax error discarding no lookahead.  ##
 +## -------------------------------------- ##
 +
 +# After a syntax error, lalr1.cc used to not check whether there
 +# actually is a lookahead before discarding the lookahead.  As a result,
 +# it mistakenly invoked the destructor for the previous lookahead.
 +
 +AT_SETUP([[Syntax error discarding no lookahead]])
 +
 +AT_DATA_GRAMMAR([[input.yy]],
 +[[%skeleton "lalr1.cc"
 +
 +%code {
 +  #include <string>
 +  int yylex (yy::parser::semantic_type *);
 +  #define USE(Args)
 +}
 +
 +%defines
 +%define parse.error verbose
 +
 +%nonassoc 'a' ;
 +
 +%destructor {
 +  std::cerr << "Discarding 'a'." << std::endl;
 +} 'a'
 +
 +%%
 +
 +start: error-reduce consistent-error 'a' { USE ($3); };
 +
 +error-reduce:
 +  'a' 'a' consistent-error 'a' { USE (($1, $2, $4)); }
 +| 'a' error { std::cerr << "Reducing 'a'." << std::endl; USE ($1); }
 +;
 +
 +consistent-error:
 +  'a'
 +| /*empty*/ %prec 'a'
 +;
 +
 +// Provide another context in which all rules are useful so that this
 +// test case looks a little more realistic.
 +start: 'b' consistent-error ;
 +
 +%%
 +
 +int
 +yylex (yy::parser::semantic_type *)
 +{
 +  static char const *input = "aa";
 +  return *input++;
 +}
 +
 +void
 +yy::parser::error (const std::string &m)
 +{
 +  std::cerr << m << std::endl;
 +}
 +
 +int
 +main ()
 +{
 +  yy::parser parser;
 +  return parser.parse ();
 +}
 +]])
 +AT_BISON_CHECK([[-o input.cc input.yy]])
 +AT_COMPILE_CXX([[input]])
 +# This used to print "Discarding 'a'." again at the end.
 +AT_PARSER_CHECK([[./input]], [[1]], [[]],
 +[[syntax error
 +Discarding 'a'.
 +Reducing 'a'.
 +]])
 +
 +AT_CLEANUP
 +
 +
 +## --------------------------- ##
 +## Syntax error as exception.  ##
 +## --------------------------- ##
 +
 +AT_SETUP([[Syntax error as exception]])
 +
 +AT_DATA_GRAMMAR([[input.yy]],
 +[[%skeleton "lalr1.cc"
 +
 +%code
 +{
 +  #include <cstdlib>
 +  int yylex (yy::parser::semantic_type *);
 +}
 +
 +%defines
 +%define variant
 +%define parse.error verbose
 +%define parse.trace
 +%%
 +
 +start:
 +  thing
 +| start thing
 +;
 +
 +thing:
 +  error   { std::cerr << "caught error" << std::endl; }
 +| item
 +;
 +
 +item:
 +  'a'
 +| 's'
 +  {
 +    throw yy::parser::syntax_error ("invalid expression");
 +  }
 +
 +%%
 +
 +int
 +yylex (yy::parser::semantic_type *)
 +{
 +  // 's': syntax error, 'l': lexical error.
 +  static char const *input = "asal";
 +  switch (int res = *input++)
 +  {
 +    case 'l':
 +      throw yy::parser::syntax_error ("invalid character");
 +    default:
 +      return res;
 +  }
 +}
 +
 +void
 +yy::parser::error (const std::string &m)
 +{
 +  std::cerr << "error: " << m << std::endl;
 +}
 +
 +int
 +main ()
 +{
 +  yy::parser parser;
 +  parser.set_debug_level (!!getenv ("YYDEBUG"));
 +  return parser.parse ();
 +}
 +]])
 +AT_BISON_CHECK([[-o input.cc input.yy]])
 +AT_COMPILE_CXX([[input]])
 +
 +AT_PARSER_CHECK([[./input]], [[0]], [[]],
 +[[error: invalid expression
 +caught error
 +error: invalid character
 +caught error
 +]])
 +
  AT_CLEANUP
 -| 'e'  { YYUSE ($$); YYUSE($1); error (location_type(), "syntax error"); }
+ ## ------------------ ##
+ ## Exception safety.  ##
+ ## ------------------ ##
+ AT_SETUP([[Exception safety]])
+ AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"])
+ AT_DATA_GRAMMAR([[input.yy]],
+ [[%skeleton "lalr1.cc"
+ %defines // FIXME: Mandated in 2.6.
+ %debug
+ %error-verbose
+ %code requires
+ {
+   #include <cassert>
+   #include <cstdlib> // size_t and getenv.
+   #include <iostream>
+   #include <list>
+   bool debug = false;
+   /// A class that counts its number of instances.
+   struct Object
+   {
+     typedef std::list<const Object*> objects;
+     static objects instances;
+     char val;
+     static bool
+     empty ()
+     {
+       return instances.empty();
+     }
+     static void
+     log (Object const *o, const std::string& msg)
+     {
+       if (debug)
+         {
+           if (o)
+             std::cerr << o << "->";
+           std::cerr << msg << " {";
+           const char* sep = " ";
+           for (objects::const_iterator i = instances.begin(),
+                                        i_end = instances.end();
+                i != i_end;
+                ++i)
+             {
+               std::cerr << sep << *i;
+               sep = ", ";
+             }
+           std::cerr << " }" << std::endl;
+         }
+     }
+     Object (char v)
+       : val (v)
+     {
+       instances.push_back(this);
+       log (this, "Object::Object");
+     }
+     ~Object ()
+     {
+       instances.remove(this);
+       log (this, "Object::~Object");
+     }
+   };
+ }
+ %code
+ {
+   #include <cassert>
+   #include <cstring> // strchr
+   #include <stdexcept>
+   int yylex (yy::parser::semantic_type *);
+   Object::objects Object::instances;
+   static char const *input;
+ }
+ %union
+ {
+   Object *obj;
+ }
+ %initial-action
+ {
+   if (strchr (input, 'i'))
+     throw std::runtime_error ("initial-action");
+ }
+ %destructor { delete $$; } <obj>;
+ %printer
+ {
+   yyo << $$ << " '" << $$->val << '\'';
+   if ($$->val == 'p')
+     throw std::runtime_error ("printer");
+ } <obj>;
+ %token <obj> 'a' 'E' 'e' 'p' 'R' 's' 'T'
+ %type  <obj> list item
+ %%
+ start: list { delete $1; };
+ list:
+   item       { $$ = $1; }
+ | item list  { $$ = $1; delete $2; } // Right recursion to load the stack.
+ ;
+ item:
+   'a'  { $$ = $1; }
 -yy::parser::error (const location_type& l, const std::string& m)
++| 'e'  { YYUSE ($$); YYUSE($1); error ("syntax error"); }
+ // Not just 'E', otherwise we reduce when 'E' is the lookahead, and
+ // then the stack is emptied, defeating the point of the test.
+ | 'E' 'a' { YYUSE($1); $$ = $2; }
+ | 'R'  { $$ = YY_NULL; delete $1; YYERROR; }
+ | 'p'  { $$ = $1; }
+ | 's'  { $$ = $1; throw std::runtime_error ("reduction"); }
+ | 'T'  { $$ = YY_NULL; delete $1; YYABORT; }
+ | error { $$ = YY_NULL; yyerrok; }
+ ;
+ %%
+ int
+ yylex (yy::parser::semantic_type *lvalp)
+ {
+   // 'a': no error.
+   // 'e': user action calls error.
+   // 'E': syntax error, with yyerror that throws.
+   // 'i': initial action throws.
+   // 'l': yylex throws.
+   // 'R': call YYERROR in the action
+   // 's': reduction throws.
+   // 'T': call YYABORT in the action
+   switch (int res = *input++)
+   {
+     case 'l':
+       throw std::runtime_error ("yylex");
+     default:
+       lvalp->obj = new Object (res);
+       // Fall through.
+     case 0:
+       return res;
+   }
+ }
+ /* A C++ error reporting function.  */
+ void
 -  YYUSE (l);
++yy::parser::error (const std::string& m)
+ {
+   throw std::runtime_error (m);
+ }
+ int
+ main (int argc, const char *argv[])
+ {
+   switch (argc)
+   {
+     case 2:
+       input = argv[1];
+       break;
+     case 3:
+       assert (!strcmp (argv[1], "--debug"));
+       debug = 1;
+       input = argv[2];
+       break;
+     default:
+       abort ();
+   }
+   yy::parser parser;
+   debug |= !!getenv ("YYDEBUG");
+   parser.set_debug_level (debug);
+   int res = 2;
+   try
+   {
+     res = parser.parse ();
+   }
+   catch (const std::exception& e)
+   {
+     std::cerr << "exception caught: " << e.what () << std::endl;
+   }
+   catch (...)
+   {
+     std::cerr << "unknown exception caught" << std::endl;
+   }
+   Object::log (YY_NULL, "end");
+   assert (Object::empty());
+   return res;
+ }
+ ]])
+ AT_BISON_CHECK([[-o input.cc --report=all input.yy]])
+ AT_COMPILE_CXX([[input]])
+ AT_PARSER_CHECK([[./input aaaas]], [[2]], [[]],
+ [[exception caught: reduction
+ ]])
+ AT_PARSER_CHECK([[./input aaaal]], [[2]], [[]],
+ [[exception caught: yylex
+ ]])
+ AT_PARSER_CHECK([[./input i]], [[2]], [[]],
+ [[exception caught: initial-action
+ ]])
+ AT_PARSER_CHECK([[./input aaaap]])
+ AT_PARSER_CHECK([[./input --debug aaaap]], [[2]], [[]], [[stderr]])
+ AT_PARSER_CHECK([[grep '^exception caught: printer$' stderr]], [], [ignore])
+ AT_PARSER_CHECK([[./input aaaae]], [[2]], [[]],
+ [[exception caught: syntax error
+ ]])
+ AT_PARSER_CHECK([[./input aaaaE]], [[2]], [[]],
+ [[exception caught: syntax error, unexpected $end, expecting 'a'
+ ]])
+ AT_PARSER_CHECK([[./input aaaaT]], [[1]])
+ # There is error-recovery, so exit success.
+ AT_PARSER_CHECK([[./input aaaaR]], [[0]])
+ AT_BISON_OPTION_POPDEFS
+ AT_CLEANUP
diff --cc tests/calc.at
@@@ -503,14 -503,15 +503,17 @@@ AT_CHECK([cat stderr], 0, [expout]
  # Make sure we did not introduce bad spaces.  Checked here because all
  # the skeletons are (or should be) exercized here.
  m4_define([AT_CHECK_SPACES],
- [# No initial empty lines.
- AT_CHECK([sed -ne '/./q;=;p;' $1])
- # No trailing spaces.
- AT_CHECK([sed -ne '/[ ]$/{=;p;}' $1])
- # No tabulations.
- AT_CHECK([sed -ne '/[ ]/{=;p;}' $1])
- # No final empty lines.
- AT_CHECK([sed -ne '${/^$/{=;p;};}' $1])
+ [AT_CHECK([$PERL -ne '
+   chomp;
+   print "$.: {$_}\n"
+     if (# No starting/ending empty lines.
+         (eof || $. == 1) && /^\s*$/
 -        # No trailing space.  FIXME: not ready for "maint".
 -        # || /\s$/
++        # No trailing space.
++        || /\s$/
++        # No tabs.
++        || /\t/
+         )' $1
+ ])dnl
  ])
  
  
Simple merge
diff --cc tests/input.at
@@@ -1321,13 -1195,13 +1321,13 @@@ AT_DATA([empty.y]
  start: '';
  start: '
  ]])
- AT_CHECK([[perl -e "print 'start: \'';" >> empty.y || exit 77]])
+ 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: 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: error: missing "'" at end of file
  ]])
  
@@@ -1336,13 -1210,13 +1336,13 @@@ AT_DATA([two.y]
  start: 'ab';
  start: 'ab
  ]])
- AT_CHECK([[perl -e "print 'start: \'ab';" >> two.y || exit 77]])
+ 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: 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: error: missing "'" at end of file
  ]])
  
@@@ -1351,13 -1225,13 +1351,13 @@@ AT_DATA([three.y]
  start: 'abc';
  start: 'abc
  ]])
- AT_CHECK([[perl -e "print 'start: \'abc';" >> three.y || exit 77]])
+ 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: 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: error: missing "'" at end of file
  ]])
  
diff --cc tests/local.at
Simple merge
Simple merge
Simple merge