From: Akim Demaille Date: Wed, 10 Oct 2012 15:31:25 +0000 (+0200) Subject: Merge branch 'maint' X-Git-Tag: v2.7.90~302 X-Git-Url: https://git.saurik.com/bison.git/commitdiff_plain/23d13411c85d3a8705f9507219f61eddea57a218 Merge branch 'maint' * 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 --- 23d13411c85d3a8705f9507219f61eddea57a218 diff --cc NEWS index fd1cadd4,1fe419f4..eaa0a3de --- a/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: != [-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 term + %type nterm + %printer {} + %destructor {} + %% + nterm: term { $$ = $1; }; + + 3.28-34: warning: type is used, but is not associated to any symbol + 4.28-34: warning: type 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 symbol3 + %% + exp: "a"; + +*** Useless destructors or printers + + Bison now warns about useless destructors or printers. In the following + example, the printer for , and the destructor for are + useless: all symbols of (token1) already have a printer, and all + symbols of type (token2) already have a destructor. + + %token token1 + token2 + token3 + token4 + %printer {} token1 + %destructor {} token2 + +*** 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 data/c.m4 index 3bc2c215,994d2964..179743c9 --- a/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 index 46eaccc7,79d6ffd0..e2363a20 --- a/data/glr.c +++ b/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[ }; - + -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 index 75eaf571,3b8c9215..13f33d1e --- a/data/lalr1.cc +++ b/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 index 44f96dda,faf1d786..a1d45c43 --- a/data/yacc.c +++ b/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_NINF ]b4_table_ninf[ + - #define yytable_value_is_error(yytable_value) \ - ]b4_table_value_equals([[table]], [[yytable_value]], [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 index 4ab00c65,ce1ebd11..5b233a48 --- a/doc/bison.texi +++ b/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 () diff --cc tests/atlocal.in index 8adb3933,2f682592..e350d137 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@@ -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 + # 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@'} + -: ${PERL='@PERL@'} + +# 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 index 288ff865,dba7a758..0d491709 --- a/tests/c++.at +++ b/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 + 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 + 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 + + + ## ------------------ ## + ## 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 + #include // size_t and getenv. + #include + #include + + bool debug = false; + + /// A class that counts its number of instances. + struct Object + { + typedef std::list 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 + #include // strchr + #include + 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 $$; } ; + %printer + { + yyo << $$ << " '" << $$->val << '\''; + if ($$->val == 'p') + throw std::runtime_error ("printer"); + } ; + + %token 'a' 'E' 'e' 'p' 'R' 's' 'T' + %type list item + + %% + + start: list { delete $1; }; + + list: + item { $$ = $1; } + | item list { $$ = $1; delete $2; } // Right recursion to load the stack. + ; + + item: + 'a' { $$ = $1; } -| 'e' { YYUSE ($$); YYUSE($1); error (location_type(), "syntax error"); } ++| '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 -yy::parser::error (const location_type& l, const std::string& m) ++yy::parser::error (const std::string& m) + { - YYUSE (l); + 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 index f785d6f0,9518c3c3..1a481cf1 --- a/tests/calc.at +++ b/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 ]) diff --cc tests/input.at index 30107218,16a9308d..736ee252 --- a/tests/input.at +++ b/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 ]])