mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +00:00
%union: fix the support for named %union
Bison supports a union tag, for obscure reasons. But it does a poor job at it, especially since Bison 3.0. Reported by Stephen Cameron and Tobias Frost. It did not ensure that the name was not given several times. An easy way to do this is to make the %union tag be handled as a %define variable, as they cannot be defined several times. Since Bison 3.0, the synclines were wrongly placed, resulting in invalid code. Addressing this issue, because of the way the union tag was stored (as a code muscle), would have been tedious. Unless we rather define the %union tag as a %percent variable, whose synclines are easier to manipulate. So replace the b4_union_name muscle by the api.value.union.name %define variable, document, and check. * data/bison.m4: Make sure that api.value.union.name has a keyword value. * data/c++.m4: Make sure that api.value.union.name is not defined. * data/c.m4 (b4_union_name): No longer use it, use api.value.union.name. * doc/bison.texi (%define Summary): Document it. * src/parse-gram.y (union_name): No longer define b4_uion_name, but api.value.union.name. * tests/input.at (Redefined %union name): New. * tests/synclines.at (%union name syncline): New. * tests/types.at: Check named %unions.
This commit is contained in:
9
NEWS
9
NEWS
@@ -4,6 +4,15 @@ GNU Bison NEWS
|
||||
|
||||
** Bug fixes
|
||||
|
||||
*** Named %union support
|
||||
|
||||
Bison 3.0 introduced a regression on named %union such as
|
||||
|
||||
%union foo { int ival; };
|
||||
|
||||
The possibility to use a name was introduced ``for Yacc compatibility''.
|
||||
It is however not required by POSIX Yacc, and its usefulness is not clear.
|
||||
|
||||
*** %define api.value.type union with %defines
|
||||
|
||||
The yacc.c and glr.c parsers were broken when %defines was used
|
||||
|
||||
2
THANKS
2
THANKS
@@ -126,6 +126,7 @@ Sebastien Fricker sebastien.fricker@gmail.com
|
||||
Sergei Steshenko sergstesh@yahoo.com
|
||||
Shura debil_urod@ngs.ru
|
||||
Stefano Lattarini stefano.lattarini@gmail.com
|
||||
Stephen Cameron stephenmcameron@gmail.com
|
||||
Steve Murphy murf@parsetree.com
|
||||
Sum Wu sum@geekhouse.org
|
||||
Théophile Ranquet theophile.ranquet@gmail.com
|
||||
@@ -133,6 +134,7 @@ Thiru Ramakrishnan thiru.ramakrishnan@gmail.com
|
||||
Tim Josling tej@melbpc.org.au
|
||||
Tim Landscheidt tim@tim-landscheidt.de
|
||||
Tim Van Holder tim.van.holder@pandora.be
|
||||
Tobias Frost tobi@debian.org
|
||||
Tom Lane tgl@sss.pgh.pa.us
|
||||
Tom Tromey tromey@cygnus.com
|
||||
Tommy Nordgren tommy.nordgren@chello.se
|
||||
|
||||
@@ -1061,3 +1061,6 @@ b4_percent_define_ifdef([api.value.type],
|
||||
[['%s' and '%s' cannot be used together]],
|
||||
[%yacc],
|
||||
[%define api.value.type "union"])])])])
|
||||
|
||||
# api.value.union.name.
|
||||
b4_percent_define_check_kind([api.value.union.name], [keyword])
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Sanity checks, before defaults installed by c.m4.
|
||||
b4_percent_define_ifdef([[api.value.union.name]],
|
||||
[b4_complain_at(b4_percent_define_get_loc([[api.value.union.name]]),
|
||||
[named %union is invalid in C++])])
|
||||
|
||||
m4_include(b4_pkgdatadir/[c.m4])
|
||||
|
||||
# b4_comment(TEXT, [PREFIX])
|
||||
|
||||
16
data/c.m4
16
data/c.m4
@@ -97,7 +97,8 @@ m4_define([b4_api_PREFIX],
|
||||
m4_define_default([b4_prefix], [b4_api_prefix])
|
||||
|
||||
# If the %union is not named, its name is YYSTYPE.
|
||||
m4_define_default([b4_union_name], [b4_api_PREFIX[]STYPE])
|
||||
b4_percent_define_default([[api.value.union.name]],
|
||||
[b4_api_PREFIX[][STYPE]])
|
||||
|
||||
|
||||
## ------------------------ ##
|
||||
@@ -608,10 +609,9 @@ m4_copy_force([b4_symbol_value_union], [b4_symbol_value])
|
||||
])
|
||||
|
||||
|
||||
# ---------------- #
|
||||
# api.value.type. #
|
||||
# ---------------- #
|
||||
|
||||
# -------------------------- #
|
||||
# api.value.type = variant. #
|
||||
# -------------------------- #
|
||||
|
||||
# b4_value_type_setup_variant
|
||||
# ---------------------------
|
||||
@@ -686,11 +686,13 @@ typedef ]b4_percent_define_get([[api.value.type]])[ ]b4_api_PREFIX[STYPE;
|
||||
[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
|
||||
typedef union ]b4_union_name[ ]b4_api_PREFIX[STYPE;
|
||||
union ]b4_union_name[
|
||||
]b4_percent_define_get_syncline([[api.value.union.name]])[
|
||||
union ]b4_percent_define_get([[api.value.union.name]])[
|
||||
{
|
||||
]b4_user_union_members[
|
||||
};
|
||||
]b4_percent_define_get_syncline([[api.value.union.name]])[
|
||||
typedef union ]b4_percent_define_get([[api.value.union.name]])[ ]b4_api_PREFIX[STYPE;
|
||||
# define ]b4_api_PREFIX[STYPE_IS_TRIVIAL 1
|
||||
# define ]b4_api_PREFIX[STYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
@@ -3851,7 +3851,7 @@ example:
|
||||
@noindent
|
||||
specifies the union tag @code{value}, so the corresponding C type is
|
||||
@code{union value}. If you do not specify a tag, it defaults to
|
||||
@code{YYSTYPE}.
|
||||
@code{YYSTYPE} (@pxref{%define Summary,,api.value.union.name}).
|
||||
|
||||
As another extension to POSIX, you may specify multiple @code{%union}
|
||||
declarations; their contents are concatenated. However, only the first
|
||||
@@ -6014,12 +6014,12 @@ Use this @var{type} as semantic value.
|
||||
@item Default Value:
|
||||
@itemize @minus
|
||||
@item
|
||||
@code{%union} if @code{%union} is used, otherwise @dots{}
|
||||
@code{union-directive} if @code{%union} is used, otherwise @dots{}
|
||||
@item
|
||||
@code{int} if type tags are used (i.e., @samp{%token <@var{type}>@dots{}} or
|
||||
@samp{%token <@var{type}>@dots{}} is used), otherwise @dots{}
|
||||
@samp{%type <@var{type}>@dots{}} is used), otherwise @dots{}
|
||||
@item
|
||||
@code{""}
|
||||
undefined.
|
||||
@end itemize
|
||||
|
||||
@item History:
|
||||
@@ -6030,6 +6030,30 @@ introduced in Bison 3.0. Was introduced for Java only in 2.3b as
|
||||
@c api.value.type
|
||||
|
||||
|
||||
@c ================================================== api.value.union.name
|
||||
@deffn Directive {%define api.value.union.name} @var{name}
|
||||
@itemize @bullet
|
||||
@item Language(s):
|
||||
C
|
||||
|
||||
@item Purpose:
|
||||
The tag of the generated @code{union} (@emph{not} the name of the
|
||||
@code{typedef}). This variable is set to @code{@var{id}} when @samp{%union
|
||||
@var{id}} is used. There is no clear reason to give this union a name.
|
||||
|
||||
@item Accepted Values:
|
||||
Any valid identifier.
|
||||
|
||||
@item Default Value:
|
||||
@code{YYSTYPE}.
|
||||
|
||||
@item History:
|
||||
Introduced in Bison 3.0.3.
|
||||
@end itemize
|
||||
@end deffn
|
||||
@c api.value.type
|
||||
|
||||
|
||||
@c ================================================== location_type
|
||||
@deffn Directive {%define location_type}
|
||||
Obsoleted by @code{api.location.type} since Bison 2.7.
|
||||
|
||||
374
src/parse-gram.c
374
src/parse-gram.c
File diff suppressed because it is too large
Load Diff
@@ -61,7 +61,7 @@ extern int gram_debug;
|
||||
param_parse = 1 << 1,
|
||||
param_both = param_lex | param_parse
|
||||
} param_type;
|
||||
#line 645 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 647 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#include "muscle-tab.h"
|
||||
|
||||
#line 68 "src/parse-gram.h" /* yacc.c:1909 */
|
||||
@@ -132,7 +132,7 @@ extern int gram_debug;
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined GRAM_STYPE && ! defined GRAM_STYPE_IS_DECLARED
|
||||
typedef union GRAM_STYPE GRAM_STYPE;
|
||||
|
||||
union GRAM_STYPE
|
||||
{
|
||||
#line 182 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
@@ -155,7 +155,7 @@ named_ref *named_ref;
|
||||
param_type param;
|
||||
#line 409 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
code_props_type code_type;
|
||||
#line 647 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 649 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
|
||||
struct
|
||||
{
|
||||
@@ -165,6 +165,8 @@ code_props_type code_type;
|
||||
|
||||
#line 167 "src/parse-gram.h" /* yacc.c:1909 */
|
||||
};
|
||||
|
||||
typedef union GRAM_STYPE GRAM_STYPE;
|
||||
# define GRAM_STYPE_IS_TRIVIAL 1
|
||||
# define GRAM_STYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
@@ -421,7 +421,9 @@ code_props_type:
|
||||
|
||||
union_name:
|
||||
%empty {}
|
||||
| ID { muscle_code_grow ("union_name", $1, @1); }
|
||||
| ID { muscle_percent_define_insert ("api.value.union.name",
|
||||
@1, muscle_keyword, $1,
|
||||
MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE); }
|
||||
;
|
||||
|
||||
grammar_declaration:
|
||||
|
||||
@@ -1904,6 +1904,51 @@ m4_popdef([AT_TEST])
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
## ----------------------- ##
|
||||
## Redefined %union name. ##
|
||||
## ----------------------- ##
|
||||
|
||||
AT_SETUP([[Redefined %union name]])
|
||||
|
||||
# AT_TEST(DIRECTIVES, ERROR)
|
||||
# --------------------------
|
||||
m4_pushdef([AT_TEST],
|
||||
[AT_DATA([[input.y]],
|
||||
[$1
|
||||
%%
|
||||
exp: %empty;
|
||||
])
|
||||
|
||||
AT_BISON_CHECK([[input.y]], [[1]], [[]],
|
||||
[$2])
|
||||
])
|
||||
|
||||
AT_TEST([[%union foo {};
|
||||
%union {};
|
||||
%union foo {};
|
||||
%define api.value.union.name foo]],
|
||||
[[input.y:3.8-10: error: %define variable 'api.value.union.name' redefined
|
||||
input.y:1.8-10: previous definition
|
||||
input.y:4.9-28: error: %define variable 'api.value.union.name' redefined
|
||||
input.y:3.8-10: previous definition
|
||||
]])
|
||||
|
||||
AT_TEST([[%define api.value.union.name {foo}]],
|
||||
[[input.y:1.9-28: error: %define variable 'api.value.union.name' requires keyword values
|
||||
input.y:1.9-28: error: %define variable 'api.value.union.name' is not used
|
||||
]])
|
||||
|
||||
AT_TEST([[%define api.value.union.name "foo"]],
|
||||
[[input.y:1.9-28: error: %define variable 'api.value.union.name' requires keyword values
|
||||
input.y:1.9-28: error: %define variable 'api.value.union.name' is not used
|
||||
]])
|
||||
|
||||
m4_popdef([AT_TEST])
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
|
||||
|
||||
## -------------- ##
|
||||
## Stray $ or @. ##
|
||||
## -------------- ##
|
||||
|
||||
@@ -182,6 +182,35 @@ exp: '0';
|
||||
])
|
||||
|
||||
|
||||
## ---------------------- ##
|
||||
## %union name syncline. ##
|
||||
## ---------------------- ##
|
||||
|
||||
# Check that invalid union names are properly reported in the
|
||||
# source file.
|
||||
AT_SETUP([%union name syncline])
|
||||
AT_BISON_OPTION_PUSHDEFS
|
||||
AT_DATA([[input.y]],
|
||||
[[%union break
|
||||
{
|
||||
char dummy;
|
||||
}
|
||||
%{
|
||||
]AT_YYERROR_DECLARE_EXTERN[
|
||||
]AT_YYLEX_DECLARE_EXTERN[
|
||||
%}
|
||||
%%
|
||||
exp: '0';
|
||||
%%
|
||||
]])
|
||||
|
||||
AT_BISON_CHECK([-o input.c input.y])
|
||||
AT_SYNCLINES_COMPILE([input.c])
|
||||
AT_CHECK([[grep '^input.y:1' stdout]], 0, [ignore])
|
||||
AT_BISON_OPTION_POPDEFS
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
## ----------------------- ##
|
||||
## Postprologue syncline. ##
|
||||
## ----------------------- ##
|
||||
|
||||
@@ -197,9 +197,14 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]],
|
||||
AT_VAL.fval = .2f],
|
||||
[10 0.2])
|
||||
|
||||
# A %union.
|
||||
AT_TEST([%skeleton "]b4_skel["
|
||||
%union { float fval; int ival; };],
|
||||
# A %union and a named %union. In C++ named %union is an error.
|
||||
m4_foreach([b4_union],
|
||||
[m4_bmatch(b4_skel, [\.cc$],
|
||||
[[%union]],
|
||||
[[%union], [%union foo],
|
||||
[%define api.value.union.name foo; %union]])],
|
||||
[AT_TEST([%skeleton "]b4_skel["
|
||||
]b4_union[ { float fval; int ival; };],
|
||||
[%token <ival> '1';
|
||||
%token <fval> '2';],
|
||||
['1' '2' { printf ("%d %2.1f\n", $1, $2); }],
|
||||
@@ -208,7 +213,7 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]],
|
||||
AT_VAL.ival = 10;
|
||||
else
|
||||
AT_VAL.fval = 0.2f],
|
||||
[10 0.2])
|
||||
[10 0.2])])
|
||||
|
||||
# A Bison-defined union.
|
||||
# The tokens names are not available directly in C++, we use their
|
||||
@@ -249,3 +254,22 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]],
|
||||
|
||||
m4_popdef([AT_TEST])
|
||||
m4_popdef([_AT_TEST])
|
||||
|
||||
|
||||
## ------------------- ##
|
||||
## C++: Named %union. ##
|
||||
## ------------------- ##
|
||||
|
||||
m4_foreach([b4_skel], [[lalr1.cc], [glr.cc]],
|
||||
[AT_SETUP([b4_skel: Named %union])
|
||||
AT_DATA([input.y],
|
||||
[%skeleton "]b4_skel["
|
||||
%union foo { float fval; int ival; };
|
||||
%%
|
||||
exp: %empty;
|
||||
])
|
||||
AT_BISON_CHECK([input.y], 1, [],
|
||||
[[input.y:2.8-10: error: named %union is invalid in C++
|
||||
]])
|
||||
AT_CLEANUP
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user