Merge remote-tracking branch 'origin/maint'

* origin/maint:
  tests: split a large test case into several smaller ones
  package: a bit of trouble shooting indications
  doc: liby's main arms the internationalization
  bison: avoid warnings from static code analysis
  c++: fix the use of destructors when variants are enabled
  style: tests: simplify the handling of some C++ tests
  c++: symbols can be empty, so use it
  c++: variants: don't leak the lookahead in error recovery
  c++: provide a means to clear symbols
  c++: clean up the handling of empty symbols
  c++: comment and style changes
  c++: variants: comparing addresses of typeid.name() is undefined
  c++: locations: complete the API and fix comments
  build: do not clean figure sources in make clean
This commit is contained in:
Akim Demaille
2015-01-13 14:43:02 +01:00
15 changed files with 270 additions and 152 deletions

14
NEWS
View File

@@ -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

View File

@@ -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

6
THANKS
View File

@@ -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

View File

@@ -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 <typename Base>
inline
]b4_parser_class_name[::basic_symbol<Base>::~basic_symbol ()
{
clear ();
}
template <typename Base>
inline
void
]b4_parser_class_name[::basic_symbol<Base>::clear ()
{]b4_variant_if([[
// User destructor.
symbol_number_type yytype = this->type_get ();
basic_symbol<Base>& 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 <typename Base>
inline
bool
]b4_parser_class_name[::basic_symbol<Base>::empty () const
{
return Base::type_get () == empty_symbol;
}
template <typename Base>
@@ -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

View File

@@ -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)

View File

@@ -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.

View File

@@ -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 <typename T>
variant (const T& t)]b4_parse_assert_if([
: yytname_ (typeid (T).name ())])[
: yytypeid_ (&typeid (T))])[
{
YYASSERT (sizeof (T) <= S);
new (yyas_<T> ()) 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> ()) 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 (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_<T> ();
}
@@ -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_<T> ();
}
@@ -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<T> (), other.as<T> ());
}
@@ -198,7 +198,7 @@ m4_define([b4_variant_define],
destroy ()
{
as<T> ().~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_;])[
};
]])

View File

@@ -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 ()

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -21,7 +21,6 @@
#include <config.h>
#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

View File

@@ -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

View File

@@ -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<std::string> strings_type;
template <typename T>
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<std::string> strings_type;
%token <::std::string> TEXT;
%token <int> 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<std::string>> list result;
%type <::std::list<std::string>> list;
%printer { yyo << $$; }
<int> <::std::string> <::std::list<std::string>>;
%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
// <http://savannah.gnu.org/support/?108481>.
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 ()
{}
])

View File

@@ -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