Le 23 févr. 2013 à 17:00, Akim Demaille <[email protected]> a écrit :
> * 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. I will squash the following patch in this one. The point is to be even clearer in NEWS, and also to fix issues with %printer and %destructor (for a while I meant to turn api.value.type=union into the same situation as with %union, assigning each symbol a forged tag. But this is wrong, as the real key to use to manipulate the symbols is its genuine type, not a union member name, for things like %printer and %destructor, but also explicit "casts" such as $<int>$). commit 36bb498d99742a0cc8c3499f5935da181bcca1f2 Author: Akim Demaille <[email protected]> Date: Mon Feb 25 11:20:08 2013 +0100 squash! api.value.type: implement proper support, check, and document diff --git a/NEWS b/NEWS index 0aabc13..7af59ea 100644 --- a/NEWS +++ b/NEWS @@ -255,11 +255,11 @@ GNU Bison NEWS ** Variable api.value.type This new %define variable supersedes the #define macro YYSTYPE. The use - of YYSTYPE is discouraged. In particular, #defining YYTSYPE *and* using + of YYSTYPE is discouraged. In particular, #defining YYSTYPE *and* using %union or %defining api.value.type results in undefined behavior. The %define variable api.value.type supports several special values, - examplified below: + exemplified below: The value "%union" denotes that fact that %union is used. @@ -270,29 +270,33 @@ GNU Bison NEWS char *sval; } %token <ival> INT "integer" - %token <sval> STR "string" + %token <sval> STRING "string" + %printer { fprintf (yyo, "%d", $$); } <ival> + %destructor { free ($$); } <sval> /* In yylex(). */ yylval.ival = 42; return INT; - yylval.sval = "42"; return STR; + yylval.sval = "42"; return STRING; - The value "union" means that the user provides genuine types, not - union members names such as "ival" and "sval" above. + The value "union" means that the user provides genuine types, not union + member names such as "ival" and "sval" above. %define api.value.type "union" %token <int> INT "integer" - %token <char *> STR "string" + %token <char *> STRING "string" + %printer { fprintf (yyo, "%d", $$); } <int> + %destructor { free ($$); } <char *> /* In yylex(). */ yylval.yytype_INT = 42; return INT; - yylval.yytype_STR = "42"; return STR; + yylval.yytype_STRING = "42"; return STRING; The value "variant" is somewhat equivalent, but for C++ special provision - is made to allow classes to be used. + is made to allow classes to be used (more about this below). %define api.value.type "variant" %token <int> INT "integer" - %token <std::string> STR "string" + %token <std::string> STRING "string" Any other name is a user type to use. This is where YYSTYPE used to be used. @@ -303,7 +307,7 @@ GNU Bison NEWS { enum { - is_int, is_str + is_int, is_string } kind; union { @@ -314,11 +318,13 @@ GNU Bison NEWS } %define api.value.type "struct my_value" %token <u.ival> INT "integer" - %token <u.sval> STR "string" + %token <u.sval> STRING "string" + %printer { fprintf (yyo, "%d", $$); } <u.ival> + %destructor { free ($$); } <u.sval> /* In yylex(). */ yylval.u.ival = 42; return INT; - yylval.u.sval = "42"; return STR; + yylval.u.sval = "42"; return STRING; ** Variable parse.error @@ -2588,7 +2594,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. LocalWords: Wprecedence Rassoul Wempty Paolo Bonzini parser's Michiel loc LocalWords: redeclaration sval fcaret reentrant XSLT xsl Wmaybe yyvsp Tedi LocalWords: pragmas noreturn untyped Rozenman unexpanded Wojciech Polak - LocalWords: Alexandre MERCHANTABILITY + LocalWords: Alexandre MERCHANTABILITY yytype Local Variables: mode: outline diff --git a/data/bison.m4 b/data/bison.m4 index 4aa6448..2e73f0d 100644 --- a/data/bison.m4 +++ b/data/bison.m4 @@ -359,12 +359,11 @@ b4_define_flag_if([yacc]) # Whether POSIX Yacc is emulated. # Whether has a semantic value. # - type_tag: string # When api.value.type=union, the generated name for the union member. -# yytype_INT etc. for %tokens, otherwise yytype_1 etc. +# 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 first defined -# as the real type (e.g. int), and then changed to be equal to type_tag. +# 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 diff --git a/data/c.m4 b/data/c.m4 index 35741b3..1814877 100644 --- a/data/c.m4 +++ b/data/c.m4 @@ -510,17 +510,13 @@ b4_locations_if([, yylocationp])[]b4_user_args[); # instead of the type name. m4_define([b4_symbol_type_register], [m4_define([b4_symbol($1, type_tag)], - [yytype_[]b4_symbol_if([$1], [is_token], - [b4_symbol_if([$1], [has_id], - [b4_symbol([$1], [id])], - [b4_symbol([$1], [number])])], + [yytype_[]b4_symbol_if([$1], [has_id], + [b4_symbol([$1], [id])], [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]);])) -m4_define([b4_symbol($1, type)], - [b4_symbol([$1], [type_tag])])dnl ]) diff --git a/data/lalr1.cc b/data/lalr1.cc index 1d864b5..4eec878 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -44,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]) # -------------------- diff --git a/tests/types.at b/tests/types.at index 901e4cc..022c7a1 100644 --- a/tests/types.at +++ b/tests/types.at @@ -138,19 +138,27 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]], AT_VAL.fval = 0.2f], [10 0.2]) - # A Bison-defined union. + # The tokens names are not available directly in C++, we use their + # user number to keep it simple between C and C++. AT_TEST([%skeleton "]b4_skel[" %define api.value.type union], [%token <int> ONE 101; - %token <float> TWO 102;], - [ONE TWO { printf ("%d %2.1f\n", $1, $2); }], - [{ 101, 102, EOF }], + %token <float> TWO 102 THREE 103; + %printer { ]AT_SKEL_CC_IF([[yyoutput << $$]], + [[fprintf (yyo, "%d", $$)]])[; } <int> + %printer { ]AT_SKEL_CC_IF([[yyoutput << $$]], + [[fprintf (yyo, "%f", $$)]])[; } <float> + ], + [ONE TWO THREE { printf ("%d %2.1f %2.1f\n", $1, $2, $3); }], + [{ 101, 102, 103, EOF }], [if (res == 101) AT_VAL.yytype_ONE = 10; - else - AT_VAL.yytype_TWO = .2f], - [10 0.2]) + else if (res == 102) + AT_VAL.yytype_TWO = .2f; + else if (res == 103) + AT_VAL.yytype_THREE = 3.3f], + [10 0.2 3.3]) # A Bison-defined variant, for lalr1.cc only. m4_if(b4_skel, [lalr1.cc], [
