Previous: C++ Unions, Up: C++ Semantic Values [Contents][Index]
Bison provides a variant based implementation of semantic values for C++. This alleviates all the limitations reported in the previous section, and in particular, object types can be used without pointers.
To enable variant-based semantic values, set the %define
variable
api.value.type
to variant
(see %define Summary). Then
%union
is ignored; instead of using the name of the fields of the
%union
to “type” the symbols, use genuine types.
For instance, instead of:
%union { int ival; std::string* sval; } %token <ival> NUMBER; %token <sval> STRING;
write:
%token <int> NUMBER; %token <std::string> STRING;
STRING
is no longer a pointer, which should fairly simplify the user
actions in the grammar and in the scanner (in particular the memory
management).
Since C++ features destructors, and since it is customary to specialize
operator<<
to support uniform printing of values, variants also
typically simplify Bison printers and destructors.
Variants are stricter than unions. When based on unions, you may play any
dirty game with yylval
, say storing an int
, reading a
char*
, and then storing a double
in it. This is no longer
possible with variants: they must be initialized, then assigned to, and
eventually, destroyed. As a matter of fact, Bison variants forbid the use
of alternative types such as ‘$<int>2’ or ‘$<std::string>$’, even
in midrule actions. It is mandatory to use typed midrule actions
(see Typed Midrule Actions).
const T&
t) ¶Available in C++98/C++03 only. Default construct/copy-construct from t. Return a reference to where the actual value may be stored. Requires that the variant was not initialized yet.
U&&...
u) ¶Available in C++11 and later only. Build a variant of type T
from
the variadic forwarding references u....
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
machine on which the generated parser will be compiled, not the machine on
which bison
was run). Second, for each possible semantic value,
Boost.Variant not only stores the value, but also a tag specifying its
type. But the parser already “knows” the type of the semantic value, so
that would be duplicating the information.
We do not use C++17’s std::variant
either: we want to support all the
C++ standards, and of course std::variant
also stores a tag to record
the current type.
Therefore we developed light-weight variants whose type tag is external (so
they are really like unions
for C++ actually). There is a number of
limitations in (the current implementation of) variants:
double
is the most demanding
type on all platforms, alignments are enforced for double
whatever
types are actually used. This may waste space in some cases.
As far as we know, these limitations can be alleviated. All it takes is some time and/or some talented C++ hacker willing to contribute to Bison.
Previous: C++ Unions, Up: C++ Semantic Values [Contents][Index]