mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 20:33:03 +00:00
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++ (C++11 and later) 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. Functions 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.yy: Don't define things in std. * examples/variant-11.test, examples/variant-11.yy: New. Check the support of move-only types. * examples/README, examples/local.mk: Adjust.
156 lines
3.1 KiB
C++
156 lines
3.1 KiB
C++
# C++ skeleton for Bison
|
|
|
|
# Copyright (C) 2002-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/>.
|
|
|
|
m4_pushdef([b4_copyright_years],
|
|
[2002-2015, 2018])
|
|
|
|
# b4_stack_define
|
|
# ---------------
|
|
m4_define([b4_stack_define],
|
|
[[ /// A stack with random access from its top.
|
|
template <class T, class S = std::vector<T> >
|
|
class stack
|
|
{
|
|
public:
|
|
// Hide our reversed order.
|
|
typedef typename S::reverse_iterator iterator;
|
|
typedef typename S::const_reverse_iterator const_iterator;
|
|
typedef typename S::size_type size_type;
|
|
|
|
stack ()
|
|
{
|
|
seq_.reserve (200);
|
|
}
|
|
|
|
stack (size_type n)
|
|
: seq_ (n)
|
|
{}
|
|
|
|
/// Random access.
|
|
///
|
|
/// Index 0 returns the topmost element.
|
|
T&
|
|
operator[] (size_type i)
|
|
{
|
|
return seq_[seq_.size () - 1 - i];
|
|
}
|
|
|
|
/// Random access.
|
|
///
|
|
/// Index 0 returns the topmost element.
|
|
const T&
|
|
operator[] (size_type i) const
|
|
{
|
|
return seq_[seq_.size () - 1 - i];
|
|
}
|
|
|
|
/// Steal the contents of \a t.
|
|
///
|
|
/// Close to move-semantics.
|
|
void
|
|
push (YY_MOVE_REF (T) t)
|
|
{
|
|
seq_.push_back (T());
|
|
operator[](0).move (t);
|
|
}
|
|
|
|
void
|
|
pop (size_type n = 1)
|
|
{
|
|
for (; n; --n)
|
|
seq_.pop_back ();
|
|
}
|
|
|
|
void
|
|
clear ()
|
|
{
|
|
seq_.clear ();
|
|
}
|
|
|
|
size_type
|
|
size () const
|
|
{
|
|
return seq_.size ();
|
|
}
|
|
|
|
const_iterator
|
|
begin () const
|
|
{
|
|
return seq_.rbegin ();
|
|
}
|
|
|
|
const_iterator
|
|
end () const
|
|
{
|
|
return seq_.rend ();
|
|
}
|
|
|
|
private:
|
|
stack (const stack&);
|
|
stack& operator= (const stack&);
|
|
/// The wrapped container.
|
|
S seq_;
|
|
};
|
|
|
|
/// Present a slice of the top of a stack.
|
|
template <class T, class S = stack<T> >
|
|
class slice
|
|
{
|
|
public:
|
|
typedef typename S::size_type size_type;
|
|
slice (const S& stack, size_type range)
|
|
: stack_ (stack)
|
|
, range_ (range)
|
|
{}
|
|
|
|
const T&
|
|
operator[] (size_type i) const
|
|
{
|
|
return stack_[range_ - i];
|
|
}
|
|
|
|
private:
|
|
const S& stack_;
|
|
size_type range_;
|
|
};
|
|
]])
|
|
|
|
b4_defines_if(
|
|
[b4_output_begin([b4_dir_prefix[]stack.hh])
|
|
b4_copyright([Stack handling for Bison parsers in C++])[
|
|
|
|
/**
|
|
** \file ]b4_dir_prefix[stack.hh
|
|
** Define the ]b4_namespace_ref[::stack class.
|
|
*/
|
|
|
|
]b4_cpp_guard_open([b4_dir_prefix[]stack.hh])[
|
|
|
|
# include <vector>
|
|
|
|
]b4_cxx_portability[
|
|
|
|
]b4_namespace_open[
|
|
]b4_stack_define[
|
|
]b4_namespace_close[
|
|
|
|
]b4_cpp_guard_close([b4_dir_prefix[]stack.hh])
|
|
b4_output_end()
|
|
])
|
|
|
|
m4_popdef([b4_copyright_years])
|