From 1f4dd2671a4dee1525b2681f4dbcb0cb3c34793e Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 18 Dec 2018 07:16:55 +0100 Subject: [PATCH] c++: provide symbol constructors per type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On %token FOO BAR we currently generate make_FOO(int) and make_BAR(int). However, in order to factor their scanners, some users would also like to have make_symbol(tok, int), where tok is FOO or BAR. To ensure type safety, add assertions that do check that value type and token type match. Bind this assertion to the parse.assert %define variable. Suggested by Frank Heckenbach. http://lists.gnu.org/archive/html/bug-bison/2018-12/msg00034.html Should also match expectations from Аскар Сафин. http://lists.gnu.org/archive/html/bug-bison/2018-12/msg00023.html * data/variant.hh: Use b4_token_visible_if where applicable. (_b4_type_constructor_declare, _b4_type_constructor_define): New. Use them. --- data/variant.hh | 85 +++++++++++++++++++++++++++++++++++++++++++++++-- tests/types.at | 19 +++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/data/variant.hh b/data/variant.hh index 836616a6..22832248 100644 --- a/data/variant.hh +++ b/data/variant.hh @@ -335,6 +335,16 @@ m4_define([b4_symbol_value_template], ## ------------- ## +# _b4_includes_tokens(SYMBOL-NUM...) +# ---------------------------------- +# Expands to non-empty iff one of the SYMBOL-NUM denotes +# a token. +m4_define([_b4_is_token], + [b4_symbol_if([$1], [is_token], [1])]) +m4_define([_b4_includes_tokens], + [m4_map([_b4_is_token], [$@])]) + + # _b4_token_maker_declare(SYMBOL-NUM) # ----------------------------------- # Declare make_SYMBOL for SYMBOL-NUM. Use at class-level. @@ -358,12 +368,38 @@ m4_define([_b4_token_maker_declare], ])]) +# _b4_type_constructor_declare(SYMBOL-NUM...) +# ------------------------------------------- +# Declare a unique make_symbol for all the SYMBOL-NUM (they +# have the same type). Use at class-level. +m4_define([_b4_type_constructor_declare], +[m4_ifval(_b4_includes_tokens($@), +[#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_symbol (dnl +b4_join([int tok], + b4_symbol_if([$1], [has_type], + [b4_symbol([$1], [type]) v]), + b4_locations_if([location_type l]))); +#else + static + symbol_type + make_symbol (dnl +b4_join([int tok], + b4_symbol_if([$1], [has_type], + [const b4_symbol([$1], [type])& v]), + b4_locations_if([const location_type& l]))); +#endif +])]) + + # b4_symbol_constructor_declare # ----------------------------- -# Declare symbol constructors for all the value types. -# Use at class-level. +# Declare symbol constructors. Use at class-level. m4_define([b4_symbol_constructor_declare], [ // Symbol constructors declarations. +b4_type_foreach([_b4_type_constructor_declare]) b4_symbol_foreach([_b4_token_maker_declare])]) @@ -401,6 +437,50 @@ m4_define([_b4_token_maker_define], ])]) +# _b4_type_constructor_define(SYMBOL-NUM...) +# ------------------------------------------ +# Declare a unique make_symbol for all the SYMBOL-NUM (they +# have the same type). Use at class-level. +m4_define([_b4_type_clause], +[b4_symbol_if([$1], [is_token], + [b4_symbol_if([$1], [has_id], + [tok == token::b4_symbol([$1], [id])], + [tok == b4_symbol([$1], [user_number])])])]) + +m4_define([_b4_type_constructor_define], +[m4_ifval(_b4_includes_tokens($@), +[#if 201103L <= YY_CPLUSPLUS + inline + b4_parser_class_name::symbol_type + b4_parser_class_name::make_symbol (dnl +b4_join([int tok], + b4_symbol_if([$1], [has_type], + [b4_symbol([$1], [type]) v]), + b4_locations_if([location_type l]))) + {b4_parse_assert_if([ + assert (m4_join([ || ], m4_map_sep([_b4_type_clause], [, ], [$@])));])[ + return symbol_type (]b4_join([token_type (tok)], + b4_symbol_if([$1], [has_type], [std::move (v)]), + b4_locations_if([std::move (l)]))); + } +#else + inline + b4_parser_class_name::symbol_type + b4_parser_class_name::make_symbol (dnl +b4_join([int tok], + b4_symbol_if([$1], [has_type], + [const b4_symbol([$1], [type])& v]), + b4_locations_if([const location_type& l]))) + {b4_parse_assert_if([ + assert (m4_join([ || ], m4_map_sep([_b4_type_clause], [, ], [$@])));])[ + return symbol_type (]b4_join([token_type (tok)], + b4_symbol_if([$1], [has_type], [v]), + b4_locations_if([l]))); + } +#endif +])]) + + # b4_basic_symbol_constructor_declare(SYMBOL-NUM) # ----------------------------------------------- # Generate a constructor declaration for basic_symbol from given type. @@ -452,4 +532,5 @@ m4_define([b4_basic_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_type_foreach([_b4_type_constructor_define]) b4_symbol_foreach([_b4_token_maker_define])]) diff --git a/tests/types.at b/tests/types.at index 2924ec18..bead23d0 100644 --- a/tests/types.at +++ b/tests/types.at @@ -325,6 +325,25 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]], [10, 21:22], [AT_REQUIRE_CXX_STD(14, [echo "$at_std not supported"; continue])]) + # Type-based token constructors on move-only types, and types with commas. + AT_TEST([%skeleton "]b4_skel[" + %code requires { #include } + %define api.value.type variant + %define api.token.constructor], + [[%token > '1'; + %token > '2';]], + ['1' '2' { std::cout << *$1 << ", " + << $2.first << ':' << $2.second << '\n'; }], + ["12"], + [[if (res == '1') + return yy::parser::make_symbol ('1', std::make_unique (10)); + else if (res == '2') + return yy::parser::make_symbol ('2', std::make_pair (21, 22)); + else + return yy::parser::make_symbol (0)]], + [10, 21:22], + [AT_REQUIRE_CXX_STD(14, [echo "$at_std not supported"; continue])]) + ]) ])