api.value.type: use keyword/brace values

Suggested by Joel E. Denny.
http://lists.gnu.org/archive/html/bison-patches/2013-03/msg00016.html

* data/bison.m4 (b4_percent_define_get_kind): New.
(b4_variant_flag): Check that api.value.type is defined as the 'variant'
keyword value.
* data/c.m4 (_b4_value_type_setup_keyword): New.
(b4_value_type_setup): Use it to simplify reading.
Use b4_define_silent.
Decode api.value.type, including its type.
(b4_value_type_define): Likewise.
* data/c++.m4 (b4_value_type_declare): Adjust the decoding of api.value.type,
taking its kind into account.
* doc/bison.texi: Adjust all the examples to the new syntax.
* NEWS: Ditto.
* tests/types.at: Adjust
This commit is contained in:
Akim Demaille
2013-04-05 14:40:25 +02:00
parent 1fa19a7697
commit 435575cb5e
6 changed files with 105 additions and 51 deletions

18
NEWS
View File

@@ -295,11 +295,11 @@ GNU Bison NEWS
yylval.sval = "42"; return STRING; yylval.sval = "42"; return STRING;
The %define variable api.value.type supports several special values. The The %define variable api.value.type supports several special values. The
value "union" means that the user provides genuine types, not union member keyword value 'union' means that the user provides genuine types, not
names such as "ival" and "sval" above (WARNING: will fail if union member names such as "ival" and "sval" above (WARNING: will fail if
-y/--yacc/%yacc is enabled). -y/--yacc/%yacc is enabled).
%define api.value.type "union" %define api.value.type union
%token <int> INT "integer" %token <int> INT "integer"
%token <char *> STRING "string" %token <char *> STRING "string"
%printer { fprintf (yyo, "%d", $$); } <int> %printer { fprintf (yyo, "%d", $$); } <int>
@@ -309,15 +309,15 @@ GNU Bison NEWS
yylval.INT = 42; return INT; yylval.INT = 42; return INT;
yylval.STRING = "42"; return STRING; yylval.STRING = "42"; return STRING;
The value "variant" is somewhat equivalent, but for C++ special provision The keyword value variant is somewhat equivalent, but for C++ special
is made to allow classes to be used (more about this below). provision is made to allow classes to be used (more about this below).
%define api.value.type "variant" %define api.value.type variant
%token <int> INT "integer" %token <int> INT "integer"
%token <std::string> STRING "string" %token <std::string> STRING "string"
Any other name is a user type to use. This is where YYSTYPE used to be Values between braces denote user defined types. This is where YYSTYPE
used. used to be used.
%code requires %code requires
{ {
@@ -334,7 +334,7 @@ GNU Bison NEWS
} u; } u;
}; };
} }
%define api.value.type "struct my_value" %define api.value.type {struct my_value}
%token <u.ival> INT "integer" %token <u.ival> INT "integer"
%token <u.sval> STRING "string" %token <u.sval> STRING "string"
%printer { fprintf (yyo, "%d", $$); } <u.ival> %printer { fprintf (yyo, "%d", $$); } <u.ival>

View File

@@ -707,6 +707,20 @@ b4_loc[]dnl
m4_popdef([b4_loc])], m4_popdef([b4_loc])],
[b4_fatal([[$0: undefined %%define variable '%s']], [$1])])]) [b4_fatal([[$0: undefined %%define variable '%s']], [$1])])])
# b4_percent_define_get_kind(VARIABLE)
# ------------------------------------
# Get the kind (code, keyword, string) of VARIABLE, i.e., how its
# value was defined (braces, not delimiters, quotes).
#
# If the %define variable VARIABLE is undefined, complain fatally
# since that's a Bison or skeleton error. Don't record this as a
# Bison usage of VARIABLE as there's no reason to suspect that the
# user-supplied value has yet influenced the output.
m4_define([b4_percent_define_get_kind],
[m4_ifdef([b4_percent_define_kind(]$1[)],
[m4_indir([b4_percent_define_kind(]$1[)])],
[b4_fatal([[$0: undefined %%define variable '%s']], [$1])])])
# b4_percent_define_get_syncline(VARIABLE) # b4_percent_define_get_syncline(VARIABLE)
# ---------------------------------------- # ----------------------------------------
# Mimic muscle_percent_define_get_syncline in ../src/muscle-tab.h exactly. # Mimic muscle_percent_define_get_syncline in ../src/muscle-tab.h exactly.
@@ -923,9 +937,11 @@ b4_error_verbose_if([m4_define([b4_token_table_flag], [1])])
# b4_variant_if([IF-VARIANT-ARE-USED], [IF-NOT]) # b4_variant_if([IF-VARIANT-ARE-USED], [IF-NOT])
# ---------------------------------------------- # ----------------------------------------------
b4_percent_define_if_define([variant]) b4_percent_define_if_define([variant])
m4_case(b4_percent_define_get([[api.value.type]]), m4_define([b4_variant_flag], [[0]])
[variant], [m4_define([b4_variant_flag], [[1]])], b4_percent_define_ifdef([[api.value.type]],
[m4_define([b4_variant_flag], [[0]])]) [m4_case(b4_percent_define_get_kind([[api.value.type]]), [keyword],
[m4_case(b4_percent_define_get([[api.value.type]]), [variant],
[m4_define([b4_variant_flag], [[1]])])])])
b4_define_flag_if([variant]) b4_define_flag_if([variant])

View File

@@ -120,14 +120,16 @@ m4_define([b4_token_enums],
m4_define([b4_value_type_declare], m4_define([b4_value_type_declare],
[b4_value_type_setup[]dnl [b4_value_type_setup[]dnl
[ /// Symbol semantic values. [ /// Symbol semantic values.
]m4_bmatch(b4_percent_define_get([api.value.type]), ]m4_bmatch(b4_percent_define_get_kind([[api.value.type]]),
[^%union\|union$], [code],
[[ typedef ]b4_percent_define_get([[api.value.type]])[ semantic_type;]],
[m4_bmatch(b4_percent_define_get([[api.value.type]]),
[union\|union-directive],
[[ union semantic_type [[ union semantic_type
{ {
]b4_user_union_members[ ]b4_user_union_members[
};]], };]])])dnl
[^$], [], ])
[[ typedef ]b4_percent_define_get([api.value.type])[ semantic_type;]])])
# b4_public_types_declare # b4_public_types_declare

View File

@@ -563,25 +563,51 @@ m4_copy_force([b4_symbol_value_union], [b4_symbol_value])
# Setup support for api.value.type=variant. By default, fail, specialized # Setup support for api.value.type=variant. By default, fail, specialized
# by other skeletons. # by other skeletons.
m4_define([b4_value_type_setup_variant], m4_define([b4_value_type_setup_variant],
[b4_complain_at(b4_percent_define_get_loc([api.value.type]), [b4_complain_at(b4_percent_define_get_loc([[api.value.type]]),
[['%s' does not support '%s']], [['%s' does not support '%s']],
[b4_skeleton], [b4_skeleton],
[%define api.value.type variant])]) [%define api.value.type variant])])
# _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]],
[[variant]],
[[yystype]]]])dnl
m4_case(b4_percent_define_get([[api.value.type]]),
[union], [b4_value_type_setup_union],
[variant], [b4_value_type_setup_variant])])
# b4_value_type_setup # b4_value_type_setup
# ------------------- # -------------------
# Check if api.value.type is properly defined, and possibly prepare # Check if api.value.type is properly defined, and possibly prepare
# its use. # its use.
m4_define([b4_value_type_setup], b4_define_silent([b4_value_type_setup],
[b4_percent_define_default([[api.value.type]], [# Define default value.
[m4_ifdef([b4_union_members], [%union], b4_percent_define_ifdef([[api.value.type]], [],
[m4_if(b4_tag_seen_flag, 0, [int], [# %union => api.value.type=union-directive
[])])])dnl m4_ifdef([b4_union_members],
m4_case(b4_percent_define_get([api.value.type]), [m4_define([b4_percent_define_kind(api.value.type)], [keyword])
[union], [b4_value_type_setup_union], m4_define([b4_percent_define(api.value.type)], [union-directive])],
[variant], [b4_value_type_setup_variant])]) [# 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\|string], [_b4_value_type_setup_keyword])
])
## -------------- ## ## -------------- ##
@@ -594,8 +620,16 @@ m4_case(b4_percent_define_get([api.value.type]),
m4_define([b4_value_type_define], m4_define([b4_value_type_define],
[b4_value_type_setup[]dnl [b4_value_type_setup[]dnl
/* Value type. */ /* Value type. */
m4_bmatch(b4_percent_define_get([api.value.type]), m4_bmatch(b4_percent_define_get_kind([[api.value.type]]),
[^%?union$], [code],
[[#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
]],
[m4_bmatch(b4_percent_define_get([[api.value.type]]),
[union\|union-directive],
[[#if ! defined ]b4_api_PREFIX[STYPE && ! defined ]b4_api_PREFIX[STYPE_IS_DECLARED [[#if ! defined ]b4_api_PREFIX[STYPE && ! defined ]b4_api_PREFIX[STYPE_IS_DECLARED
typedef union ]b4_union_name[ ]b4_api_PREFIX[STYPE; typedef union ]b4_union_name[ ]b4_api_PREFIX[STYPE;
union ]b4_union_name[ union ]b4_union_name[
@@ -605,14 +639,7 @@ union ]b4_union_name[
# define ]b4_api_PREFIX[STYPE_IS_TRIVIAL 1 # define ]b4_api_PREFIX[STYPE_IS_TRIVIAL 1
# define ]b4_api_PREFIX[STYPE_IS_DECLARED 1 # define ]b4_api_PREFIX[STYPE_IS_DECLARED 1
#endif #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 # b4_location_type_define

View File

@@ -1555,7 +1555,7 @@ calculator. As in C, comments are placed between @samp{/*@dots{}*/}.
%@} %@}
@end group @end group
%define api.value.type double %define api.value.type @{double@}
%token NUM %token NUM
%% /* Grammar rules and actions follow. */ %% /* Grammar rules and actions follow. */
@@ -1582,9 +1582,9 @@ thus specifying the C data type for semantic values of both tokens and
groupings (@pxref{Value Type, ,Data Types of Semantic Values}). The Bison groupings (@pxref{Value Type, ,Data Types of Semantic Values}). The Bison
parser will use whatever type @code{api.value.type} is defined as; if you parser will use whatever type @code{api.value.type} is defined as; if you
don't define it, @code{int} is the default. Because we specify don't define it, @code{int} is the default. Because we specify
@code{double}, each token and each expression has an associated value, which @samp{@{double@}}, each token and each expression has an associated value,
is a floating point number. C code can use @code{YYSTYPE} to refer to the which is a floating point number. C code can use @code{YYSTYPE} to refer to
value @code{api.value.type}. the value @code{api.value.type}.
Each terminal symbol that is not a single-character literal must be Each terminal symbol that is not a single-character literal must be
declared. (Single-character literals normally don't need to be declared.) declared. (Single-character literals normally don't need to be declared.)
@@ -1806,7 +1806,7 @@ The semantic value of the token (if it has one) is stored into the
global variable @code{yylval}, which is where the Bison parser will look global variable @code{yylval}, which is where the Bison parser will look
for it. (The C data type of @code{yylval} is @code{YYSTYPE}, whose value for it. (The C data type of @code{yylval} is @code{YYSTYPE}, whose value
was defined at the beginning of the grammar via @samp{%define api.value.type was defined at the beginning of the grammar via @samp{%define api.value.type
double}; @pxref{Rpcalc Declarations,,Declarations for @code{rpcalc}}.) @{double@}}; @pxref{Rpcalc Declarations,,Declarations for @code{rpcalc}}.)
A token type code of zero is returned if the end-of-input is encountered. A token type code of zero is returned if the end-of-input is encountered.
(Bison recognizes any nonpositive value as indicating end-of-input.) (Bison recognizes any nonpositive value as indicating end-of-input.)
@@ -2004,7 +2004,7 @@ parentheses nested to arbitrary depth. Here is the Bison code for
@group @group
/* Bison declarations. */ /* Bison declarations. */
%define api.value.type double %define api.value.type @{double@}
%token NUM %token NUM
%left '-' '+' %left '-' '+'
%left '*' '/' %left '*' '/'
@@ -3670,14 +3670,14 @@ specify some other type, define the @code{%define} variable
@code{api.value.type} like this: @code{api.value.type} like this:
@example @example
%define api.value.type double %define api.value.type @{double@}
@end example @end example
@noindent @noindent
or or
@example @example
%define api.value.type "struct semantic_type" %define api.value.type @{struct semantic_type@}
@end example @end example
The value of @code{api.value.type} should be a type name that does not The value of @code{api.value.type} should be a type name that does not

View File

@@ -26,7 +26,7 @@ AT_SETUP([[%union vs. %define api.value.type]])
AT_DATA([[input.y]], AT_DATA([[input.y]],
[[%union { int ival; } [[%union { int ival; }
%define api.value.type "%union" %define api.value.type union-directive
%% %%
exp: %empty; exp: %empty;
]]) ]])
@@ -45,7 +45,7 @@ AT_SETUP([[%yacc vs. %define api.value.type union]])
AT_DATA([[input.y]], AT_DATA([[input.y]],
[[%yacc [[%yacc
%define api.value.type "union" %define api.value.type union
%% %%
exp: %empty; exp: %empty;
]]) ]])
@@ -108,16 +108,25 @@ AT_CLEANUP
m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]], m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]],
[# A built-in type. [# A built-in type.
AT_TEST([%skeleton "]b4_skel[" AT_TEST([%skeleton "]b4_skel["
%define api.value.type double], %define api.value.type {double}],
[], [],
['1' '2' { printf ("%2.1f\n", $1 + $2); }], ['1' '2' { printf ("%2.1f\n", $1 + $2); }],
["12"], ["12"],
[AT_VAL = (res - '0') / 10.0], [AT_VAL = (res - '0') / 10.0],
[0.3]) [0.3])
# A typedef which looks like a Bison keyword, but it's using braces.
AT_TEST([%skeleton "]b4_skel["
%define api.value.type {variant}],
[%code requires { typedef double variant; }],
['1' '2' { printf ("%2.1f\n", $1 + $2); }],
["12"],
[AT_VAL = (res - '0') / 10.0],
[0.3])
# A user defined struct. # A user defined struct.
AT_TEST([%skeleton "]b4_skel[" AT_TEST([%skeleton "]b4_skel["
%define api.value.type "struct foo"], %define api.value.type {struct foo}],
[%code requires { struct foo { float fval; int ival; }; }], [%code requires { struct foo { float fval; int ival; }; }],
['1' '2' ['1' '2'
{ printf ("%d %2.1f\n", $1.ival + $2.ival, $1.fval + $2.fval); }], { printf ("%d %2.1f\n", $1.ival + $2.ival, $1.fval + $2.fval); }],
@@ -128,7 +137,7 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]],
# A user defined struct that uses pointers. # A user defined struct that uses pointers.
AT_TEST([%skeleton "]b4_skel[" AT_TEST([%skeleton "]b4_skel["
%define api.value.type "struct bar"], %define api.value.type {struct bar}],
[%code requires [%code requires
{ {
struct u struct u
@@ -158,7 +167,7 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]],
# A user defined union. # A user defined union.
AT_TEST([%skeleton "]b4_skel[" AT_TEST([%skeleton "]b4_skel["
%define api.value.type "union foo"], %define api.value.type {union foo}],
[%code requires { union foo { float fval; int ival; }; }], [%code requires { union foo { float fval; int ival; }; }],
['1' '2' { printf ("%d %2.1f\n", $1.ival, $2.fval); }], ['1' '2' { printf ("%d %2.1f\n", $1.ival, $2.fval); }],
["12"], ["12"],