mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +00:00
This is based on what is recommended by both Scott Meyers, in 'Effective
C++', and Andrei Alexandrescu and Herb Sutter in 'C++ Coding Standards'.
Use a static_cast on void* rather than directly use a reinterpret_cast,
which can have nefarious effects on objects. However, even though following
this guideline is good practice in general, I am not quite sure how relevant
it is when applied to conversions from POD to objects. Actually, it might
very well be the opposite: isn't this exactly what reinterpret_cast is for?
What we really want *is* to transmit the memory map as a series of bytes,
which, if I am correct, falls into the kind of "low level" hack for which
this cast is meant.
In any case, this silences the warning, which will be greatly appreciated by
anyone using variants with a compiler supporting -fstrict-aliasing.
* data/variant.hh (as): Here.
* tests/c++.at (Exception safety, C++ Variant-based Symbols, Variants):
Don't use NO_STRICT_ALIAS_CXXFLAGS (revert commit ddb9db15), as type punning
is no longer an issue.
* tests/atlocal.in, configure.ac (NO_STRICT_ALIAS_CXXFLAGS): Remove
definition.
* examples/local.mk (NO_STRICT_ALIAS_CXXFLAGS): Remove from AM_CXXFLAGS.
* doc/bison.texi: Don't mention type punning issues.
352 lines
9.5 KiB
C++
352 lines
9.5 KiB
C++
# C++ skeleton for Bison
|
|
|
|
# Copyright (C) 2002-2013 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/>.
|
|
|
|
|
|
## --------- ##
|
|
## variant. ##
|
|
## --------- ##
|
|
|
|
# b4_symbol_variant(YYTYPE, YYVAL, ACTION, [ARGS])
|
|
# ------------------------------------------------
|
|
# Run some ACTION ("build", or "destroy") on YYVAL of symbol type
|
|
# YYTYPE.
|
|
m4_define([b4_symbol_variant],
|
|
[m4_pushdef([b4_dollar_dollar],
|
|
[$2.$3< $][3 >(m4_shift3($@))])dnl
|
|
switch ($1)
|
|
{
|
|
b4_type_foreach([b4_type_action_])[]dnl
|
|
default:
|
|
break;
|
|
}
|
|
m4_popdef([b4_dollar_dollar])dnl
|
|
])
|
|
|
|
|
|
# _b4_char_sizeof_counter
|
|
# -----------------------
|
|
# A counter used by _b4_char_sizeof_dummy to create fresh symbols.
|
|
m4_define([_b4_char_sizeof_counter],
|
|
[0])
|
|
|
|
# _b4_char_sizeof_dummy
|
|
# ---------------------
|
|
# At each call return a new C++ identifier.
|
|
m4_define([_b4_char_sizeof_dummy],
|
|
[m4_define([_b4_char_sizeof_counter], m4_incr(_b4_char_sizeof_counter))dnl
|
|
dummy[]_b4_char_sizeof_counter])
|
|
|
|
|
|
# b4_char_sizeof(SYMBOL-NUMS)
|
|
# ---------------------------
|
|
# To be mapped on the list of type names to produce:
|
|
#
|
|
# char dummy1[sizeof(type_name_1)];
|
|
# char dummy2[sizeof(type_name_2)];
|
|
#
|
|
# for defined type names.
|
|
m4_define([b4_char_sizeof],
|
|
[b4_symbol_if([$1], [has_type],
|
|
[
|
|
m4_map([ b4_symbol_tag_comment], [$@])dnl
|
|
char _b4_char_sizeof_dummy@{sizeof([b4_symbol([$1], [type])])@};
|
|
])])
|
|
|
|
|
|
# b4_variant_includes
|
|
# -------------------
|
|
# The needed includes for variants support.
|
|
m4_define([b4_variant_includes],
|
|
[b4_parse_assert_if([[#include <typeinfo>]])[
|
|
#ifndef YYASSERT
|
|
# include <cassert>
|
|
# define YYASSERT assert
|
|
#endif
|
|
]])
|
|
|
|
# b4_variant_define
|
|
# -----------------
|
|
# Define "variant".
|
|
m4_define([b4_variant_define],
|
|
[[ /// A char[S] buffer to store and retrieve objects.
|
|
///
|
|
/// Sort of a variant, but does not keep track of the nature
|
|
/// of the stored data, since that knowledge is available
|
|
/// via the current state.
|
|
template <size_t S>
|
|
struct variant
|
|
{
|
|
/// Type of *this.
|
|
typedef variant<S> self_type;
|
|
|
|
/// Empty construction.
|
|
variant ()]b4_parse_assert_if([
|
|
: tname (YY_NULL)])[
|
|
{}
|
|
|
|
/// Construct and fill.
|
|
template <typename T>
|
|
variant (const T& t)]b4_parse_assert_if([
|
|
: tname (typeid (T).name ())])[
|
|
{
|
|
YYASSERT (sizeof (T) <= S);
|
|
new (buffer.raw) T (t);
|
|
}
|
|
|
|
/// Destruction, allowed only if empty.
|
|
~variant ()
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (!tname);
|
|
])[}
|
|
|
|
/// Instantiate an empty \a T in here.
|
|
template <typename T>
|
|
T&
|
|
build ()
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (!tname);
|
|
YYASSERT (sizeof (T) <= S);
|
|
tname = typeid (T).name ();])[
|
|
return *new (buffer.raw) T;
|
|
}
|
|
|
|
/// Instantiate a \a T in here from \a t.
|
|
template <typename T>
|
|
T&
|
|
build (const T& t)
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (!tname);
|
|
YYASSERT (sizeof (T) <= S);
|
|
tname = typeid (T).name ();])[
|
|
return *new (buffer.raw) T (t);
|
|
}
|
|
|
|
/// Accessor to a built \a T.
|
|
template <typename T>
|
|
T&
|
|
as ()
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (tname == typeid (T).name ());
|
|
YYASSERT (sizeof (T) <= S);])[
|
|
{
|
|
void *dummy = buffer.raw;
|
|
return *static_cast<T*> (dummy);
|
|
}
|
|
}
|
|
|
|
/// Const accessor to a built \a T (for %printer).
|
|
template <typename T>
|
|
const T&
|
|
as () const
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (tname == typeid (T).name ());
|
|
YYASSERT (sizeof (T) <= S);])[
|
|
{
|
|
const void *dummy = buffer.raw;
|
|
return *static_cast<const T*> (dummy);
|
|
}
|
|
}
|
|
|
|
/// Swap the content with \a other, of same type.
|
|
///
|
|
/// Both variants must be built beforehand, because swapping the actual
|
|
/// data requires reading it (with as()), and this is not possible on
|
|
/// unconstructed variants: it would require some dynamic testing, which
|
|
/// should not be the variant's responsability.
|
|
/// Swapping between built and (possibly) non-built is done with
|
|
/// variant::move ().
|
|
template <typename T>
|
|
void
|
|
swap (self_type& other)
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (tname);
|
|
YYASSERT (tname == other.tname);])[
|
|
std::swap (as<T>(), other.as<T>());
|
|
}
|
|
|
|
/// Move the content of \a other to this.
|
|
///
|
|
/// Destroys \a other.
|
|
template <typename T>
|
|
void
|
|
move (self_type& other)
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (!tname);])[
|
|
build<T>();
|
|
swap<T>(other);
|
|
other.destroy<T>();
|
|
}
|
|
|
|
/// Copy the content of \a other to this.
|
|
template <typename T>
|
|
void
|
|
copy (const self_type& other)
|
|
{
|
|
build<T> (other.as<T> ());
|
|
}
|
|
|
|
/// Destroy the stored \a T.
|
|
template <typename T>
|
|
void
|
|
destroy ()
|
|
{
|
|
as<T> ().~T ();]b4_parse_assert_if([
|
|
tname = YY_NULL;])[
|
|
}
|
|
|
|
private:
|
|
/// Prohibit blind copies.
|
|
self_type& operator=(const self_type&);
|
|
variant (const self_type&);
|
|
|
|
/// A buffer large enough to store any of the semantic values.
|
|
/// Long double is chosen as it has the strongest alignment
|
|
/// constraints.
|
|
union
|
|
{
|
|
long double align_me;
|
|
char raw[S];
|
|
} buffer;]b4_parse_assert_if([
|
|
|
|
/// Whether the content is built: if defined, the name of the stored type.
|
|
const char* tname;])[
|
|
};
|
|
]])
|
|
|
|
|
|
## -------------------------- ##
|
|
## Adjustments for variants. ##
|
|
## -------------------------- ##
|
|
|
|
|
|
# b4_semantic_type_declare
|
|
# ------------------------
|
|
# Declare semantic_type.
|
|
m4_define([b4_semantic_type_declare],
|
|
[ /// An auxiliary type to compute the largest semantic type.
|
|
union union_type
|
|
{]b4_type_foreach([b4_char_sizeof])[};
|
|
|
|
/// Symbol semantic values.
|
|
typedef variant<sizeof(union_type)> semantic_type;dnl
|
|
])
|
|
|
|
|
|
# How the semantic value is extracted when using variants.
|
|
|
|
# b4_symbol_value(VAL, [TYPE])
|
|
# ----------------------------
|
|
m4_define([b4_symbol_value],
|
|
[m4_ifval([$2],
|
|
[$1.as< $2 >()],
|
|
[$1])])
|
|
|
|
# b4_symbol_value_template(VAL, [TYPE])
|
|
# -------------------------------------
|
|
# Same as b4_symbol_value, but used in a template method.
|
|
m4_define([b4_symbol_value_template],
|
|
[m4_ifval([$2],
|
|
[$1.template as< $2 >()],
|
|
[$1])])
|
|
|
|
|
|
|
|
## ------------- ##
|
|
## make_SYMBOL. ##
|
|
## ------------- ##
|
|
|
|
|
|
# b4_symbol_constructor_declare_(SYMBOL-NUMBER)
|
|
# ---------------------------------------------
|
|
# Declare the overloaded version of make_symbol for the (common) type of
|
|
# these SYMBOL-NUMBERS. Use at class-level.
|
|
m4_define([b4_symbol_constructor_declare_],
|
|
[b4_symbol_if([$1], [is_token], [b4_symbol_if([$1], [has_id],
|
|
[ static inline
|
|
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])));
|
|
|
|
])])])
|
|
|
|
|
|
# b4_symbol_constructor_declare
|
|
# -----------------------------
|
|
# Declare symbol constructors for all the value types.
|
|
# Use at class-level.
|
|
m4_define([b4_symbol_constructor_declare],
|
|
[ // Symbol constructors declarations.
|
|
b4_symbol_foreach([b4_symbol_constructor_declare_])])
|
|
|
|
|
|
|
|
# b4_symbol_constructor_define_(SYMBOL-NUMBER)
|
|
# --------------------------------------------
|
|
# Define symbol constructor for this SYMBOL-NUMBER.
|
|
m4_define([b4_symbol_constructor_define_],
|
|
[b4_symbol_if([$1], [is_token], [b4_symbol_if([$1], [has_id],
|
|
[ 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])))
|
|
{
|
|
return symbol_type (b4_join([token::b4_symbol([$1], [id])],
|
|
b4_symbol_if([$1], [has_type], [v]),
|
|
b4_locations_if([l])));
|
|
|
|
}
|
|
|
|
])])])
|
|
|
|
|
|
# b4_basic_symbol_constructor_declare
|
|
# ----------------------------------
|
|
# Generate a constructor declaration for basic_symbol from given 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_basic_symbol_constructor_define
|
|
# ----------------------------------
|
|
# Generate a constructor implementation for basic_symbol from given type.
|
|
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]))[)
|
|
: Base (t)
|
|
, value (]b4_symbol_if([$1], [has_type], [v])[)]b4_locations_if([
|
|
, location (l)])[
|
|
{}
|
|
]])
|
|
|
|
# b4_symbol_constructor_define
|
|
# ----------------------------
|
|
# Define the overloaded versions of make_symbol for all the value types.
|
|
m4_define([b4_symbol_constructor_define],
|
|
[ // Implementation of make_symbol for each symbol type.
|
|
b4_symbol_foreach([b4_symbol_constructor_define_])])
|