diff --git a/NEWS b/NEWS index 490e89ed..18771946 100644 --- a/NEWS +++ b/NEWS @@ -4,19 +4,23 @@ GNU Bison NEWS ** Bug fixes -*** Named %union support +*** C++ with Variants (lalr1.cc) + + Problems with %destructor and '%define parse.assert' have been fixed. + +*** Named %union support (yacc.c, glr.c) Bison 3.0 introduced a regression on named %union such as %union foo { int ival; }; - The possibility to use a name was introduced ``for Yacc compatibility''. + The possibility to use a name was introduced "for Yacc compatibility". It is however not required by POSIX Yacc, and its usefulness is not clear. -*** %define api.value.type union with %defines +*** %define api.value.type union with %defines (yacc.c, glr.c) - The yacc.c and glr.c parsers were broken when %defines was used - together with "%define api.value.type union". + The C parsers were broken when %defines was used together with "%define + api.value.type union". *** Redeclarations are reported in proper order diff --git a/README-hacking b/README-hacking index 4b773745..25e4ef34 100644 --- a/README-hacking +++ b/README-hacking @@ -103,15 +103,17 @@ to perform the first checkout of the submodules, run $ git submodule update --init -Git submodule support is weak before versions 1.6 and later, you -should probably upgrade Git if your version is older. +Git submodule support is weak before versions 1.6 and later, upgrade Git if +your version is older. The next step is to get other files needed to build, which are extracted from other source packages: $ ./bootstrap -And there you are! Just +If it fails with missing symbols (e.g., "error: possibly undefined macro: +AC_PROG_GNU_M4"), you are likely to have forgotten the submodule +initialization part. Otherwise, there you are! Just $ ./configure $ make diff --git a/THANKS b/THANKS index 2436f004..b9849103 100644 --- a/THANKS +++ b/THANKS @@ -12,6 +12,7 @@ Andreas Schwab schwab@suse.de Andrew Suffield asuffield@users.sourceforge.net Angelo Borsotti angelo.borsotti@gmail.com Anthony Heading ajrh@ajrh.net +Antonio Silva Correia amsilvacorreia@hotmail.com Arnold Robbins arnold@skeeve.com Art Haas ahaas@neosoft.com Baron Schwartz baron@sequent.org @@ -82,15 +83,19 @@ Martin Mokrejs mmokrejs@natur.cuni.cz Martin Nylin martin.nylin@linuxmail.org Matt Kraai kraai@alumni.cmu.edu Matt Rosing rosing@peakfive.com +Michael Catanzaro mcatanzaro@gnome.org Michael Felt mamfelt@gmail.com Michael Hayes m.hayes@elec.canterbury.ac.nz Michael Raskin 7c6f434c@mail.ru +Michel d'Hooge michel.dhooge@gmail.com Michiel De Wilde mdewilde.agilent@gmail.com Mickael Labau labau_m@epita.fr Mike Castle dalgoda@ix.netcom.com +Mike Sullivan Mike.sullivan@Oracle.COM Neil Booth NeilB@earthling.net Nelson H. F. Beebe beebe@math.utah.edu Nick Bowler nbowler@elliptictech.com +Nicolas Bedon nicolas.bedon@univ-rouen.fr Nicolas Burrus nicolas.burrus@epita.fr Nicolas Tisserand nicolas.tisserand@epita.fr Noah Friedman friedman@gnu.org @@ -132,6 +137,7 @@ Steve Murphy murf@parsetree.com Sum Wu sum@geekhouse.org Théophile Ranquet theophile.ranquet@gmail.com Thiru Ramakrishnan thiru.ramakrishnan@gmail.com +Thomas Jahns jahns@dkrz.de Tim Josling tej@melbpc.org.au Tim Landscheidt tim@tim-landscheidt.de Tim Van Holder tim.van.holder@pandora.be diff --git a/data/c++.m4 b/data/c++.m4 index 7c0fd78e..4321c305 100644 --- a/data/c++.m4 +++ b/data/c++.m4 @@ -174,9 +174,12 @@ m4_define([b4_public_types_declare], /// (External) token type, as returned by yylex. typedef token::yytokentype token_type; - /// Internal symbol number. + /// Symbol type: an internal symbol number. typedef int symbol_number_type; + /// The symbol type number to denote an empty symbol. + enum { empty_symbol = -2 }; + /// Internal symbol number for tokens (subsumed by symbol_number_type). typedef ]b4_int_type_for([b4_translate])[ token_number_type; @@ -209,8 +212,15 @@ m4_define([b4_public_types_declare], const semantic_type& v]b4_locations_if([, const location_type& l])[); + /// Destroy the symbol. ~basic_symbol (); + /// Destroy contents, and record that is empty. + void clear (); + + /// Whether empty. + bool empty () const; + /// Destructive move, \a s is emptied into this. void move (basic_symbol& s); @@ -240,21 +250,23 @@ m4_define([b4_public_types_declare], /// Constructor from (external) token numbers. by_type (kind_type t); + /// Record that this symbol is empty. + void clear (); + /// Steal the symbol type from \a that. void move (by_type& that); /// The (internal) type number (corresponding to \a type). - /// -1 when this symbol is empty. + /// \a empty when empty. symbol_number_type type_get () const; /// The token. token_type token () const; - enum { empty = 0 }; - /// The symbol type. - /// -1 when this symbol is empty. - token_number_type type; + /// \a empty_symbol when empty. + /// An int, not token_number_type, to be able to store empty_symbol. + int type; }; /// "External" symbols: returned by the scanner. @@ -323,9 +335,18 @@ m4_define([b4_public_types_define], template inline ]b4_parser_class_name[::basic_symbol::~basic_symbol () + { + clear (); + } + + template + inline + void + ]b4_parser_class_name[::basic_symbol::clear () {]b4_variant_if([[ // User destructor. symbol_number_type yytype = this->type_get (); + basic_symbol& yysym = *this; switch (yytype) { ]b4_symbol_foreach([b4_symbol_destructor])dnl @@ -335,6 +356,15 @@ m4_define([b4_public_types_define], // Type destructor. ]b4_symbol_variant([[yytype]], [[value]], [[template destroy]])])[ + Base::clear (); + } + + template + inline + bool + ]b4_parser_class_name[::basic_symbol::empty () const + { + return Base::type_get () == empty_symbol; } template @@ -352,7 +382,7 @@ m4_define([b4_public_types_define], // by_type. inline ]b4_parser_class_name[::by_type::by_type () - : type (empty) + : type (empty_symbol) {} inline @@ -365,12 +395,19 @@ m4_define([b4_public_types_define], : type (yytranslate_ (t)) {} + inline + void + ]b4_parser_class_name[::by_type::clear () + { + type = empty_symbol; + } + inline void ]b4_parser_class_name[::by_type::move (by_type& that) { type = that.type; - that.type = empty; + that.clear (); } inline diff --git a/data/lalr1.cc b/data/lalr1.cc index 1bbec8ae..0e0e17ae 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -214,9 +214,9 @@ b4_location_define])])[ /// Generate an error message. /// \param yystate the state where the error occurred. - /// \param yytoken the lookahead token type, or yyempty_. + /// \param yyla the lookahead token. virtual std::string yysyntax_error_ (state_type yystate, - symbol_number_type yytoken) const; + const symbol_type& yyla) const; /// Compute post-reduction state. /// \param yystate the current state @@ -288,16 +288,21 @@ b4_location_define])])[ /// Copy constructor. by_state (const by_state& other); + /// Record that this symbol is empty. + void clear (); + /// Steal the symbol type from \a that. void move (by_state& that); /// The (internal) type number (corresponding to \a state). - /// "empty" when empty. + /// \a empty_symbol when empty. symbol_number_type type_get () const; - enum { empty = 0 }; + /// The state number used to denote an empty symbol. + enum { empty_state = -1 }; /// The state. + /// \a empty when empty. state_type state; }; @@ -338,13 +343,12 @@ b4_location_define])])[ /// Pop \a n symbols the three stacks. void yypop_ (unsigned int n = 1); - // Constants. + /// Constants. enum { yyeof_ = 0, yylast_ = ]b4_last[, ///< Last index in yytable_. yynnts_ = ]b4_nterms_number[, ///< Number of nonterminal symbols. - yyempty_ = -2, yyfinal_ = ]b4_final_state_number[, ///< Termination state number. yyterror_ = 1, yyerrcode_ = 256, @@ -464,7 +468,7 @@ m4_if(b4_prefix, [yy], [], #endif // !]b4_api_PREFIX[DEBUG #define yyerrok (yyerrstatus_ = 0) -#define yyclearin (yyempty = true) +#define yyclearin (yyla.clear ()) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab @@ -533,7 +537,7 @@ m4_if(b4_prefix, [yy], [], // by_state. inline ]b4_parser_class_name[::by_state::by_state () - : state (empty) + : state (empty_state) {} inline @@ -541,12 +545,19 @@ m4_if(b4_prefix, [yy], [], : state (other.state) {} + inline + void + ]b4_parser_class_name[::by_state::clear () + { + state = empty_state; + } + inline void ]b4_parser_class_name[::by_state::move (by_state& that) { state = that.state; - that.state = empty; + that.clear (); } inline @@ -558,7 +569,7 @@ m4_if(b4_prefix, [yy], [], ]b4_parser_class_name[::symbol_number_type ]b4_parser_class_name[::by_state::type_get () const { - return state == empty ? 0 : yystos_[state]; + return state == empty_state ? empty_symbol : yystos_[state]; } inline @@ -574,7 +585,7 @@ m4_if(b4_prefix, [yy], [], [value], [move], [that.value])], [[value = that.value;]])[ // that is emptied. - that.type = empty; + that.type = empty_symbol; } inline @@ -695,9 +706,6 @@ m4_if(b4_prefix, [yy], [], int ]b4_parser_class_name[::parse () { - /// Whether yyla contains a lookahead. - bool yyempty = true; - // State. int yyn; /// Length of the RHS of the rule being reduced. @@ -754,7 +762,7 @@ b4_dollar_popdef])[]dnl goto yydefault; // Read a lookahead token. - if (yyempty) + if (yyla.empty ()) { YYCDEBUG << "Reading a token: "; try @@ -768,7 +776,6 @@ b4_dollar_popdef])[]dnl error (yyexc); goto yyerrlab1; } - yyempty = false; } YY_SYMBOL_PRINT ("Next token is", yyla); @@ -788,9 +795,6 @@ b4_dollar_popdef])[]dnl goto yyreduce; } - // Discard the token being shifted. - yyempty = true; - // Count tokens shifted since error; after three, turn off error status. if (yyerrstatus_) --yyerrstatus_; @@ -873,8 +877,7 @@ b4_dollar_popdef])[]dnl { ++yynerrs_; error (]b4_join(b4_locations_if([yyla.location]), - [[yysyntax_error_ (yystack_[0].state, - yyempty ? yyempty_ : yyla.type_get ())]])[); + [[yysyntax_error_ (yystack_[0].state, yyla)]])[); } ]b4_locations_if([[ @@ -887,10 +890,10 @@ b4_dollar_popdef])[]dnl // Return failure if at end of input. if (yyla.type_get () == yyeof_) YYABORT; - else if (!yyempty) + else if (!yyla.empty ()) { yy_destroy_ ("Error: discarding", yyla); - yyempty = true; + yyla.clear (); } } @@ -966,7 +969,7 @@ b4_dollar_popdef])[]dnl goto yyreturn; yyreturn: - if (!yyempty) + if (!yyla.empty ()) yy_destroy_ ("Cleanup: discarding lookahead", yyla); /* Do not reclaim the symbols of the rule whose action triggered @@ -986,7 +989,7 @@ b4_dollar_popdef])[]dnl << std::endl; // Do not try to display the values of the reclaimed symbols, // as their printer might throw an exception. - if (!yyempty) + if (!yyla.empty ()) yy_destroy_ (YY_NULLPTR, yyla); while (1 < yystack_.size ()) @@ -1008,10 +1011,9 @@ b4_dollar_popdef])[]dnl // Generate an error message. std::string ]b4_parser_class_name[::yysyntax_error_ (]dnl -b4_error_verbose_if([state_type yystate, symbol_number_type yytoken], - [state_type, symbol_number_type])[) const +b4_error_verbose_if([state_type yystate, const symbol_type& yyla], + [state_type, const symbol_type&])[) const {]b4_error_verbose_if([[ - std::string yyres; // Number of reported tokens (one for the "unexpected", one per // "expected"). size_t yycount = 0; @@ -1025,7 +1027,7 @@ b4_error_verbose_if([state_type yystate, symbol_number_type yytoken], the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - - The only way there can be no lookahead present (in yytoken) is + - The only way there can be no lookahead present (in yyla) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to @@ -1045,8 +1047,9 @@ b4_error_verbose_if([state_type yystate, symbol_number_type yytoken], token that will not be accepted due to an error action in a later state. */ - if (yytoken != yyempty_) + if (!yyla.empty ()) { + int yytoken = yyla.type_get (); yyarg[yycount++] = yytname_[yytoken]; int yyn = yypact_[yystate]; if (!yy_pact_value_is_default_ (yyn)) @@ -1089,6 +1092,7 @@ b4_error_verbose_if([state_type yystate, symbol_number_type yytoken], #undef YYCASE_ } + std::string yyres; // Argument number. size_t yyi = 0; for (char const* yyp = yyformat; *yyp; ++yyp) diff --git a/data/location.cc b/data/location.cc index 8e8a2c27..53fddd48 100644 --- a/data/location.cc +++ b/data/location.cc @@ -83,7 +83,7 @@ m4_define([b4_position_define], } }; - /// Add and assign a position. + /// Add \a width columns, in place. inline position& operator+= (position& res, int width) { @@ -91,21 +91,21 @@ m4_define([b4_position_define], return res; } - /// Add two position objects. + /// Add \a width columns. inline position operator+ (position res, int width) { return res += width; } - /// Add and assign a position. + /// Subtract \a width columns, in place. inline position& operator-= (position& res, int width) { return res += -width; } - /// Add two position objects. + /// Subtract \a width columns. inline position operator- (position res, int width) { @@ -216,36 +216,42 @@ m4_define([b4_location_define], position end; }; - /// Join two location objects to create a location. - inline location operator+ (location res, const location& end) + /// Join two locations, in place. + inline location& operator+= (location& res, const location& end) { res.end = end.end; return res; } - /// Change end position in place. + /// Join two locations. + inline location operator+ (location res, const location& end) + { + return res += end; + } + + /// Add \a width columns to the end position, in place. inline location& operator+= (location& res, int width) { res.columns (width); return res; } - /// Change end position. + /// Add \a width columns to the end position. inline location operator+ (location res, int width) { return res += width; } - /// Change end position in place. + /// Subtract \a width columns to the end position, in place. inline location& operator-= (location& res, int width) { return res += -width; } - /// Change end position. - inline location operator- (const location& begin, int width) + /// Subtract \a width columns to the end position. + inline location operator- (location res, int width) { - return begin + -width; + return res -= width; } ]b4_percent_define_flag_if([[define_location_comparison]], [[ /// Compare two location objects. diff --git a/data/variant.hh b/data/variant.hh index 78c2f945..f918e34c 100644 --- a/data/variant.hh +++ b/data/variant.hh @@ -95,13 +95,13 @@ m4_define([b4_variant_define], /// Empty construction. variant ()]b4_parse_assert_if([ - : yytname_ (YY_NULLPTR)])[ + : yytypeid_ (YY_NULLPTR)])[ {} /// Construct and fill. template variant (const T& t)]b4_parse_assert_if([ - : yytname_ (typeid (T).name ())])[ + : yytypeid_ (&typeid (T))])[ { YYASSERT (sizeof (T) <= S); new (yyas_ ()) T (t); @@ -110,7 +110,7 @@ m4_define([b4_variant_define], /// Destruction, allowed only if empty. ~variant () {]b4_parse_assert_if([ - YYASSERT (!yytname_); + YYASSERT (!yytypeid_); ])[} /// Instantiate an empty \a T in here. @@ -118,9 +118,9 @@ m4_define([b4_variant_define], T& build () {]b4_parse_assert_if([ - YYASSERT (!yytname_); + YYASSERT (!yytypeid_); YYASSERT (sizeof (T) <= S); - yytname_ = typeid (T).name ();])[ + yytypeid_ = & typeid (T);])[ return *new (yyas_ ()) T; } @@ -129,9 +129,9 @@ m4_define([b4_variant_define], T& build (const T& t) {]b4_parse_assert_if([ - YYASSERT (!yytname_); + YYASSERT (!yytypeid_); YYASSERT (sizeof (T) <= S); - yytname_ = typeid (T).name ();])[ + yytypeid_ = & typeid (T);])[ return *new (yyas_ ()) T (t); } @@ -140,7 +140,7 @@ m4_define([b4_variant_define], T& as () {]b4_parse_assert_if([ - YYASSERT (yytname_ == typeid (T).name ()); + YYASSERT (*yytypeid_ == typeid (T)); YYASSERT (sizeof (T) <= S);])[ return *yyas_ (); } @@ -150,7 +150,7 @@ m4_define([b4_variant_define], const T& as () const {]b4_parse_assert_if([ - YYASSERT (yytname_ == typeid (T).name ()); + YYASSERT (*yytypeid_ == typeid (T)); YYASSERT (sizeof (T) <= S);])[ return *yyas_ (); } @@ -167,8 +167,8 @@ m4_define([b4_variant_define], void swap (self_type& other) {]b4_parse_assert_if([ - YYASSERT (yytname_); - YYASSERT (yytname_ == other.yytname_);])[ + YYASSERT (yytypeid_); + YYASSERT (*yytypeid_ == *other.yytypeid_);])[ std::swap (as (), other.as ()); } @@ -198,7 +198,7 @@ m4_define([b4_variant_define], destroy () { as ().~T ();]b4_parse_assert_if([ - yytname_ = YY_NULLPTR;])[ + yytypeid_ = YY_NULLPTR;])[ } private: @@ -233,7 +233,7 @@ m4_define([b4_variant_define], } yybuffer_;]b4_parse_assert_if([ /// Whether the content is built: if defined, the name of the stored type. - const char *yytname_;])[ + const std::type_info *yytypeid_;])[ }; ]]) diff --git a/doc/bison.texi b/doc/bison.texi index 11bd2d86..1a2b169b 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -10382,9 +10382,23 @@ declare @code{yyerror} as follows: int yyerror (char const *); @end example -Bison ignores the @code{int} value returned by this @code{yyerror}. -If you use the Yacc library's @code{main} function, your -@code{yyparse} function should have the following type signature: +@noindent +The @code{int} value returned by this @code{yyerror} is ignored. + +The implementation of Yacc library's @code{main} function is: + +@example +int main (void) +@{ + setlocale (LC_ALL, ""); + return yyparse (); +@} +@end example + +@noindent +so if you use it, the internationalization support is enabled (e.g., error +messages are translated), and your @code{yyparse} function should have the +following type signature: @example int yyparse (void); @@ -10686,12 +10700,17 @@ The first, inclusive, position of the range, and the first beyond. Forwarded to the @code{end} position. @end deftypemethod -@deftypemethod {location} {location} operator+ (const location& @var{end}) -@deftypemethodx {location} {location} operator+ (int @var{width}) +@deftypemethod {location} {location} operator+ (int @var{width}) @deftypemethodx {location} {location} operator+= (int @var{width}) -@deftypemethodx {location} {location} operator- (int @var{width}) +@deftypemethodx {location} {location} operator- (int @var{width}) @deftypemethodx {location} {location} operator-= (int @var{width}) -Various forms of syntactic sugar. +Various forms of syntactic sugar for @code{columns}. +@end deftypemethod + +@deftypemethod {location} {location} operator+ (const location& @var{end}) +@deftypemethodx {location} {location} operator+= (const location& @var{end}) +Join two locations: starts at the position of the first one, and ends at the +position of the second. @end deftypemethod @deftypemethod {location} {void} step () diff --git a/doc/local.mk b/doc/local.mk index e92ea715..c340452a 100644 --- a/doc/local.mk +++ b/doc/local.mk @@ -132,7 +132,7 @@ endif ## Graphviz examples generation. ## ## ----------------------------- ## -CLEANDIRS += doc/figs +CLEANFILES += $(FIGS_GV:.gv=.eps) $(FIGS_GV:.gv=.pdf) $(FIGS_GV:.gv=.png) FIGS_GV = \ doc/figs/example.gv \ doc/figs/example-reduce.gv doc/figs/example-shift.gv diff --git a/po/POTFILES.in b/po/POTFILES.in index ee34879a..8086f556 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -15,7 +15,6 @@ src/reduce.c src/scan-code.l src/scan-gram.l src/scan-skel.l -src/symlist.c src/symtab.c djgpp/subpipe.c diff --git a/src/scan-code.l b/src/scan-code.l index f90916c1..308d1d0d 100644 --- a/src/scan-code.l +++ b/src/scan-code.l @@ -711,7 +711,7 @@ handle_action_dollar (symbol_list *rule, char *text, location dollar_loc) "]b4_rhs_value(%d, %d, ", effective_rule_length, n); obstack_quote (&obstack_for_string, type_name); obstack_sgrow (&obstack_for_string, ")["); - if (n > 0) + if (0 < n) symbol_list_n_get (effective_rule, n)->action_props.is_value_used = true; break; diff --git a/src/symlist.c b/src/symlist.c index 38f5fc8d..d70763b0 100644 --- a/src/symlist.c +++ b/src/symlist.c @@ -21,7 +21,6 @@ #include #include "system.h" -#include "complain.h" #include "symlist.h" /*--------------------------------------. @@ -174,22 +173,17 @@ symbol_list * symbol_list_n_get (symbol_list *l, int n) { int i; - - if (n < 0) - return NULL; - + aver (0 <= n); for (i = 0; i < n; ++i) { l = l->next; - if (l == NULL - || (l->content_type == SYMLIST_SYMBOL && l->content.sym == NULL)) - return NULL; + aver (l); } - + aver (l->content_type == SYMLIST_SYMBOL); + aver (l->content.sym); return l; } - /*--------------------------------------------------------------. | Get the data type (alternative in the union) of the value for | | symbol N in symbol list L. | @@ -198,21 +192,14 @@ symbol_list_n_get (symbol_list *l, int n) uniqstr symbol_list_n_type_name_get (symbol_list *l, location loc, int n) { - l = symbol_list_n_get (l, n); - if (!l) - { - complain (&loc, complaint, _("invalid $ value: $%d"), n); - return NULL; - } - aver (l->content_type == SYMLIST_SYMBOL); - return l->content.sym->content->type_name; + return symbol_list_n_get (l, n)->content.sym->content->type_name; } bool symbol_list_null (symbol_list *node) { - return !node || - (node->content_type == SYMLIST_SYMBOL && !(node->content.sym)); + return (!node + || (node->content_type == SYMLIST_SYMBOL && !node->content.sym)); } void diff --git a/src/symlist.h b/src/symlist.h index 639b593b..aeb46229 100644 --- a/src/symlist.h +++ b/src/symlist.h @@ -116,7 +116,10 @@ void symbol_list_free (symbol_list *list); /** Return the length of \c l. */ int symbol_list_length (symbol_list const *l); -/** Get item \c n in symbol list \c l. */ +/** Get item \c n in symbol list \c l. + ** \pre 0 <= n + ** \post res != NULL + **/ symbol_list *symbol_list_n_get (symbol_list *l, int n); /* Get the data type (alternative in the union) of the value for diff --git a/tests/c++.at b/tests/c++.at index f1586f55..737037d3 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -60,8 +60,10 @@ main (void) { int fail = 0; ]AT_YYLTYPE[ loc; fail += check (loc, "1.1"); + fail += check (loc + 10, "1.1-10"); loc += 10; fail += check (loc, "1.1-10"); loc += -5; fail += check (loc, "1.1-5"); + fail += check (loc - 5, "1.1"); loc -= 5; fail += check (loc, "1.1"); // Check that we don't go below. // http://lists.gnu.org/archive/html/bug-bison/2013-02/msg00000.html @@ -70,6 +72,11 @@ main (void) loc.columns (10); loc.lines (10); fail += check (loc, "1.1-11.0"); loc.lines (-2); fail += check (loc, "1.1-9.0"); loc.lines (-10); fail += check (loc, "1.1"); + + ]AT_YYLTYPE[ loc2 (YY_NULLPTR, 5, 10); + fail += check (loc2, "5.10"); + fail += check (loc + loc2, "1.1-5.9"); + loc += loc2; fail += check (loc, "1.1-5.9"); return !fail; } ]]) @@ -168,6 +175,9 @@ AT_CLEANUP ## Variants. ## ## ---------- ## +# Check that the variants are properly supported, including in error +# recovery. + # AT_TEST([DIRECTIVES]) # --------------------- # Check the support of variants in C++, with the additional DIRECTIVES. @@ -225,7 +235,7 @@ typedef std::list strings_type; template inline std::string - string_cast (const T& t) + to_string (const T& t) { std::ostringstream o; o << t; @@ -236,15 +246,18 @@ typedef std::list strings_type; %token <::std::string> TEXT; %token NUMBER; %token END_OF_FILE 0; +%token COMMA "," %type <::std::string> item; // Using the template type to exercize its parsing. // Starting with :: to ensure we don't output "<::" which starts by the // digraph for the left square bracket. -%type <::std::list> list result; +%type <::std::list> list; %printer { yyo << $$; } <::std::string> <::std::list>; +%destructor { std::cerr << "Destroy: " << $$ << '\n'; } <*>; +%destructor { std::cerr << "Destroy: \"" << $$ << "\"\n"; } <::std::string>; %% result: @@ -252,14 +265,14 @@ result: ; list: - /* nothing */ { /* Generates an empty string list */ } -| list item { std::swap ($$,$][1); $$.push_back ($][2); } -| list error { std::swap ($$,$][1); } + item { $$.push_back ($][1); } +| list "," item { std::swap ($$, $][1); $$.push_back ($][3); } +| list error { std::swap ($$, $][1); } ; item: - TEXT { std::swap ($$,$][1); } -| NUMBER { if ($][1 == 3) YYERROR; else $$ = string_cast ($][1); } + TEXT { std::swap ($$, $][1); } +| NUMBER { if ($][1 == 3) YYERROR; else $$ = to_string ($][1); } ; %% ]AT_TOKEN_CTOR_IF([], @@ -278,30 +291,43 @@ namespace yy parser::location_type* yylloc])[)]])[ {]AT_LOCATION_IF([ typedef parser::location_type location;])[ - static int stage = -1; - ++stage; - if (stage == STAGE_MAX) - {]AT_TOKEN_CTOR_IF([[ + // The 5 is a syntax error whose recovery requires that we discard + // the lookahead. This tests a regression, see + // . + static char const *input = "0,1,2,3,45,6"; + switch (int stage = *input++) + { + case 0:]AT_TOKEN_CTOR_IF([[ return parser::make_END_OF_FILE (]AT_LOCATION_IF([location ()])[);]], [AT_LOCATION_IF([ *yylloc = location ();])[ return parser::token::END_OF_FILE;]])[ - } - else if (stage % 2) - {]AT_TOKEN_CTOR_IF([[ - return parser::make_NUMBER (stage]AT_LOCATION_IF([, location ()])[);]], -[[ - yylval->BUILD (int, stage);]AT_LOCATION_IF([ + + case ',': + ]AT_TOKEN_CTOR_IF([[ + return parser::make_COMMA (]AT_LOCATION_IF([location ()])[);]], [[ +]AT_LOCATION_IF([ *yylloc = location ();])[ - return parser::token::NUMBER;]])[ - } - else - {]AT_TOKEN_CTOR_IF([[ - return parser::make_TEXT (string_cast (stage)]AT_LOCATION_IF([, location ()])[);]], [[ - yylval->BUILD (std::string, string_cast (stage));]AT_LOCATION_IF([ - *yylloc = location ();])[ - return parser::token::TEXT;]])[ - } + return parser::token::COMMA;]])[ + + default: + stage = stage - '0'; + if (stage % 2) + {]AT_TOKEN_CTOR_IF([[ + return parser::make_NUMBER (stage]AT_LOCATION_IF([, location ()])[);]], [[ + yylval->BUILD (int, stage);]AT_LOCATION_IF([ + *yylloc = location ();])[ + return parser::token::NUMBER;]])[ + } + else + {]AT_TOKEN_CTOR_IF([[ + return parser::make_TEXT (to_string (stage)]AT_LOCATION_IF([, location ()])[);]], [[ + yylval->BUILD (std::string, to_string (stage));]AT_LOCATION_IF([ + *yylloc = location ();])[ + return parser::token::TEXT;]])[ + } + } + abort (); } } @@ -312,8 +338,31 @@ namespace yy AT_FULL_COMPILE([list]) AT_PARSER_CHECK([./list], 0, -[(0, 1, 2, 4) -]) +[[(0, 1, 2, 4, 6) +]], +[[Destroy: "" +Destroy: "0" +Destroy: (0) +Destroy: 1 +Destroy: "1" +Destroy: () +Destroy: "" +Destroy: "2" +Destroy: () +Destroy: "" +Destroy: 3 +Destroy: () +Destroy: "" +Destroy: "4" +Destroy: () +Destroy: () +Destroy: 5 +Destroy: () +Destroy: "" +Destroy: "6" +Destroy: () +Destroy: (0, 1, 2, 4, 6) +]]) AT_BISON_OPTION_POPDEFS AT_CLEANUP @@ -321,11 +370,11 @@ AT_CLEANUP AT_TEST([[%skeleton "lalr1.cc" ]]) AT_TEST([[%skeleton "lalr1.cc" %define parse.assert]]) -AT_TEST([[%skeleton "lalr1.cc" %locations %define parse.assert]]) +AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %locations]]) AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %code {\n#define TWO_STAGE_BUILD\n}]]) AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define api.token.constructor]]) AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define api.token.constructor %define api.token.prefix {TOK_}]]) -AT_TEST([[%skeleton "lalr1.cc" %locations %define parse.assert %define api.token.constructor %define api.token.prefix {TOK_}]]) +AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define api.token.constructor %define api.token.prefix {TOK_} %locations]]) m4_popdef([AT_TEST]) @@ -345,6 +394,7 @@ AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) AT_DATA([input.yy], [[%skeleton "lalr1.cc" %locations +%defines %debug %% exp: /* empty */; @@ -352,7 +402,7 @@ exp: /* empty */; ]AT_YYERROR_DEFINE[ ]]) -AT_BISON_CHECK([-o input.cc input.yy], 0) +AT_BISON_CHECK([-o input.cc input.yy]) AT_DATA([Doxyfile], [# The PROJECT_NAME tag is a single word (or a sequence of words @@ -423,7 +473,7 @@ AT_CHECK_DOXYGEN([Private]) # so don't check compilation. m4_pushdef([AT_TEST], [AT_BISON_OPTION_PUSHDEFS([%language "C++" %define api.namespace {$1}]) -AT_DATA_GRAMMAR([[input.y]], +AT_DATA_GRAMMAR([[input.yy]], [[%language "C++" %define api.namespace {]$1[} %union { int i; } @@ -455,10 +505,10 @@ void ]]) -AT_BISON_CHECK([[-o input.cc input.y]]) +AT_BISON_CHECK([[-o input.cc input.yy]]) m4_if([$#], [1], -[AT_COMPILE_CXX([[input]], [[input.cc]]) +[AT_COMPILE_CXX([[input]]) AT_PARSER_CHECK([[./input]])]) AT_BISON_OPTION_POPDEFS ]) @@ -502,7 +552,7 @@ AT_SETUP([[Syntax error discarding no lookahead]]) AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) -AT_DATA_GRAMMAR([[input.yy]], +AT_DATA_GRAMMAR([[input.y]], [[%skeleton "lalr1.cc" %code { @@ -555,8 +605,7 @@ yy::parser::error (const std::string &m) ]AT_MAIN_DEFINE[ ]]) -AT_BISON_CHECK([[-o input.cc input.yy]]) -AT_COMPILE_CXX([[input]]) +AT_FULL_COMPILE([[input]]) # This used to print "Discarding 'a'." again at the end. AT_PARSER_CHECK([[./input]], [[1]], [[]], [[syntax error @@ -576,7 +625,7 @@ AT_SETUP([[Syntax error as exception]]) AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) -AT_DATA_GRAMMAR([[input.yy]], +AT_DATA_GRAMMAR([[input.y]], [[%skeleton "lalr1.cc" %code @@ -631,8 +680,7 @@ yy::parser::error (const std::string &m) ]AT_MAIN_DEFINE[ ]]) -AT_BISON_CHECK([[-o input.cc input.yy]]) -AT_COMPILE_CXX([[input]]) +AT_FULL_COMPILE([[input]]) AT_PARSER_CHECK([[./input]], [[0]], [[]], [[error: invalid expression @@ -803,10 +851,10 @@ list: item: 'a' { $$ = $][1; } -| 'e' { YYUSE ($$); YYUSE($][1); error ("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; } +| 'E' 'a' { YYUSE ($][1); $$ = $][2; } | 'R' { ]AT_VARIANT_IF([], [$$ = YY_NULLPTR; delete $][1]; )[YYERROR; } | 'p' { $$ = $][1; } | 's' { $$ = $][1; throw std::runtime_error ("reduction"); } @@ -929,9 +977,9 @@ AT_TEST([%define api.value.type variant], [without]) m4_popdef([AT_TEST]) -## ------------------------------------ ## -## C++ GLR parser identifier shadowing ## -## ------------------------------------ ## +## ------------------------------------- ## +## C++ GLR parser identifier shadowing. ## +## ------------------------------------- ## AT_SETUP([[C++ GLR parser identifier shadowing]]) @@ -967,7 +1015,7 @@ int yylex (yy::parser::semantic_type *yylval) void yy::parser::error (std::string const&) {} -int main() +int main () {} ]) diff --git a/tests/conflicts.at b/tests/conflicts.at index 819b992d..03b8fa20 100644 --- a/tests/conflicts.at +++ b/tests/conflicts.at @@ -393,10 +393,10 @@ AT_CLEANUP ## parse.error=verbose and consistent errors. ## ## ------------------------------------------- ## -AT_SETUP([[parse.error=verbose and consistent errors]]) - m4_pushdef([AT_CONSISTENT_ERRORS_CHECK], [ +AT_SETUP([[parse.error=verbose and consistent errors: $1]]) + AT_BISON_OPTION_PUSHDEFS([$1]) m4_pushdef([AT_YYLEX_PROTOTYPE], @@ -483,7 +483,11 @@ m4_popdef([AT_EXPECTING]) m4_popdef([AT_YYLEX_PROTOTYPE]) AT_BISON_OPTION_POPDEFS -]) +AT_CLEANUP +]) dnl AT_CONSISTENT_ERRORS_CHECK + + + m4_pushdef([AT_PREVIOUS_STATE_GRAMMAR], [[%nonassoc 'a'; @@ -653,7 +657,6 @@ m4_popdef([AT_USER_ACTION_INPUT]) m4_popdef([AT_CONSISTENT_ERRORS_CHECK]) -AT_CLEANUP