* 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.
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)))])])
## ---------##
#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
{
]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
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)
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], [
/* 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
#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
};
# 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)
@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 ()
# 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
- # 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
[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
# 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
# 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
])
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
]])
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
]])
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
]])