C++: support variadic emplace

Suggested by Askar Safin.
http://lists.gnu.org/archive/html/bug-bison/2018-12/msg00006.html

* data/variant.hh: Implement.
* tests/types.at: Check.
* doc/bison.texi: Document.
This commit is contained in:
Akim Demaille
2018-12-10 17:41:24 +01:00
parent d657da9fb4
commit 81dbd0d82e
4 changed files with 42 additions and 28 deletions

16
NEWS
View File

@@ -100,6 +100,22 @@ GNU Bison NEWS
until it sees the '='. So we notate the two possible reductions to until it sees the '='. So we notate the two possible reductions to
indicate that each conflicts in one rule. indicate that each conflicts in one rule.
*** C++: Variadic emplace
If your application requires C++11, you may now use a variadic emplace for
semantic values:
%define api.value.type variant
%token <std::pair<int, int>> PAIR
in your scanner:
int yylex (parser::semantic_type *lvalp)
{
lvalp->emplace <std::pair<int, int>> (1, 2);
return parser::token::PAIR;
}
*** More POSIX Yacc compatibility warnings *** More POSIX Yacc compatibility warnings
More Bison specific directives are now reported with -y or -Wyacc. This More Bison specific directives are now reported with -y or -Wyacc. This

View File

@@ -121,6 +121,18 @@ m4_define([b4_value_type_declare],
YYASSERT (!yytypeid_); YYASSERT (!yytypeid_);
])[} ])[}
# if 201103L <= YY_CPLUSPLUS
/// Instantiate a \a T in here from \a t.
template <typename T, typename... U>
T&
emplace (U&&... u)
{]b4_parse_assert_if([
YYASSERT (!yytypeid_);
YYASSERT (sizeof (T) <= size);
yytypeid_ = & typeid (T);])[
return *new (yyas_<T> ()) T (std::forward <U>(u)...);
}
# else
/// Instantiate an empty \a T in here. /// Instantiate an empty \a T in here.
template <typename T> template <typename T>
T& T&
@@ -132,18 +144,6 @@ m4_define([b4_value_type_declare],
return *new (yyas_<T> ()) T (); return *new (yyas_<T> ()) T ();
} }
# if 201103L <= YY_CPLUSPLUS
/// Instantiate a \a T in here from \a t.
template <typename T, typename U>
T&
emplace (U&& u)
{]b4_parse_assert_if([
YYASSERT (!yytypeid_);
YYASSERT (sizeof (T) <= size);
yytypeid_ = & typeid (T);])[
return *new (yyas_<T> ()) T (std::forward <U>(u));
}
# else
/// Instantiate a \a T in here from \a t. /// Instantiate a \a T in here from \a t.
template <typename T> template <typename T>
T& T&

View File

@@ -11088,20 +11088,17 @@ in midrule actions. It is mandatory to use typed midrule actions
(@pxref{Typed Midrule Actions}). (@pxref{Typed Midrule Actions}).
@deftypemethod {semantic_type} {T&} emplace<T> () @deftypemethod {semantic_type} {T&} emplace<T> ()
Initialize, but leave empty. Return a reference to where the actual value @deftypemethodx {semantic_type} {T&} emplace<T> (const T& @var{t})
may be stored. Requires that the variant was not initialized yet. Available in C++98/C++03 only. Default construct/copy-construct from
@var{t}. Return a reference to where the actual value may be stored.
Requires that the variant was not initialized yet.
@end deftypemethod @end deftypemethod
@deftypemethod {semantic_type} {T&} emplace<T> (const T& @var{t}) @deftypemethod {semantic_type} {T&} emplace<T, U> (U&&... @var{u})
Initialize, and copy-construct from @var{t}. Available in C++98/C++03 only. Available in C++11 and later only. Build a variant of type @code{T} from
the variadic forwarding references @var{u...}.
@end deftypemethod @end deftypemethod
@deftypemethod {semantic_type} {T&} emplace<T, U> (U&& @var{u})
Build a variant of type @code{T} from the forwarding reference @var{u}.
Available in C++11 and later only.
@end deftypemethod
@strong{Warning}: We do not use Boost.Variant, for two reasons. First, it @strong{Warning}: We do not use Boost.Variant, for two reasons. First, it
appeared unacceptable to require Boost on the user's machine (i.e., the appeared unacceptable to require Boost on the user's machine (i.e., the
machine on which the generated parser will be compiled, not the machine on machine on which the generated parser will be compiled, not the machine on

View File

@@ -288,21 +288,22 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]],
AT_VAL.build (std::make_pair<std::string, std::string> ("two", "deux"));], AT_VAL.build (std::make_pair<std::string, std::string> ("two", "deux"));],
[10:11, two:deux]) [10:11, two:deux])
# Move-only types. # Move-only types, and variadic emplace.
AT_TEST([%skeleton "]b4_skel[" AT_TEST([%skeleton "]b4_skel["
%code requires { #include <memory> } %code requires { #include <memory> }
%define api.value.type variant], %define api.value.type variant],
[[%token <std::unique_ptr<int>> '1'; [[%token <std::unique_ptr<int>> '1';
%token <std::unique_ptr<std::string>> '2';]], %token <std::pair<int, int>> '2';]],
['1' '2' { std::cout << *$1 << ", " << *$2 << '\n'; }], ['1' '2' { std::cout << *$1 << ", "
<< $2.first << ", "
<< $2.second << '\n'; }],
["12"], ["12"],
[[if (res == '1') [[if (res == '1')
]AT_VAL[.emplace <std::unique_ptr<int>> ]AT_VAL[.emplace <std::unique_ptr<int>>
(std::make_unique <int> (10)); (std::make_unique <int> (10));
else if (res == '2') else if (res == '2')
]AT_VAL[.emplace <std::unique_ptr<std::string>> ]AT_VAL[.emplace <std::pair<int, int>> (21, 22);]],
(std::make_unique <std::string> ("two"));]], [10, 21, 22],
[10, two],
[AT_REQUIRE_CXX_STD(14, [echo "$at_std not supported"; continue])])]) [AT_REQUIRE_CXX_STD(14, [echo "$at_std not supported"; continue])])])
]) ])
]) ])