Files
bison/examples/c++
Akim Demaille e51e89856a glr2.cc: add support for variants
(Bison) Variants are extremely picky, which makes them both
annoying (lots of micro-details must be taken care of) and
precious (all the micro-details must be taken care of, in particular
object lifetime).

So (i) each time a semantic value is stored, it must be stored in a
place that exists, and (ii) each time a semantic value is discarded,
its place must have been emptied.

Example of (i)

    - new (&yys.value ()) value_type (s->value ());
    + {]b4_variant_if([[
    +   new (&yys.value ()) value_type ();
    +   ]b4_symbol_variant([yy_accessing_symbol (s->yylrState)],
    +                      [yys.value ()], [copy], [s->value ()])], [[
    +   new (&yys.value ()) value_type (s->value ());]])[
    + }

Example of (ii)

      yyparser.yy_destroy_ ("Error: discarding",
    -                       yytoken, &yylval]b4_locations_if([, &yylloc])[);
    +                       yytoken, &yylval]b4_locations_if([, &yylloc])[);]b4_variant_if([[
    + // Value type destructor.
    + ]b4_symbol_variant([[YYTRANSLATE (this->yychar)]], [[yylval]], [[template destroy]])])[
      this->yychar = ]b4_namespace_ref[::]b4_parser_class[::token::]b4_symbol(empty, id)[;

However, in some places we must not be "pure".  In particular:

    glr_stack_item (const glr_stack_item& other) YY_NOEXCEPT YY_NOTHROW
      : is_state_ (other.is_state_)
    {
      std::memcpy (raw_, other.raw_, union_size);
    }

still must use memcpy, because the constructor would change pred, and
it must not.  This constructor is used only when resizing the stack,
in which case pred (which is relative) must not be "adjusted".

The result works, but is messy.  Its verbosity comes from at least two
factors:

- we don't have support for complete symbols (binding kind, value and
  location), and we should at least try to have it.  That simplified
  lalr1.cc a lot.

- I have not tried to be smart and use 'move' when possible.  As a
  consequence many places have 'copy' and then 'destroy'.  That kind
  of clean up can be done once everything appears to be solid.

* data/skeletons/glr2.cc: Be more rigorous in object lifetime.
In particular, don't forget to discard the lookahead when we're done
with it.
Call variant routines where needed.
Deal with plenty of details.
(b4_call_merger): Add support for variants.
Use references in mergers, rather than pointers.

* examples/c++/glr/c++-types.yy: Exercise variants.
2021-01-05 09:28:20 +01:00
..
2020-09-26 18:33:48 +02:00
2021-01-05 09:28:20 +01:00
2019-09-22 07:48:10 +02:00
2020-05-10 11:51:17 +02:00
2020-01-05 10:26:35 +01:00
2020-01-05 10:26:35 +01:00

Examples in C++

This directory contains examples of Bison grammar files in C++.

You can run make to compile these examples. And make clean to tidy afterwards.

simple.yy - Simple example in C++14

A very simple example in C++, based on variants and symbol constructors. Variants allow to use any C++ type as semantic value type, and symbol constructors ensure consistency between declared token kind and effective semantic value.

Run as ./simple.

Extracted from the documentation: A Simple C++ Example.

variant.yy - Self-contained example in C++98

A variation of simple.yy, in C++98.

Run as ./variant.

variant-11.yy - Self-contained example in modern C++

Another variation of simple.yy, closely related to the previous one, but exhibiting support for C++11's move semantics.

Run as ./variant or ./variant NUMBER.

calc++ - A Complete C++ Example

A fully featured C++ version of the canonical example for parsers: a calculator. Also uses Flex for the scanner.

Don't look at this example first: it is fully featured and can serve as a starting point for a clean parser in C++. The previous examples are better introductory examples, and the C examples are also useful introductory examples.

Extracted from the documentation: A Complete C++ Example.