YYSTYPE if your grammar contains at least one <type> tag.
Your YYSTYPE need not be a macro; it can be a typedef.
* doc/bison.texinfo (Value Type, Multiple Types, Location Type):
(Union Decl, Decl Summary): Document this.
* data/glr.c (YYSTYPE): Implement this.
* data/glr.cc (YYSTYPE): Likewise.
* data/lalr1.cc (YYSTYPE): Likewise.
* data/yacc.c (YYSTYPE): Likewise.
* src/output.c (prepare): Output tag_seen_flag.
* src/parse-gram.y (declaration, grammar_declaration):
Use 'union_seen' rather than 'typed' to determine whether
%union has been seen, since grammars can now be typed without
%union.
(symbol_declaration, type.opt, symbol_def):
Keep track of whether a tag has been seen.
* src/reader.c (union_seen, tag_seen): New vars.
(typed): remove.
* src/reader.h (union_seen, tag_seen, typed): Likewise.
* src/scan-code.l (untyped_var_seen): New variable.
(handle_action_dollar): Adjust to above changes.
(handle_action_dollar, handle_action_at):
Improve overflow checking for outlandish numbers.
* tests/input.at (AT_CHECK_UNUSED_VALUES): Redo test to
avoid new diagnostics generated by above changes.
* tests/regression.at (YYSTYPE typedef): Add test to check
for type tags without %union.
+2006-07-09 Paul Eggert <eggert@cs.ucla.edu>
+
+ * NEWS: Instead of %union, you can define and use your own union type
+ YYSTYPE if your grammar contains at least one <type> tag.
+ Your YYSTYPE need not be a macro; it can be a typedef.
+ * doc/bison.texinfo (Value Type, Multiple Types, Location Type):
+ (Union Decl, Decl Summary): Document this.
+ * data/glr.c (YYSTYPE): Implement this.
+ * data/glr.cc (YYSTYPE): Likewise.
+ * data/lalr1.cc (YYSTYPE): Likewise.
+ * data/yacc.c (YYSTYPE): Likewise.
+ * src/output.c (prepare): Output tag_seen_flag.
+ * src/parse-gram.y (declaration, grammar_declaration):
+ Use 'union_seen' rather than 'typed' to determine whether
+ %union has been seen, since grammars can now be typed without
+ %union.
+ (symbol_declaration, type.opt, symbol_def):
+ Keep track of whether a tag has been seen.
+ * src/reader.c (union_seen, tag_seen): New vars.
+ (typed): remove.
+ * src/reader.h (union_seen, tag_seen, typed): Likewise.
+ * src/scan-code.l (untyped_var_seen): New variable.
+ (handle_action_dollar): Adjust to above changes.
+ (handle_action_dollar, handle_action_at):
+ Improve overflow checking for outlandish numbers.
+ * tests/input.at (AT_CHECK_UNUSED_VALUES): Redo test to
+ avoid new diagnostics generated by above changes.
+ * tests/regression.at (YYSTYPE typedef): Add test to check
+ for type tags without %union.
+
+ * src/symlist.c (symbol_list_length): Return int, not unsigned
+ int, since callers expect int. This may need to get revisited
+ once we have proper integer overflow checking.
+
+ * src/scan-gram.h (gram_scanner_cursor): Remove decl, since this
+ object is now static.
+
+ * src/getargs.c (flags_argmatch): Return void, not int,
+ to pacify ./configure --enable-gcc-warnings.
+
+ * src/flex-scanner.h (STRING_FREE): Don't use FLEX_PREFIX (last_string)
+ since last_string is already defined to FLEX_PREFIX (last_string).
+
2006-07-09 Akim Demaille <akim@lrde.epita.fr>
Implement --warnings/-W.
Changes in version 2.3+:
+* Instead of %union, you can define and use your own union type
+ YYSTYPE if your grammar contains at least one <type> tag.
+ Your YYSTYPE need not be a macro; it can be a typedef.
+ This change is for compatibility with other Yacc implementations,
+ and is required by POSIX.
+
* Locations columns and lines start at 1.
In accordance with the GNU Coding Standards and Emacs.
`%{ ... %}' syntax. To generate the pre-prologue, Bison concatenates all
prologue blocks that you've declared before the first %union. To generate
the post-prologue, Bison concatenates all prologue blocks that you've
- declared after the first %union.
+ declared after the first %union.
Previous releases of Bison inserted the pre-prologue into both the header
file and the code file in all cases except for LALR(1) parsers in C. In the
b4_token_enums(b4_tokens)
-[#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+[#ifndef YYSTYPE
]m4_ifdef([b4_stype],
-[typedef union b4_union_name
-b4_user_stype
- YYSTYPE;],
-[typedef int YYSTYPE;])[
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
+[[typedef union ]b4_union_name[
+]b4_user_stype[
+ YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1]],
+[m4_if(b4_tag_seen_flag, 0,
+[[typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1]])])[
#endif
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
[ union semantic_type
b4_user_stype
;],
-[ typedef int semantic_type;])[
+[m4_if(b4_tag_seen_flag, 0,
+[[ typedef int semantic_type;]],
+[[ typedef YYSTYPE semantic_type;]])])[
#else
typedef YYSTYPE semantic_type;
#endif
[ union semantic_type
b4_user_stype
;],
-[ typedef int semantic_type;])[
+[m4_if(b4_tag_seen_flag, 0,
+[[ typedef int semantic_type;]],
+[[ typedef YYSTYPE semantic_type;]])])[
#else
typedef YYSTYPE semantic_type;
#endif
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
]m4_ifdef([b4_stype],
-[[typedef union ]b4_union_name
-b4_user_stype
- YYSTYPE;],
-[typedef int YYSTYPE;])[
+[[typedef union ]b4_union_name[
+]b4_user_stype[
+ YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1]],
+[m4_if(b4_tag_seen_flag, 0,
+[[typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1]])])[
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
#endif
]b4_locations_if([#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
[#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
]m4_ifdef([b4_stype],
-[[typedef union ]b4_union_name
-b4_user_stype
- YYSTYPE;],
-[typedef int YYSTYPE;])[
+[[typedef union ]b4_union_name[
+]b4_user_stype[
+ YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1]],
+[m4_if(b4_tag_seen_flag, 0,
+[[typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1]])])[
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
#endif
]b4_pure_if([],
@acronym{RPN} and infix calculator examples (@pxref{RPN Calc, ,Reverse Polish
Notation Calculator}).
-Bison's default is to use type @code{int} for all semantic values. To
+Bison normally uses the type @code{int} for semantic values if your
+program uses the same data type for all language constructs. To
specify some other type, define @code{YYSTYPE} as a macro, like this:
@example
@itemize @bullet
@item
-Specify the entire collection of possible data types, with the
+Specify the entire collection of possible data types, either by using the
@code{%union} Bison declaration (@pxref{Union Decl, ,The Collection of
-Value Types}).
+Value Types}), or by using a @code{typedef} or a @code{#define} to
+define @code{YYSTYPE} to be a union type whose member names are
+the type tags.
@item
Choose one of those types for each symbol (terminal or nonterminal) for
You can specify the type of locations by defining a macro called
@code{YYLTYPE}, just as you can specify the semantic value type by
-defining @code{YYSTYPE} (@pxref{Value Type}).
+defining a @code{YYSTYPE} macro (@pxref{Value Type}).
When @code{YYLTYPE} is not defined, Bison uses a default structure type with
four members:
Note that, unlike making a @code{union} declaration in C, you need not write
a semicolon after the closing brace.
+Instead of @code{%union}, you can define and use your own union type
+@code{YYSTYPE} if your grammar contains at least one
+@samp{<@var{type}>} tag. For example, you can put the following into
+a header file @file{parser.h}:
+
+@example
+@group
+union YYSTYPE @{
+ double val;
+ symrec *tptr;
+@};
+typedef union YYSTYPE YYSTYPE;
+@end group
+@end example
+
+@noindent
+and then your grammar can use the following
+instead of @code{%union}:
+
+@example
+@group
+%@{
+#include "parser.h"
+%@}
+%type <val> expr
+%token <tptr> ID
+@end group
+@end example
+
@node Type Decl
@subsection Nonterminal Symbols
@cindex declaring value types, nonterminals
If the parser output file is named @file{@var{name}.c} then this file
is named @file{@var{name}.h}.
-Unless @code{YYSTYPE} is already defined as a macro, the output header
-declares @code{YYSTYPE}. Therefore, if you are using a @code{%union}
+For C parsers, the output header declares @code{YYSTYPE} unless unless
+@code{YYSTYPE} is already defined as a macro or you have used a
+@code{<@var{type}>} tag without using @code{%union}.
+Therefore, if you are using a @code{%union}
(@pxref{Multiple Types, ,More Than One Value Type}) with components that
require other definitions, or if you have defined a @code{YYSTYPE} macro
+or type definition
(@pxref{Value Type, ,Data Types of Semantic Values}), you need to
arrange for these definitions to be propagated to all modules, e.g., by
putting them in a prerequisite header that is included both by your
If you have also used locations, the output header declares
@code{YYLTYPE} and @code{yylloc} using a protocol similar to that of
-@code{YYSTYPE} and @code{yylval}. @xref{Locations, ,Tracking
+the @code{YYSTYPE} macro and @code{yylval}. @xref{Locations, ,Tracking
Locations}.
This output file is normally essential if you wish to put the definition
MUSCLE_INSERT_BOOL ("locations_flag", locations_flag);
MUSCLE_INSERT_BOOL ("pure_flag", pure_parser);
MUSCLE_INSERT_BOOL ("synclines_flag", !no_lines_flag);
+ MUSCLE_INSERT_BOOL ("tag_seen_flag", tag_seen);
MUSCLE_INSERT_BOOL ("yacc_flag", yacc_flag);
/* File names. */
static void add_param (char const *, char *, location);
static symbol_class current_class = unknown_sym;
-static uniqstr current_type = 0;
+static uniqstr current_type = NULL;
static symbol *current_lhs;
static location current_lhs_location;
static int current_prec = 0;
grammar_declaration
| PROLOGUE
{
- prologue_augment (translate_code ($1, @1), @1, typed);
+ prologue_augment (translate_code ($1, @1), @1, union_seen);
}
| "%after-header" "{...}"
{
{
char const *body = $3;
- if (typed)
+ if (union_seen)
{
/* Concatenate the union bodies, turning the first one's
trailing '}' into '\n', and omitting the second one's '{'. */
body++;
}
- typed = true;
+ union_seen = true;
muscle_code_grow ("stype", body, @3);
}
;
}
| "%type" TYPE symbols.1
{
+ tag_seen = true;
symbol_list *list;
for (list = $3; list; list = list->next)
symbol_type_set (list->sym, $2, @2);
type.opt:
/* Nothing. */ { current_type = NULL; }
-| TYPE { current_type = $1; }
+| TYPE { current_type = $1; tag_seen = true; }
;
/* One or more nonterminals to be %typed. */
TYPE
{
current_type = $1;
+ tag_seen = true;
}
| id
{
merger_list *merge_functions;
/* Was %union seen? */
-bool typed = false;
+bool union_seen = false;
+
+/* Was a tag seen? */
+bool tag_seen = false;
/* Should rules have a default precedence? */
bool default_prec = true;
extern merger_list *merge_functions;
/* Was %union seen? */
-extern bool typed;
+extern bool union_seen;
+
+/* Was a tag seen? */
+extern bool tag_seen;
/* Should rules have a default precedence? */
extern bool default_prec;
static void handle_action_at (symbol_list *rule, char *cp, location at_loc);
static location the_location;
static location *loc = &the_location;
+
+/* True if an untyped $$ or $n was seen. */
+static bool untyped_var_seen;
%}
/* C and C++ comments in code. */
%x SC_COMMENT SC_LINE_COMMENT
++cp;
*cp = '\0';
++cp;
+ if (untyped_var_seen)
+ complain_at (dollar_loc, _("explicit type given in untyped grammar"));
+ tag_seen = true;
}
if (*cp == '$')
{
if (!type_name)
type_name = symbol_list_n_type_name_get (rule, dollar_loc, 0);
- if (!type_name && typed)
+
+ if (!type_name)
{
- if (rule->midrule_parent_rule)
- complain_at (dollar_loc,
- _("$$ for the midrule at $%d of `%s' has no declared"
- " type"),
- rule->midrule_parent_rhs_index,
- effective_rule->sym->tag);
+ if (union_seen | tag_seen)
+ {
+ if (rule->midrule_parent_rule)
+ complain_at (dollar_loc,
+ _("$$ for the midrule at $%d of `%s'"
+ " has no declared type"),
+ rule->midrule_parent_rhs_index,
+ effective_rule->sym->tag);
+ else
+ complain_at (dollar_loc, _("$$ of `%s' has no declared type"),
+ rule->sym->tag);
+ }
else
- complain_at (dollar_loc, _("$$ of `%s' has no declared type"),
- rule->sym->tag);
+ untyped_var_seen = true;
+ type_name = "";
}
- if (!type_name)
- type_name = "";
+
obstack_fgrow1 (&obstack_for_string,
"]b4_lhs_value([%s])[", type_name);
rule->used = true;
}
else
{
- long int num;
- set_errno (0);
- num = strtol (cp, 0, 10);
- if (INT_MIN <= num && num <= effective_rule_length && ! get_errno ())
+ long int num = strtol (cp, NULL, 10);
+
+ if (1 - INT_MAX + effective_rule_length <= num
+ && num <= effective_rule_length)
{
int n = num;
- if (1-n > max_left_semantic_context)
- max_left_semantic_context = 1-n;
- if (!type_name && n > 0)
+ if (max_left_semantic_context < 1 - n)
+ max_left_semantic_context = 1 - n;
+ if (!type_name && 0 < n)
type_name =
symbol_list_n_type_name_get (effective_rule, dollar_loc, n);
- if (!type_name && typed)
- complain_at (dollar_loc, _("$%d of `%s' has no declared type"),
- n, effective_rule->sym->tag);
if (!type_name)
- type_name = "";
+ {
+ if (union_seen | tag_seen)
+ complain_at (dollar_loc, _("$%d of `%s' has no declared type"),
+ n, effective_rule->sym->tag);
+ else
+ untyped_var_seen = true;
+ type_name = "";
+ }
+
obstack_fgrow3 (&obstack_for_string,
"]b4_rhs_value(%d, %d, [%s])[",
effective_rule_length, n, type_name);
obstack_sgrow (&obstack_for_string, "]b4_lhs_location[");
else
{
- long int num;
- set_errno (0);
- num = strtol (cp, 0, 10);
+ long int num = strtol (cp, NULL, 10);
- if (INT_MIN <= num && num <= effective_rule_length && ! get_errno ())
+ if (1 - INT_MAX + effective_rule_length <= num
+ && num <= effective_rule_length)
{
int n = num;
obstack_fgrow2 (&obstack_for_string, "]b4_rhs_location(%d, %d)[",
| Initialize the scanner. |
`-------------------------*/
-/* Translate the dollars and ats in \a a, whose location is l.
- Depending on the \a sc_context (SC_RULE_ACTION, SC_SYMBOL_ACTION,
- INITIAL), the processing is different. */
+/* Translate the dollars and ats in \a a, whose location is \a l. The
+ translation is for \a rule, in the context \a sc_context
+ (SC_RULE_ACTION, SC_SYMBOL_ACTION, INITIAL). */
static const char *
translate_action (int sc_context, symbol_list *rule, const char *a, location l)
d: INT | INT { } INT { $]1[ } INT { };
e: INT | INT { } INT { } INT { $]1[ };
f: INT | INT { } INT { } INT { $]$[ = $]1[ + $]3[ + $]5[; };
-g: INT | INT { $]$[ } INT { $]$[ } INT { };
-h: INT | INT { $]$[ } INT { $]$[ = $]2[ } INT { };
+g: INT | INT { $<integer>$; } INT { $<integer>$; } INT { };
+h: INT | INT { $<integer>$; } INT { $<integer>$ = $<integer>2; } INT { };
i: INT | INT INT { } { $]$[ = $]1[ + $]2[; };
j: INT | INT INT { $<integer>$ = 1; } { $]$[ = $]1[ + $]2[; };
-k: INT | INT INT { $]$[; } { $]$[ = $]3[; } { };
-l: INT | INT { $]$[ = $]1[; } INT { $]$[ = $]2[ + $]3[; } INT { $]$[ = $]4[ + $]5[; };]]m4_ifval($1, [
+k: INT | INT INT { $<integer>$; } { $<integer>$ = $<integer>3; } { };
+l: INT | INT { $<integer>$ = $<integer>1; } INT { $<integer>$ = $<integer>2 + $<integer>3; } INT { $<integer>$ = $<integer>4 + $<integer>5; };]]m4_ifval($1, [
_AT_UNUSED_VALUES_DECLARATIONS])
)
input.y:15.10-36: warning: unset value: $]$[
input.y:15.10-36: warning: unused value: $]3[
input.y:15.10-36: warning: unused value: $]5[
-input.y:17.10-38: warning: unset value: $]$[
-input.y:17.10-38: warning: unused value: $]1[
-input.y:17.10-38: warning: unused value: $]2[
-input.y:17.10-38: warning: unused value: $]3[
-input.y:17.10-38: warning: unused value: $]4[
-input.y:17.10-38: warning: unused value: $]5[
-input.y:18.10-43: warning: unset value: $]$[
-input.y:18.10-43: warning: unused value: $]1[
-input.y:18.10-43: warning: unused value: $]3[
-input.y:18.10-43: warning: unused value: $]4[
-input.y:18.10-43: warning: unused value: $]5[
+input.y:17.10-58: warning: unset value: $]$[
+input.y:17.10-58: warning: unused value: $]1[
+input.y:17.10-58: warning: unused value: $]2[
+input.y:17.10-58: warning: unused value: $]3[
+input.y:17.10-58: warning: unused value: $]4[
+input.y:17.10-58: warning: unused value: $]5[
+input.y:18.10-72: warning: unset value: $]$[
+input.y:18.10-72: warning: unused value: $]1[
+input.y:18.10-72: warning: unused value: $]3[
+input.y:18.10-72: warning: unused value: $]4[
+input.y:18.10-72: warning: unused value: $]5[
input.y:20.10-55: warning: unused value: $]3[
-input.y:21.10-41: warning: unset value: $]$[
-input.y:21.10-41: warning: unused value: $]1[
-input.y:21.10-41: warning: unused value: $]2[
-input.y:21.10-41: warning: unused value: $]4[
+input.y:21.10-68: warning: unset value: $]$[
+input.y:21.10-68: warning: unused value: $]1[
+input.y:21.10-68: warning: unused value: $]2[
+input.y:21.10-68: warning: unused value: $]4[
]])])
+## ----------------- ##
+## YYSTYPE typedef. ##
+## ----------------- ##
+
+AT_SETUP([YYSTYPE typedef])
+
+AT_DATA_GRAMMAR([input.y],
+[[%{
+void yyerror (char const *);
+int yylex (void);
+typedef union { char const *val; } YYSTYPE;
+%}
+
+%type <val> program
+
+%%
+
+program: { $$ = ""; };
+]])
+
+AT_CHECK([bison -o input.c input.y])
+AT_COMPILE([input.o], [-c input.c])
+
+AT_CLEANUP
+
+
+
## ------------------------------------- ##
## Early token definitions with --yacc. ##
## ------------------------------------- ##