summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorAkim Demaille <akim.demaille@gmail.com>2020-12-27 09:37:26 +0100
committerAkim Demaille <akim.demaille@gmail.com>2021-01-05 09:28:20 +0100
commite51e89856a5bb4462bf850048a355607dbe70cd5 (patch)
tree8bd56a24feb294cb9421481f7e877f6eb508f1e5 /examples
parentc2a06bf7915d53ed9aaf6efdd14af15c64cc2654 (diff)
downloadbison-e51e89856a5bb4462bf850048a355607dbe70cd5.tar.gz
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.
Diffstat (limited to 'examples')
-rw-r--r--examples/c++/glr/c++-types.yy17
1 files changed, 9 insertions, 8 deletions
diff --git a/examples/c++/glr/c++-types.yy b/examples/c++/glr/c++-types.yy
index 8399b4f9..9b649f52 100644
--- a/examples/c++/glr/c++-types.yy
+++ b/examples/c++/glr/c++-types.yy
@@ -34,7 +34,7 @@
#include "ast.hh"
}
-%define api.value.type {Node}
+%define api.value.type variant
%code
{
@@ -47,8 +47,8 @@
# define nullptr 0
#endif
- static yy::parser::value_type
- stmtMerge (const yy::parser::value_type& x0, const yy::parser::value_type& x1);
+ static Node
+ stmtMerge (const Node& x0, const Node& x1);
static int
yylex (yy::parser::value_type* val, yy::parser::location_type* loc);
@@ -56,12 +56,13 @@
%expect-rr 1
+%type <Node> TYPENAME ID stmt expr decl declarator
+%printer { yyo << $$; } <Node>
+
%token
TYPENAME "typename"
ID "identifier"
-%printer { yyo << $$; } TYPENAME ID stmt expr decl declarator
-
%right '='
%left '+'
@@ -148,7 +149,7 @@ yylex (yy::parser::value_type* lvalp, yy::parser::location_type* llocp)
= isupper (static_cast <unsigned char> (form[0]))
? yy::parser::token::TYPENAME
: yy::parser::token::ID;
- *lvalp = Term (form);
+ lvalp->emplace<Node> (Term (form));
}
else
{
@@ -163,8 +164,8 @@ yylex (yy::parser::value_type* lvalp, yy::parser::location_type* llocp)
}
}
-static yy::parser::value_type
-stmtMerge (const yy::parser::value_type& x0, const yy::parser::value_type& x1)
+static Node
+stmtMerge (const Node& x0, const Node& x1)
{
return Nterm ("<OR>", x0, x1);
}