bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: RFC: lalr1.cc: support move semantics


From: Akim Demaille
Subject: Re: RFC: lalr1.cc: support move semantics
Date: Wed, 12 Sep 2018 07:06:11 +0200

Here is my updated proposal.

commit 4ba0a5eac0953e308128af23324103f9589dc37e
Author: Akim Demaille <address@hidden>
Date:   Sun Aug 12 18:05:47 2018 +0200

    lalr1.cc: support move semantics
    
    Modern C++ (i.e., C++11 and later) introduced "move only" types: types such
    as std::unique_ptr<T> that can never be duplicated.  They must never be
    copied (by assignments and constructors), they must be "moved".  The
    implementation of lalr1.cc used to copy symbols (including their semantic
    values).  This commit ensures that values are only moved in modern C++, yet
    remain compatible with C++98/C++03.
    
    Suggested by Frank Heckenbach, who provided a full implementation on
    top of C++17's std::variant.
    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.
    
    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++ the callers must use std::move, and the
    callees must take their arguments as rvalue refs (foo&&).  In order to
    avoid duplicating these functions to support both legacy C++ and
    modern C++, 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 value.
    
    See:
    https://lists.gnu.org/archive/html/bison-patches/2018-09/msg00024.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 3e730a07..34e94b3b 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 f9165056..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,7 +341,7 @@ 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
@@ -345,7 +349,7 @@ b4_location_define])])[
     /// \param s    the state
     /// \param sym  the symbol (for its value and location).
     /// \warning the contents of \a sym.value is stolen.
-    void yypush_ (const char* m, state_type s, symbol_type& sym);
+    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 6df8ace7..9effb9d6 100644
--- a/examples/local.mk
+++ b/examples/local.mk
@@ -46,14 +46,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..c78bab07
--- /dev/null
+++ b/examples/variant-11.yy
@@ -0,0 +1,159 @@
+/*
+  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 string_uptr = std::unique_ptr<std::string>;
+  using string_uptrs = std::vector<string_uptr>;
+}
+
+%code // *.cc
+{
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+
+  namespace yy
+  {
+    // Prototype of the yylex function providing subsequent tokens.
+    static parser::symbol_type yylex ();
+
+    // Print a vector of strings.
+    std::ostream&
+    operator<< (std::ostream& o, const string_uptrs& ss)
+    {
+      o << '{';
+      const char *sep = "";
+      for (const auto& s: ss)
+        {
+          o << sep << *s;
+          sep = ", ";
+        }
+      return o << '}';
+    }
+  }
+
+  template <typename... Args>
+  string_uptr
+  make_string_uptr (Args&&... args)
+  {
+    // std::make_unique is C++14.
+    return std::unique_ptr<std::string>(new 
std::string{std::forward<Args>(args)...});
+  }
+
+  // Convert to string.
+  template <typename T>
+    std::string
+    to_string (const T& t)
+  {
+    auto&& o = std::ostringstream{};
+    o << t;
+    return o.str ();
+  }
+}
+
+%token <string_uptr> TEXT;
+%token <int> NUMBER;
+%printer { yyo << '(' << &$$ << ") " << $$; } <*>;
+%printer { yyo << *$$; } <string_uptr>;
+%token END_OF_FILE 0;
+
+%type <string_uptr> item;
+%type <string_uptrs> 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_string_uptr (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_string_uptr ("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_string_uptr ("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/examples/variant.yy b/examples/variant.yy
index ff3b9506..0a2ec687 100644
--- a/examples/variant.yy
+++ b/examples/variant.yy
@@ -37,16 +37,12 @@ typedef std::vector<std::string> strings_type;
 #include <iterator>
 #include <sstream>
 
-  // Prototype of the yylex function providing subsequent tokens.
   namespace yy
   {
+    // Prototype of the yylex function providing subsequent tokens.
     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
-  {
+    // Print a vector of strings.
     std::ostream&
     operator<< (std::ostream& o, const strings_type& ss)
     {
@@ -62,10 +58,10 @@ typedef std::vector<std::string> strings_type;
     }
   }
 
-  // Conversion to string.
+  // Convert to string.
   template <typename T>
     std::string
-    string_cast (const T& t)
+    to_string (const T& t)
   {
     std::ostringstream o;
     o << t;
@@ -94,7 +90,7 @@ list:
 
 item:
   TEXT    { std::swap ($$, $1); }
-| NUMBER  { $$ = string_cast ($1); }
+| NUMBER  { $$ = to_string ($1); }
 ;
 %%
 
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)
   {




reply via email to

[Prev in Thread] Current Thread [Next in Thread]