api.value.type: implement proper support, check, and document

* data/c.m4 (b4_symbol_type_register, b4_type_define_tag)
(b4_symbol_value_union, b4_value_type_setup_union)
(b4_value_type_setup_variant, b4_value_type_setup):
New.
(b4_value_type_define): Use it to set up properly the type.
Handle the various possible values of api.value.type.
* data/c++.m4 (b4_value_type_declare): Likewise.
* data/lalr1.cc (b4_value_type_setup_variant): Redefine.

* tests/types.at: New.
Exercise all the C/C++ skeletons with different types of
api.value.type values.
* tests/local.mk, tests/testsuite.at: Use it.

* doc/bison.texi (%define Summary): Document api.value.type.
* NEWS: Advertise it, together with api.token.constructor.
This commit is contained in:
Akim Demaille
2013-02-08 17:17:33 +01:00
parent dde95ca432
commit 6574576cfb
9 changed files with 463 additions and 25 deletions

View File

@@ -361,6 +361,7 @@ b4_define_flag_if([yacc]) # Whether POSIX Yacc is emulated.
# Whether the symbol has an id.
# - id: string
# If has_id, the id. Guaranteed to be usable as a C identifier.
# Prefixed by api.token.prefix if defined.
# - tag: string.
# A representat of the symbol. Can be 'foo', 'foo.id', '"foo"' etc.
# - user_number: integer
@@ -371,9 +372,13 @@ b4_define_flag_if([yacc]) # Whether POSIX Yacc is emulated.
# The internalized number (used after yytranslate).
# - has_type: 0, 1
# Whether has a semantic value.
# - type_tag: string
# When api.value.type=union, the generated name for the union member.
# yytype_INT etc. for symbols that has_id, otherwise yytype_1 etc.
# - type
# If it has a semantic value, its type tag, or, if variant are used,
# its type.
# In the case of api.value.type=union, type is the real type (e.g. int).
# - has_printer: 0, 1
# - printer: string
# - printer_file: string
@@ -962,3 +967,10 @@ b4_percent_define_ifdef([api.prefix],
[['%s' and '%s' cannot be used together]],
[%name-prefix],
[%define api.prefix])])])
b4_percent_define_ifdef([api.value.type],
[m4_ifdef([b4_union_members],
[b4_complain_at(b4_percent_define_get_loc([api.value.type]),
[['%s' and '%s' cannot be used together]],
[%union],
[%define api.value.type])])])

View File

@@ -118,15 +118,16 @@ m4_define([b4_token_enums],
# ---------------------
# Declare semantic_type.
m4_define([b4_value_type_declare],
[b4_value_type_setup[]dnl
[ /// Symbol semantic values.
m4_ifdef([b4_union_members],
[ union semantic_type
]m4_bmatch(b4_percent_define_get([api.value.type]),
[^%union\|union$],
[[ union semantic_type
{
b4_user_union_members
};],
[m4_if(b4_tag_seen_flag, 0,
[[ typedef int semantic_type;]],
[[ typedef ]b4_api_PREFIX[STYPE semantic_type;]])])])
]b4_user_union_members[
};]],
[^$], [],
[[ typedef ]b4_percent_define_get([api.value.type])[ semantic_type;]])])
# b4_public_types_declare

117
data/c.m4
View File

@@ -492,28 +492,127 @@ b4_locations_if([, yylocationp])[]b4_user_args[);
}]dnl
])
## ---------------- ##
## api.value.type. ##
## ---------------- ##
# ---------------------- #
# api.value.type=union. #
# ---------------------- #
# b4_symbol_type_register(SYMBOL-NUM)
# -----------------------------------
# Symbol SYMBOL-NUM has a type (for variant) instead of a type-tag.
# Extend the definition of %union's body 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])],
[yytype_[]b4_symbol([$1], [number])])])dnl
m4_append([b4_user_union_members],
m4_expand([
b4_symbol_tag_comment([$1])dnl
b4_symbol([$1], [type]) b4_symbol([$1], [type_tag]);]))
])
# 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, [TYPE])
# ----------------------------------
# Same of b4_symbol_value, but when api.value.type=union.
m4_define([b4_symbol_value_union],
[m4_ifval([$2],
[(*($2*)(&$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])
])
# ---------------- #
# api.value.type. #
# ---------------- #
# b4_value_type_setup_variant
# ---------------------------
# Setup support for api.value.type=variant. By default, fail, specialized
# by other skeletons.
m4_define([b4_value_type_setup_variant],
[b4_complain_at(b4_percent_define_get_loc([api.value.type]),
[['%s' does not support '%s']],
[b4_skeleton],
[%define api.value.type variant])])
# b4_value_type_setup
# -------------------
# Check if api.value.type is properly defined, and possibly prepare
# its use.
m4_define([b4_value_type_setup],
[b4_percent_define_default([[api.value.type]],
[m4_ifdef([b4_union_members], [%union],
[m4_if(b4_tag_seen_flag, 0, [int],
[])])])dnl
m4_case(b4_percent_define_get([api.value.type]),
[union], [b4_value_type_setup_union],
[variant], [b4_value_type_setup_variant])])
## -------------- ##
## Declarations. ##
## -------------- ##
# b4_value_type_define
# --------------------
m4_define([b4_value_type_define],
[[/* Value type. */
#if ! defined ]b4_api_PREFIX[STYPE && ! defined ]b4_api_PREFIX[STYPE_IS_DECLARED
]m4_ifdef([b4_union_members],
[[typedef union ]b4_union_name[ ]b4_api_PREFIX[STYPE;
[b4_value_type_setup[]dnl
/* Value type. */
m4_bmatch(b4_percent_define_get([api.value.type]),
[^%?union$],
[[#if ! defined ]b4_api_PREFIX[STYPE && ! defined ]b4_api_PREFIX[STYPE_IS_DECLARED
typedef union ]b4_union_name[ ]b4_api_PREFIX[STYPE;
union ]b4_union_name[
{
]b4_user_union_members[
};
# define ]b4_api_PREFIX[STYPE_IS_TRIVIAL 1]],
[m4_if(b4_tag_seen_flag, 0,
[[typedef int ]b4_api_PREFIX[STYPE;
# define ]b4_api_PREFIX[STYPE_IS_TRIVIAL 1]])])[
# define ]b4_api_PREFIX[STYPE_IS_TRIVIAL 1
# define ]b4_api_PREFIX[STYPE_IS_DECLARED 1
#endif
]])
]],
[^$], [],
[[#if ! defined ]b4_api_PREFIX[STYPE && ! defined ]b4_api_PREFIX[STYPE_IS_DECLARED
typedef ]b4_percent_define_get([api.value.type])[ ]b4_api_PREFIX[STYPE;
# define ]b4_api_PREFIX[STYPE_IS_TRIVIAL 1
# define ]b4_api_PREFIX[STYPE_IS_DECLARED 1
#endif
]])])
# b4_location_type_define

View File

@@ -17,6 +17,8 @@
m4_include(b4_pkgdatadir/[c++.m4])
# api.value.type=variant is valid.
m4_define([b4_value_type_setup_variant])
# b4_integral_parser_table_declare(TABLE-NAME, CONTENT, COMMENT)
# --------------------------------------------------------------
@@ -42,9 +44,11 @@ m4_define([b4_integral_parser_table_define],
# b4_symbol_value_template(VAL, [TYPE])
# -------------------------------------
# Same as b4_symbol_value, but used in a template method. It makes
# a difference when using variants.
# a difference when using variants. Note that b4_value_type_setup_union
# overrides b4_symbol_value, so we must override it again.
m4_copy([b4_symbol_value], [b4_symbol_value_template])
m4_append([b4_value_type_setup_union],
[m4_copy_force([b4_symbol_value_union], [b4_symbol_value_template])])
# b4_lhs_value([TYPE])
# --------------------