bison-patches
[Top][All Lists]
Advanced

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

RFC: lalr1.cc: support move semantics


From: Akim Demaille
Subject: RFC: lalr1.cc: support move semantics
Date: Sun, 9 Sep 2018 14:33:52 +0200

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 <address@hidden>
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)
   {




reply via email to

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