diff --git a/data/skeletons/d.m4 b/data/skeletons/d.m4 index e4e60c8c..d2fa6e29 100644 --- a/data/skeletons/d.m4 +++ b/data/skeletons/d.m4 @@ -275,7 +275,7 @@ m4_define([b4_declare_symbol_enum], ]]) -# b4-case(ID, CODE, [COMMENTS]) +# b4_case(ID, CODE, [COMMENTS]) # ----------------------------- m4_define([b4_case], [ case $1:m4_ifval([$3], [ b4_comment([$3])]) $2 @@ -302,6 +302,109 @@ m4_define([b4_location_type], b4_percent_define_ifdef([[location_type]],[b4_perc m4_define([b4_position_type], b4_percent_define_ifdef([[position_type]],[b4_percent_define_get([[position_type]])],[YYPosition])) +## ---------------- ## +## api.value.type. ## +## ---------------- ## + + +# ---------------------- # +# api.value.type=union. # +# ---------------------- # + +# b4_symbol_type_register(SYMBOL-NUM) +# ----------------------------------- +# Symbol SYMBOL-NUM has a type (for union) instead of a type-tag. +# Extend the definition of %union's body (b4_union_members) with a +# field of that type, and extend the symbol's "type" field to point to +# the field name, instead of the type name. +m4_define([b4_symbol_type_register], +[m4_define([b4_symbol($1, type_tag)], + [b4_symbol_if([$1], [has_id], + [b4_symbol([$1], [id])], + [yykind_[]b4_symbol([$1], [number])])])dnl +m4_append([b4_union_members], +m4_expand([m4_format([ %-40s %s], + m4_expand([b4_symbol([$1], [type]) b4_symbol([$1], [type_tag]);]), + [b4_symbol_tag_comment([$1])])])) +]) + + +# b4_type_define_tag(SYMBOL1-NUM, ...) +# ------------------------------------ +# For the batch of symbols SYMBOL1-NUM... (which all have the same +# type), enhance the %union definition for each of them, and set +# there "type" field to the field tag name, instead of the type name. +m4_define([b4_type_define_tag], +[b4_symbol_if([$1], [has_type], + [m4_map([b4_symbol_type_register], [$@])]) +]) + + +# b4_symbol_value_union(VAL, SYMBOL-NUM, [TYPE]) +# ---------------------------------------------- +# Same of b4_symbol_value, but when api.value.type=union. +m4_define([b4_symbol_value_union], +[m4_ifval([$3], + [(*($3*)(&$1))], + [m4_ifval([$2], + [b4_symbol_if([$2], [has_type], + [($1.b4_symbol([$2], [type_tag]))], + [$1])], + [$1])])]) + + +# b4_value_type_setup_union +# ------------------------- +# Setup support for api.value.type=union. Symbols are defined with a +# type instead of a union member name: build the corresponding union, +# and give the symbols their tag. +m4_define([b4_value_type_setup_union], +[m4_define([b4_union_members]) +b4_type_foreach([b4_type_define_tag]) +m4_copy_force([b4_symbol_value_union], [b4_symbol_value]) +]) + + +# _b4_value_type_setup_keyword +# ---------------------------- +# api.value.type is defined with a keyword/string syntax. Check if +# that is properly defined, and prepare its use. +m4_define([_b4_value_type_setup_keyword], +[b4_percent_define_check_values([[[[api.value.type]], + [[none]], + [[union]], + [[union-directive]], + [[yystype]]]])dnl +m4_case(b4_percent_define_get([[api.value.type]]), + [union], [b4_value_type_setup_union])]) + + +# b4_value_type_setup +# ------------------- +# Check if api.value.type is properly defined, and possibly prepare +# its use. +b4_define_silent([b4_value_type_setup], +[ +# Define default value. +b4_percent_define_ifdef([[api.value.type]], [], +[# %union => api.value.type=union-directive +m4_ifdef([b4_union_members], +[m4_define([b4_percent_define_kind(api.value.type)], [keyword]) +m4_define([b4_percent_define(api.value.type)], [union-directive])], +[# no tag seen => api.value.type={int} +m4_if(b4_tag_seen_flag, 0, +[m4_define([b4_percent_define_kind(api.value.type)], [code]) +m4_define([b4_percent_define(api.value.type)], [int])], +[# otherwise api.value.type=yystype +m4_define([b4_percent_define_kind(api.value.type)], [keyword]) +m4_define([b4_percent_define(api.value.type)], [yystype])])])]) + +# Set up. +m4_bmatch(b4_percent_define_get_kind([[api.value.type]]), + [keyword], [_b4_value_type_setup_keyword]) +]) + + ## ----------------- ## ## Semantic Values. ## ## ----------------- ## @@ -454,11 +557,18 @@ alias Position = ]b4_position_type[;]])[ m4_define([b4_basic_symbol_constructor_define], [b4_token_visible_if([$1], [ this(TokenKind token]b4_symbol_if([$1], [has_type], -[[, typeof(YYSemanticType.]b4_symbol([$1], [type])dnl -[) val]])[]b4_locations_if([[, Location loc]])[) +[[, ]b4_union_if([], [[typeof(YYSemanticType.]])b4_symbol([$1], [type])dnl +[]b4_union_if([], [[) ]])[ val]])[]b4_locations_if([[, Location loc]])[) { - kind = yytranslate_(token);]b4_symbol_if([$1], [has_type], [[ - value_.]b4_symbol([$1], [type])[ = val;]])[]b4_locations_if([ + kind = yytranslate_(token);]b4_union_if([b4_symbol_if([$1], [has_type], [[ + static foreach (member; __traits(allMembers, YYSemanticType)) + { + static if (is(typeof(mixin("value_." ~ member)) == ]b4_symbol([$1], [type])[)) + { + mixin("value_." ~ member ~ " = val;"); + } + }]])], [b4_symbol_if([$1], [has_type], [[ + value_.]b4_symbol([$1], [type])[ = val;]])])[]b4_locations_if([ location_ = loc;])[ } ])]) diff --git a/data/skeletons/lalr1.d b/data/skeletons/lalr1.d index 4b287866..96eb259d 100644 --- a/data/skeletons/lalr1.d +++ b/data/skeletons/lalr1.d @@ -206,7 +206,7 @@ public struct ]b4_location_type[ private immutable bool yy_location_is_class = false; -]])])m4_ifdef([b4_user_union_members], [private union YYSemanticType +]])])[]b4_value_type_setup[]m4_ifdef([b4_user_union_members], [private union YYSemanticType { b4_user_union_members };], diff --git a/tests/calc.at b/tests/calc.at index 0e76c282..042cac7b 100644 --- a/tests/calc.at +++ b/tests/calc.at @@ -645,11 +645,11 @@ m4_define([_AT_DATA_CALC_Y(d)], alias semantic_value = int; } /* Exercise %union. */ -%union +]AT_UNION_IF([[]], [[%union { semantic_value ival; -}; -%printer { yyo.write($$); } ; +};]])[ +%printer { yyo.write($$); } <]AT_UNION_IF([[int]], [[ival]])[>; %code { ]AT_TOKEN_TRANSLATE_IF([[ @@ -670,8 +670,8 @@ m4_define([_AT_DATA_CALC_Y(d)], /* Bison Declarations */ %token EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[ -%token NUM "number" -%type exp +%token <]AT_UNION_IF([[int]], [[ival]])[> NUM "number" +%type <]AT_UNION_IF([[int]], [[ival]])[> exp %token EQUAL "=" MINUS "-" @@ -1499,6 +1499,7 @@ AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error det #AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed %debug %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) #AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) +AT_CHECK_CALC_LALR1_D([%define parse.error custom %define api.value.type union]) # ----------------------- # # LALR1 Java Calculator. # diff --git a/tests/local.at b/tests/local.at index 8411bfa3..f8836282 100644 --- a/tests/local.at +++ b/tests/local.at @@ -319,6 +319,8 @@ m4_pushdef([AT_UNION_IF], [m4_bmatch([$3], [%define api\.value\.type union], [$1], [$2])]) m4_pushdef([AT_VARIANT_IF], [m4_bmatch([$3], [%define api\.value\.type variant], [$1], [$2])]) +m4_pushdef([AT_UNION_IF], +[m4_bmatch([$3], [%define api\.value\.type union], [$1], [$2])]) m4_pushdef([AT_API_prefix], [m4_bmatch([$3], [%define api\.prefix {.*}], [m4_bregexp([$3], [%define api\.prefix {\([^\}]*\)}], [\1])],