Hi, This is my proposal to add support for move semantics to Bison. The commit message should be clear enough. I’d be happy to receive comments/reviews.
Frank’s contribution addressed several other issues. Here, I’m focusing only on move-semantics. There’s probably more cleanup to do. For instance, it’s unpleasing that some of YY* macros are intended for the user if she wants to them, while other are definitely implementation details (e.g., YY_RVREF). We should have a consistent approach to clearly separate public from private macros. There’s also probably room for improvement in plenty of places. I have added an example/variant-11.yy that _requires_ move semantics for some of its semantics values. Please, check it. commit e5395adb79d8ca1c88a14d4da4280e2ca612ff5d Author: Akim Demaille <[email protected]> Date: Sun Aug 12 18:05:47 2018 +0200 lalr1.cc: support move semantics Symbols (terminal/non terminal) are handled by several functions that used to take const-refs, which resulted eventually in a copy pushed on the stack. With modern C++ (post C++11), move semantics allows to avoid some of these copies. This requires that std::move be used by callers, and rvalue refs (foo&&) be used by the callees. In order to avoid duplicating these functions, let's introduce macros (YY_MOVE, YY_RVREF, etc.) that rely on copy-semantics for C++98/03, and move-semantics for modern C++. That's easy for inner types, when the parser's functions pass arguments to each other. Funtions facing the user (make_NUMBER, make_STRING, etc.) should support both rvalue-refs (for instance to support move-only types: make_INT (std::make_unique<int> (1))), and lvalue-refs (so that we can pass a variable: make_INT (my_int)). To avoid the multiplication of the signatures (there is also the location), let's take the argument by copy. Suggested by Frank Heckenbach. See http://lists.gnu.org/archive/html/bug-bison/2018-03/msg00002.html, and https://lists.gnu.org/archive/html/bison-patches/2018-04/msg00002.html. * data/c++.m4 (b4_cxx_portability): New. (basic_symbol): In C++11, replace copy-ctors with move-ctors. In C++11, replace copies with moves. * data/lalr1.cc (stack_symbol_type, yypush_): Likewise. Use YY_MOVE to avoid useless copies. * data/variant.hh (variant): Support move-semantics. (make_SYMBOL): In C++11, in order to support both read-only lvalues, and rvalues, take the argument as a copy. * data/stack.hh (yypush_): Use rvalue-refs in C++11. * tests/c++.at: Use move semantics. * tests/headers.at: Adjust to the new macros (YY_MOVE, etc.). * configure.ac (CXX98_CXXFLAGS, CXX11_CXXFLAGS, CXX14_CXXFLAGS) (CXX17_CXXFLAGS, ENABLE_CXX11): New. * tests/atlocal.in: Receive them. * examples/variant-11.test, examples/variant-11.yy: New. Check the support of move-only types. * examples/README, examples/local.mk: Adjust. diff --git a/configure.ac b/configure.ac index cf4428d7..ea89dbae 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,8 @@ AC_PROG_CC_STDC AC_PROG_CXX AC_LANG_PUSH([C++]) gl_WARN_ADD([-fno-exceptions], [NO_EXCEPTIONS_CXXFLAGS]) +gl_WARN_ADD([-std=c++11], [CXX11_CXXFLAGS]) +AM_CONDITIONAL([ENABLE_CXX11], [test x"$CXX11_CXXFLAGS" != x]) AC_LANG_POP([C++]) # Gnulib (early checks). diff --git a/data/c++.m4 b/data/c++.m4 index 0b23b3e0..32bf8254 100644 --- a/data/c++.m4 +++ b/data/c++.m4 @@ -50,6 +50,25 @@ m4_define([b4_inline], [m4_fatal([$0: invalid argument: $1])])]) +# b4_cxx_portability +# ------------------ +m4_define([b4_cxx_portability], +[// Support move semantics when possible. +#if defined __cplusplus && 201103L <= __cplusplus +# define YY_MOVE std::move +# define YY_MOVE_OR_COPY move +# define YY_MOVE_REF(Type) Type&& +# define YY_RVREF(Type) Type&& +# define YY_COPY(Type) Type +#else +# define YY_MOVE +# define YY_MOVE_OR_COPY copy +# define YY_MOVE_REF(Type) Type& +# define YY_RVREF(Type) const Type& +# define YY_COPY(Type) const Type& +#endif[]dnl +]) + ## ---------------- ## ## Default values. ## @@ -219,19 +238,20 @@ m4_define([b4_symbol_type_declare], /// Default constructor. basic_symbol (); - /// Copy constructor. - basic_symbol (const basic_symbol& other); + /// Move or copy constructor. + basic_symbol (YY_RVREF (basic_symbol) other); + ]b4_variant_if([[ /// Constructor for valueless symbols, and symbols from each type. ]b4_type_foreach([b4_basic_symbol_constructor_declare])], [[ /// Constructor for valueless symbols. basic_symbol (typename Base::kind_type t]b4_locations_if([, - const location_type& l])[); + YY_MOVE_REF (location_type) l])[); /// Constructor for symbols with semantic value. basic_symbol (typename Base::kind_type t, - const semantic_type& v]b4_locations_if([, - const location_type& l])[);]])[ + YY_RVREF (semantic_type) v]b4_locations_if([, + YY_RVREF (location_type) l])[);]])[ /// Destroy the symbol. ~basic_symbol (); @@ -312,13 +332,13 @@ m4_define([b4_public_types_define], {} template <typename Base> - ]b4_parser_class_name[::basic_symbol<Base>::basic_symbol (const basic_symbol& other) - : Base (other) - , value (]b4_variant_if([], [other.value])[)]b4_locations_if([ - , location (other.location)])[ + ]b4_parser_class_name[::basic_symbol<Base>::basic_symbol (YY_RVREF (basic_symbol) other) + : Base (YY_MOVE (other)) + , value (]b4_variant_if([], [YY_MOVE (other.value)]))b4_locations_if([ + , location (YY_MOVE (other.location))])[ {]b4_variant_if([ - b4_symbol_variant([other.type_get ()], [value], [copy], - [other.value])])[ + b4_symbol_variant([other.type_get ()], [value], [YY_MOVE_OR_COPY], + [YY_MOVE (other.value)])])[ } ]b4_variant_if([[ @@ -328,7 +348,7 @@ m4_define([b4_public_types_define], template <typename Base> ]b4_parser_class_name[::basic_symbol<Base>::basic_symbol (]b4_join( [typename Base::kind_type t], - b4_locations_if([const location_type& l]))[) + b4_locations_if([YY_MOVE_REF (location_type) l]))[) : Base (t) , value ()]b4_locations_if([ , location (l)])[ @@ -337,14 +357,14 @@ m4_define([b4_public_types_define], template <typename Base> ]b4_parser_class_name[::basic_symbol<Base>::basic_symbol (]b4_join( [typename Base::kind_type t], - [const semantic_type& v], - b4_locations_if([const location_type& l]))[) + [YY_RVREF (semantic_type) v], + b4_locations_if([YY_RVREF (location_type) l]))[) : Base (t) - , value (]b4_variant_if([], [v])[)]b4_locations_if([ - , location (l)])[ + , value (]b4_variant_if([], [YY_MOVE (v)])[)]b4_locations_if([ + , location (YY_MOVE (l))])[ {]b4_variant_if([[ (void) v; - ]b4_symbol_variant([this->type_get ()], [value], [copy], [v])])[}]])[ + ]b4_symbol_variant([this->type_get ()], [value], [YY_MOVE_OR_COPY], [YY_MOVE (v)])])[}]])[ template <typename Base> ]b4_parser_class_name[::basic_symbol<Base>::~basic_symbol () @@ -385,9 +405,9 @@ m4_define([b4_public_types_define], { super_type::move (s); ]b4_variant_if([b4_symbol_variant([this->type_get ()], [value], [move], - [s.value])], - [value = s.value;])[]b4_locations_if([ - location = s.location;])[ + [YY_MOVE (s.value)])], + [value = YY_MOVE (s.value);])[]b4_locations_if([ + location = YY_MOVE (s.location);])[ } // by_type. diff --git a/data/lalr1.cc b/data/lalr1.cc index 4679eb42..239c242b 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -153,13 +153,17 @@ m4_define([b4_shared_declarations], # include <iostream> # include <stdexcept> # include <string> -# include <vector>]b4_defines_if([[ +# include <vector> + +]b4_cxx_portability[ +]b4_defines_if([[ # include "stack.hh" ]b4_bison_locations_if([[# include "location.hh"]])])[ ]b4_variant_if([b4_variant_includes])[ ]b4_attribute_define[ ]b4_null_define[ + ]b4_YYDEBUG_define[ ]b4_namespace_open[ @@ -318,12 +322,12 @@ b4_location_define])])[ typedef basic_symbol<by_state> super_type; /// Construct an empty symbol. stack_symbol_type (); - /// Copy construct (for efficiency). - stack_symbol_type (const stack_symbol_type& that); + /// Move or copy construction. + stack_symbol_type (YY_RVREF (stack_symbol_type) that); /// Steal the contents from \a sym to build this. - stack_symbol_type (state_type s, symbol_type& sym); + stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) sym); /// Assignment, needed by push_back. - stack_symbol_type& operator= (stack_symbol_type& that); + stack_symbol_type& operator= (YY_MOVE_REF (stack_symbol_type) that); }; /// Stack type. @@ -337,15 +341,15 @@ b4_location_define])])[ /// if null, no trace is output. /// \param sym the symbol /// \warning the contents of \a s.value is stolen. - void yypush_ (const char* m, stack_symbol_type& sym); + void yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym); /// Push a new look ahead token on the state on the stack. /// \param m a debug message to display /// if null, no trace is output. /// \param s the state /// \param sym the symbol (for its value and location). - /// \warning the contents of \a s.value is stolen. - void yypush_ (const char* m, state_type s, symbol_type& sym); + /// \warning the contents of \a sym.value is stolen. + void yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym); /// Pop \a n symbols the three stacks. void yypop_ (unsigned n = 1); @@ -588,34 +592,33 @@ m4_if(b4_prefix, [yy], [], ]b4_parser_class_name[::stack_symbol_type::stack_symbol_type () {} - ]b4_parser_class_name[::stack_symbol_type::stack_symbol_type (const stack_symbol_type& that) - : super_type (that.state]b4_variant_if([], [, that.value])[]b4_locations_if([, that.location])[) + ]b4_parser_class_name[::stack_symbol_type::stack_symbol_type (YY_RVREF (stack_symbol_type) that) + : super_type (YY_MOVE (that.state)]b4_variant_if([], [, YY_MOVE (that.value)])b4_locations_if([, YY_MOVE (that.location)])[) {]b4_variant_if([ b4_symbol_variant([that.type_get ()], - [value], [copy], [that.value])])[ + [value], [YY_MOVE_OR_COPY], [YY_MOVE (that.value)])])[ } - ]b4_parser_class_name[::stack_symbol_type::stack_symbol_type (state_type s, symbol_type& that) - : super_type (s]b4_variant_if([], [, that.value])[]b4_locations_if([, that.location])[) + ]b4_parser_class_name[::stack_symbol_type::stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) that) + : super_type (s]b4_variant_if([], [, YY_MOVE (that.value)])[]b4_locations_if([, YY_MOVE (that.location)])[) {]b4_variant_if([ b4_symbol_variant([that.type_get ()], - [value], [move], [that.value])])[ + [value], [move], [YY_MOVE (that.value)])])[ // that is emptied. that.type = empty_symbol; } ]b4_parser_class_name[::stack_symbol_type& - ]b4_parser_class_name[::stack_symbol_type::operator= (stack_symbol_type& that) + ]b4_parser_class_name[::stack_symbol_type::operator= (YY_MOVE_REF (stack_symbol_type) that) { state = that.state; ]b4_variant_if([b4_symbol_variant([that.type_get ()], - [value], [move], [that.value])], - [[value = that.value;]])[]b4_locations_if([ - location = that.location;])[ + [value], [move], [YY_MOVE (that.value)])], + [[value = YY_MOVE (that.value);]])[]b4_locations_if([ + location = YY_MOVE (that.location);])[ return *this; } - template <typename Base> void ]b4_parser_class_name[::yy_destroy_ (const char* yymsg, basic_symbol<Base>& yysym) const @@ -649,18 +652,22 @@ m4_if(b4_prefix, [yy], [], #endif void - ]b4_parser_class_name[::yypush_ (const char* m, stack_symbol_type& sym) + ]b4_parser_class_name[::yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym) { if (m) YY_SYMBOL_PRINT (m, sym); - yystack_.push (sym); + yystack_.push (YY_MOVE (sym)); } void - ]b4_parser_class_name[::yypush_ (const char* m, state_type s, symbol_type& sym) + ]b4_parser_class_name[::yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym) { - stack_symbol_type t (s, sym); - yypush_ (m, t); +#if defined __cplusplus && 201103L <= __cplusplus + yypush_ (m, stack_symbol_type (s, YY_MOVE (sym))); +#else + stack_symbol_type ss(s, sym); + yypush_ (m, ss); +#endif } void @@ -756,7 +763,7 @@ b4_dollar_popdef])[]dnl location values to have been already stored, initialize these stacks with a primary value. */ yystack_.clear (); - yypush_ (YY_NULLPTR, 0, yyla); + yypush_ (YY_NULLPTR, 0, YY_MOVE (yyla)); // A new symbol was pushed on the stack. yynewstate: @@ -818,7 +825,7 @@ b4_dollar_popdef])[]dnl --yyerrstatus_; // Shift the lookahead token. - yypush_ ("Shifting", yyn, yyla); + yypush_ ("Shifting", yyn, YY_MOVE (yyla)); goto yynewstate; /*-----------------------------------------------------------. @@ -887,7 +894,7 @@ b4_dollar_popdef])[]dnl YY_STACK_PRINT (); // Shift the result of the reduction. - yypush_ (YY_NULLPTR, yylhs); + yypush_ (YY_NULLPTR, YY_MOVE (yylhs)); } goto yynewstate; @@ -976,7 +983,7 @@ b4_dollar_popdef])[]dnl // Shift the error token. error_token.state = yyn; - yypush_ ("Shifting", error_token); + yypush_ ("Shifting", YY_MOVE (error_token)); } goto yynewstate; diff --git a/data/stack.hh b/data/stack.hh index f3ac21f9..f74cdfd2 100644 --- a/data/stack.hh +++ b/data/stack.hh @@ -62,7 +62,7 @@ m4_define([b4_stack_define], /// /// Close to move-semantics. void - push (T& t) + push (YY_MOVE_REF (T) t) { seq_.push_back (T()); operator[](0).move (t); @@ -142,6 +142,8 @@ b4_copyright([Stack handling for Bison parsers in C++])[ # include <vector> +]b4_cxx_portability[ + ]b4_namespace_open[ ]b4_stack_define[ ]b4_namespace_close[ diff --git a/data/variant.hh b/data/variant.hh index a10d9447..4ba3f006 100644 --- a/data/variant.hh +++ b/data/variant.hh @@ -101,11 +101,11 @@ m4_define([b4_variant_define], /// Construct and fill. template <typename T> - variant (const T& t)]b4_parse_assert_if([ + variant (YY_RVREF (T) t)]b4_parse_assert_if([ : yytypeid_ (&typeid (T))])[ { YYASSERT (sizeof (T) <= S); - new (yyas_<T> ()) T (t); + new (yyas_<T> ()) T (YY_MOVE (t)); } /// Destruction, allowed only if empty. @@ -183,10 +183,26 @@ m4_define([b4_variant_define], move (self_type& other) { build<T> (); +# if defined __cplusplus && 201103L <= __cplusplus + as<T> () = YY_MOVE (other.as<T> ()); +# else swap<T> (other); +# endif other.destroy<T> (); } +# if defined __cplusplus && 201103L <= __cplusplus + /// Move the content of \a other to this. + template <typename T> + void + move (self_type&& other) + { + build<T> (); + as<T> () = YY_MOVE (other.as<T> ()); + other.destroy<T> (); + } +#endif + /// Copy the content of \a other to this. template <typename T> void @@ -293,8 +309,8 @@ m4_define([b4_symbol_constructor_declare_], symbol_type make_[]b4_symbol_([$1], [id]) (dnl b4_join(b4_symbol_if([$1], [has_type], - [const b4_symbol([$1], [type])& v]), - b4_locations_if([const location_type& l]))); + [YY_COPY (b4_symbol([$1], [type])) v]), + b4_locations_if([YY_COPY (location_type) l]))); ])])]) @@ -318,12 +334,12 @@ m4_define([b4_symbol_constructor_define_], b4_parser_class_name::symbol_type b4_parser_class_name::make_[]b4_symbol_([$1], [id]) (dnl b4_join(b4_symbol_if([$1], [has_type], - [const b4_symbol([$1], [type])& v]), - b4_locations_if([const location_type& l]))) + [YY_COPY (b4_symbol([$1], [type])) v]), + b4_locations_if([YY_COPY (location_type) l]))) { return symbol_type (b4_join([token::b4_symbol([$1], [id])], - b4_symbol_if([$1], [has_type], [v]), - b4_locations_if([l]))); + b4_symbol_if([$1], [has_type], [YY_MOVE (v)]), + b4_locations_if([YY_MOVE (l)]))); } ])])]) @@ -335,8 +351,8 @@ b4_join(b4_symbol_if([$1], [has_type], m4_define([b4_basic_symbol_constructor_declare], [[ basic_symbol (]b4_join( [typename Base::kind_type t], - b4_symbol_if([$1], [has_type], const b4_symbol([$1], [type])[& v]), - b4_locations_if([const location_type& l]))[); + b4_symbol_if([$1], [has_type], [YY_RVREF (b4_symbol([$1], [type])) v]), + b4_locations_if([YY_RVREF (location_type) l]))[); ]]) # b4_basic_symbol_constructor_define @@ -346,11 +362,11 @@ m4_define([b4_basic_symbol_constructor_define], [[ template <typename Base> ]b4_parser_class_name[::basic_symbol<Base>::basic_symbol (]b4_join( [typename Base::kind_type t], - b4_symbol_if([$1], [has_type], const b4_symbol([$1], [type])[& v]), - b4_locations_if([const location_type& l]))[) + b4_symbol_if([$1], [has_type], [YY_RVREF (b4_symbol([$1], [type])) v]), + b4_locations_if([YY_RVREF (location_type) l]))[) : Base (t)]b4_symbol_if([$1], [has_type], [ - , value (v)])[]b4_locations_if([ - , location (l)])[ + , value (YY_MOVE (v))])[]b4_locations_if([ + , location (YY_MOVE (l))])[ {} ]]) diff --git a/examples/README b/examples/README index 9780d829..f0670cd0 100644 --- a/examples/README +++ b/examples/README @@ -13,6 +13,10 @@ A C++ example that uses variants (they allow to use any C++ type as semantic value type) and symbol constructors (they ensure consistency between declared token type and effective semantic value). +* variant-11.yy +Another C++ example, closely related to the previous one, but exhibiting +support for C++11's move semantics. + ----- Local Variables: @@ -22,19 +26,11 @@ End: Copyright (C) 2018 Free Software Foundation, Inc. -This file is part of Bison, the GNU Compiler Compiler. - -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 -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.3 or +any later version published by the Free Software Foundation; with no +Invariant Sections, with no Front-Cover Texts, and with no Back-Cover +Texts. A copy of the license is included in the "GNU Free +Documentation License" file as part of this distribution. # LocalWords: mfcalc calc parsers yy diff --git a/examples/local.mk b/examples/local.mk index 2518da34..a5667f92 100644 --- a/examples/local.mk +++ b/examples/local.mk @@ -45,14 +45,24 @@ $(extracted): %D%/extracted.stamp ## Examples. ## ## ---------- ## + examplesdir = $(docdir)/examples -dist_examples_DATA = %D%/README %D%/variant.yy +dist_examples_DATA = %D%/README %D%/variant.yy %D%/variant-11.yy check_PROGRAMS += %D%/variant nodist_%C%_variant_SOURCES = %D%/variant.yy %C%_variant_CPPFLAGS = -I$(top_builddir) dist_TESTS += %D%/variant.test +%D%/variant.cc: $(BISON_IN) $(dist_pkgdata_DATA) +if ENABLE_CXX11 + check_PROGRAMS += %D%/variant-11 + nodist_%C%_variant_11_SOURCES = %D%/variant-11.yy + %C%_variant_11_CXXFLAGS = $(CXX11_CXXFLAGS) + %C%_variant_11_CPPFLAGS = -I$(top_builddir) + dist_TESTS += %D%/variant-11.test + %D%/variant-11.cc: $(BISON_IN) $(dist_pkgdata_DATA) +endif include %D%/calc++/local.mk include %D%/mfcalc/local.mk diff --git a/examples/variant-11.test b/examples/variant-11.test new file mode 100644 index 00000000..3bc2b397 --- /dev/null +++ b/examples/variant-11.test @@ -0,0 +1,19 @@ +#! /bin/sh + +# Copyright (C) 2018 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 +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +: >input +run 0 "{I have three numbers for you., 1, 2, 3, And that's all!}" diff --git a/examples/variant-11.yy b/examples/variant-11.yy new file mode 100644 index 00000000..d8481121 --- /dev/null +++ b/examples/variant-11.yy @@ -0,0 +1,163 @@ +/* + Copyright (C) 2008-2015, 2018 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +%debug +%language "c++" +%defines +%define api.token.constructor +%define api.value.type variant +%define parse.assert +%locations + +%code requires // *.hh +{ +#include <memory> // std::unique_ptr +#include <string> +#include <vector> + + using ustring = std::unique_ptr<std::string>; + using ustrings = std::vector<ustring>; +} + +%code // *.cc +{ +#include <algorithm> +#include <iostream> +#include <iterator> +#include <sstream> + + // Prototype of the yylex function providing subsequent tokens. + namespace yy + { + static parser::symbol_type yylex (); + } + + // Printing a vector of strings. + // Koening look up will look into std, since that's an std::vector. + namespace std + { + std::ostream& + operator<< (std::ostream& o, const ustrings& ss) + { + o << '{'; + const char *sep = ""; + for (const auto& s: ss) + { + o << sep << *s; + sep = ", "; + } + return o << '}'; + } + } + + template <typename... Args> + ustring + make_ustring (Args&&... args) + { + // std::make_unique is C++14. + return std::unique_ptr<std::string>(new std::string(std::forward<Args>(args)...)); + } + + // Conversion to string. + template <typename T> + std::string + to_string (const T& t) + { + auto&& o = std::ostringstream{}; + o << t; + return o.str (); + } +} + +%token <ustring> TEXT; +%token <int> NUMBER; +%printer { yyo << '(' << &$$ << ") " << $$; } <*>; +%printer { yyo << *$$; } <ustring>; +%token END_OF_FILE 0; + +%type <ustring> item; +%type <ustrings> list; + +%% + +result: + list { std::cout << $1 << '\n'; } +; + +list: + %empty { /* Generates an empty string list */ } +| list item { $$ = std::move ($1); $$.emplace_back (std::move ($2)); } +; + +item: + TEXT { $$ = std::move ($1); } +| NUMBER { $$ = make_ustring (to_string ($1)); } +; +%% + +namespace yy +{ + // The yylex function providing subsequent tokens: + // TEXT "I have three numbers for you." + // NUMBER 1 + // NUMBER 2 + // NUMBER 3 + // TEXT "And that's all!" + // END_OF_FILE + + static + parser::symbol_type + yylex () + { + static auto count = 0u; + auto stage = count; + ++count; + auto loc = parser::location_type{nullptr, stage + 1, stage + 1}; + switch (stage) + { + case 0: + return parser::make_TEXT (make_ustring ("I have three numbers for you."), std::move (loc)); + case 1: + case 2: + case 3: + return parser::make_NUMBER (stage, std::move (loc)); + case 4: + return parser::make_TEXT (make_ustring ("And that's all!"), std::move (loc)); + default: + return parser::make_END_OF_FILE (std::move (loc)); + } + } + + // Mandatory error function + void + parser::error (const parser::location_type& loc, const std::string& msg) + { + std::cerr << loc << ": " << msg << '\n'; + } +} + +int +main () +{ + auto&& p = yy::parser{}; + p.set_debug_level (!!getenv ("YYDEBUG")); + return p.parse (); +} + +// Local Variables: +// mode: C++ +// End: diff --git a/tests/atlocal.in b/tests/atlocal.in index a0a91687..c26ed0b5 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -54,6 +54,9 @@ BISON_CXX_WORKS='@BISON_CXX_WORKS@' # Compiler flags to disable exception support. NO_EXCEPTIONS_CXXFLAGS='@NO_EXCEPTIONS_CXXFLAGS@' +# Requiring a specific C++ standard. +CXX11_CXXFLAGS='@CXX11_CXXFLAGS@' + # Be sure that the C++ compiler is not broken because of gnulib. This # cannot be checked in configure (gnulib is not parameterized yet), # and checking this in every C++ test in AC_COMPILE_CXX is too costly. diff --git a/tests/c++.at b/tests/c++.at index 5941c0ed..1b80063b 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -151,8 +151,12 @@ int main() // stack_symbol_type: construction, accessor. { +#if defined __cplusplus && 201103L <= __cplusplus + auto ss = parser::stack_symbol_type(1, parser::make_INT(123)); +#else parser::symbol_type s = parser::make_INT(123); parser::stack_symbol_type ss(1, s); +#endif std::cerr << ss.value.as<int>() << '\n'; } @@ -161,8 +165,12 @@ int main() parser::stack_type st; for (int i = 0; i < 100; ++i) { +#if defined __cplusplus && 201103L <= __cplusplus + auto ss = parser::stack_symbol_type(1, parser::make_INT(123)); +#else parser::symbol_type s = parser::make_INT(123); parser::stack_symbol_type ss(1, s); +#endif st.push(ss); } } diff --git a/tests/headers.at b/tests/headers.at index 541610db..e6e747b0 100644 --- a/tests/headers.at +++ b/tests/headers.at @@ -311,15 +311,20 @@ AT_TEST([x8], [%define api.pure %define api.push-pull both]) AT_CHECK([[$PERL -n -0777 -e ' s{/\*.*?\*/}{}gs; s{//.*}{}g; - s{\b(YYChar + s{\b((defined|if)\ YYDEBUG + |YYChar |YYPUSH_MORE(?:_DEFINED)? |YYUSE |YY_ATTRIBUTE(?:_PURE|_UNUSED)? + |YY_COPY |YY_IGNORE_MAYBE_UNINITIALIZED_(?:BEGIN|END) |YY_INITIAL_VALUE - |YY_\w+_INCLUDED + |YY_MOVE + |YY_MOVE_OR_COPY + |YY_MOVE_REF |YY_NULLPTR - |(defined|if)\ YYDEBUG + |YY_RVREF + |YY_\w+_INCLUDED )\b}{}gx; while (/^(.*YY.*)$/gm) {
