Merge remote-tracking branch 'origin/maint'

* origin/maint: (29 commits)
  regen
  synclines: remove spurious empty line
  also support $<foo>$ in the %initial-action
  skeletons: b4_dollar_pushdef and popdef to simpify complex definitions
  regen
  printer/destructor: translate only once
  factor the handling of m4 escaping
  news: schedule the removal of the ";" hack
  style changes in the scanners
  regen
  support $<tag>$ in printers and destructors
  scan-code: factor the handling of the type in $<TYPE>$
  muscles: fix another occurrence of unescaped type name
  glr.cc: fix the handling of yydebug
  gnulib: update
  formatting changes
  tests: fix an assertion
  tests: adjust to GCC 4.8, which displays caret errors
  be sure to properly escape type names
  obstack_quote: escape and quote for M4
  muscles: shuffle responsabilities
  muscles: make private functions static
  muscles: rename private functions/macros
  obstack_escape: escape M4 characters
  remove dead macro
  maint: style changes
  doc: avoid problems with case insensitive file systems
  configure: fix botched quoting
  news: fix typo.

Conflicts:
	NEWS
	data/c.m4
	data/glr.cc
	data/lalr1.cc
	examples/rpcalc/local.mk
	src/muscle-tab.h
	src/output.c
	src/parse-gram.c
	src/parse-gram.h
	src/parse-gram.y
	src/scan-code.l
	src/symlist.c
	src/symlist.h
	src/symtab.h
	tests/calc.at
This commit is contained in:
Akim Demaille
2012-07-27 16:22:45 +02:00
32 changed files with 669 additions and 294 deletions

2
.gitignore vendored
View File

@@ -11,6 +11,7 @@
/INSTALL /INSTALL
/Makefile /Makefile
/Makefile.in /Makefile.in
/README-release
/_* /_*
/a.exe /a.exe
/a.out /a.out
@@ -31,4 +32,3 @@
/patches /patches
/releases /releases
/stamp-h* /stamp-h*
/README-release

37
NEWS
View File

@@ -129,6 +129,41 @@ GNU Bison NEWS
* Noteworthy changes in release ?.? (????-??-??) [?] * Noteworthy changes in release ?.? (????-??-??) [?]
Bison no longer executes user-specified M4 code when processing a grammar.
** Future Changes
In addition to the removal of the features announced in Bison 2.6, the
next major release will remove the "Temporary hack for adding a semicolon
to the user action", as announced in the release 2.5. Instead of:
exp: exp "+" exp { $$ = $1 + $3 };
write:
exp: exp "+" exp { $$ = $1 + $3; };
** Bug fixes
*** Type names are now properly escaped.
*** glr.cc: set_debug_level and debug_level work as expected.
*** Stray @ or $ in actions
While Bison used to warn about stray $ or @ in action rules, it did not
for other actions such as printers, destructors, or initial actions. It
now does.
** Type names in actions
For consistency with rule actions, it is now possible to qualify $$ by a
type-name in destructors, printers, and initial actions. For instance:
%printer { fprintf (yyo, "(%d, %f)", $<ival>$, $<fval>$); } <*> <>;
will display two values for each typed and untyped symbol (provided
that YYSTYPE has both "ival" and "fval" fields).
* Noteworthy changes in release 2.6 (2012-07-19) [stable] * Noteworthy changes in release 2.6 (2012-07-19) [stable]
@@ -137,7 +172,7 @@ GNU Bison NEWS
The next major release of Bison will drop support for the following The next major release of Bison will drop support for the following
deprecated features. Please report disagreements to bug-bison@gnu.org. deprecated features. Please report disagreements to bug-bison@gnu.org.
*** K&C parsers *** K&R C parsers
Support for generating parsers in K&R C will be removed. Parsers Support for generating parsers in K&R C will be removed. Parsers
generated for C support ISO C90, and are tested with ISO C99 and ISO C11 generated for C support ISO C90, and are tested with ISO C99 and ISO C11

1
THANKS
View File

@@ -13,6 +13,7 @@ Anthony Heading ajrh@ajrh.net
Arnold Robbins arnold@skeeve.com Arnold Robbins arnold@skeeve.com
Art Haas ahaas@neosoft.com Art Haas ahaas@neosoft.com
Baron Schwartz baron@sequent.org Baron Schwartz baron@sequent.org
Ben Pfaff blp@cs.stanford.edu
Benoit Perrot benoit.perrot@epita.fr Benoit Perrot benoit.perrot@epita.fr
Bernd Kiefer kiefer@dfki.de Bernd Kiefer kiefer@dfki.de
Bert Deknuydt Bert.Deknuydt@esat.kuleuven.ac.be Bert Deknuydt Bert.Deknuydt@esat.kuleuven.ac.be

4
TODO
View File

@@ -1,4 +1,8 @@
* Short term * Short term
** scan-code.l
Avoid variables for format strings, as then GCC cannot check them.
show_sub_messages should call show_sub_message.
** Variable names. ** Variable names.
What should we name `variant' and `lex_symbol'? What should we name `variant' and `lex_symbol'?

View File

@@ -177,7 +177,7 @@ case $VALGRIND:$host_os in
# VALGRIND+=' --suppressions=$(abs_top_srcdir)/build-aux/darwin11.4.0.valgrind' # VALGRIND+=' --suppressions=$(abs_top_srcdir)/build-aux/darwin11.4.0.valgrind'
VALGRIND=;; VALGRIND=;;
*:*) *:*)
AC_SUBST([VALGRIND_PREBISON], [$VALGRIND -q]);; AC_SUBST([VALGRIND_PREBISON], ["$VALGRIND -q"]);;
esac esac
AM_MISSING_PROG([AUTOM4TE], [autom4te]) AM_MISSING_PROG([AUTOM4TE], [autom4te])

View File

@@ -376,19 +376,17 @@ m4_define([b4_symbol_action_location],
# Same as in C, but using references instead of pointers. # Same as in C, but using references instead of pointers.
m4_define([b4_symbol_action], m4_define([b4_symbol_action],
[b4_symbol_if([$1], [has_$2], [b4_symbol_if([$1], [has_$2],
[m4_pushdef([b4_dollar_dollar], [b4_dollar_pushdef([(*yyvaluep)],
[b4_symbol_value([(*yyvaluep)], b4_symbol_if([$1], [has_type],
b4_symbol_if([$1], [has_type], [m4_dquote(b4_symbol([$1], [type]))]),
[b4_symbol([$1], [type])]))])dnl [(*yylocationp)])dnl
m4_pushdef([b4_at_dollar], [(*yylocationp)])dnl
b4_symbol_case_([$1])[]dnl b4_symbol_case_([$1])[]dnl
b4_syncline([b4_symbol([$1], [$2_line])], ["b4_symbol([$1], [$2_file])"]) b4_syncline([b4_symbol([$1], [$2_line])], ["b4_symbol([$1], [$2_file])"])
b4_symbol([$1], [$2]) b4_symbol([$1], [$2])
b4_syncline([@oline@], [@ofile@]) b4_syncline([@oline@], [@ofile@])
break; break;
m4_popdef([b4_at_dollar])dnl b4_dollar_popdef[]dnl
m4_popdef([b4_dollar_dollar])dnl
])]) ])])

43
data/c-like.m4 Normal file
View File

@@ -0,0 +1,43 @@
-*- Autoconf -*-
# Common code for C-like languages (C, C++, Java, etc.)
# Copyright (C) 2012 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# b4_dollar_dollar_(VALUE, FIELD, DEFAULT-FIELD)
# ----------------------------------------------
# If FIELD (or DEFAULT-FIELD) is non-null, return "VALUE.FIELD",
# otherwise just VALUE. Be sure to pass "(VALUE)" is VALUE is a
# pointer.
m4_define([b4_dollar_dollar_],
[b4_symbol_value([$1],
m4_if([$2], [[]],
[[$3]], [[$2]]))])
# b4_dollar_pushdef(VALUE-POINTER, DEFAULT-FIELD, LOCATION)
# b4_dollar_popdef
# ---------------------------------------------------------
# Define b4_dollar_dollar for VALUE and DEFAULT-FIELD,
# and b4_at_dollar for LOCATION.
m4_define([b4_dollar_pushdef],
[m4_pushdef([b4_dollar_dollar],
[b4_dollar_dollar_([$1], m4_dquote($][1), [$2])])dnl
m4_pushdef([b4_at_dollar], [$3])dnl
])
m4_define([b4_dollar_popdef],
[m4_popdef([b4_at_dollar])dnl
m4_popdef([b4_dollar_dollar])dnl
])

View File

@@ -17,6 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
m4_include(b4_pkgdatadir/[c-like.m4])
# b4_tocpp(STRING) # b4_tocpp(STRING)
# ---------------- # ----------------

View File

@@ -2294,12 +2294,10 @@ yyrecoverSyntaxError (yyGLRStack* yystackp]b4_user_formals[)
#endif #endif
]) ])
m4_ifdef([b4_initial_action], [ m4_ifdef([b4_initial_action], [
m4_pushdef([b4_at_dollar], [yylloc])dnl b4_dollar_pushdef([yylval], [], [yylloc])dnl
m4_pushdef([b4_dollar_dollar], [yylval])dnl
/* User initialization code. */ /* User initialization code. */
b4_user_initial_action b4_user_initial_action
m4_popdef([b4_dollar_dollar])dnl b4_dollar_popdef])[]dnl
m4_popdef([b4_at_dollar])])dnl
[ [
if (! yyinitGLRStack (yystackp, YYINITDEPTH)) if (! yyinitGLRStack (yystackp, YYINITDEPTH))
goto yyexhaustedlab; goto yyexhaustedlab;

View File

@@ -202,6 +202,7 @@ m4_pushdef([b4_parse_param], m4_defn([b4_parse_param_orig]))dnl
void void
]b4_parser_class_name[::set_debug_level (debug_level_type l) ]b4_parser_class_name[::set_debug_level (debug_level_type l)
{ {
// Actually, it is yydebug which is really used.
yydebug = l; yydebug = l;
} }

View File

@@ -17,6 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
m4_include(b4_pkgdatadir/[c-like.m4])
# b4_comment(TEXT) # b4_comment(TEXT)
# ---------------- # ----------------

View File

@@ -98,19 +98,19 @@ m4_define([b4_rhs_location],
# Same as in C, but using references instead of pointers. # Same as in C, but using references instead of pointers.
m4_define([b4_symbol_action], m4_define([b4_symbol_action],
[b4_symbol_if([$1], [has_$2], [b4_symbol_if([$1], [has_$2],
[m4_pushdef([b4_dollar_dollar], [m4_pushdef([b4_symbol_value], m4_defn([b4_symbol_value_template]))[]dnl
[b4_symbol_value_template([yysym.value], b4_dollar_pushdef([yysym.value],
b4_symbol_if([$1], [has_type], b4_symbol_if([$1], [has_type],
[b4_symbol([$1], [type])]))])dnl [m4_dquote(b4_symbol([$1], [type]))]),
m4_pushdef([b4_at_dollar], [yysym.location])dnl [yysym.location])dnl
b4_symbol_case_([$1]) b4_symbol_case_([$1])
b4_syncline([b4_symbol([$1], [$2_line])], ["b4_symbol([$1], [$2_file])"]) b4_syncline([b4_symbol([$1], [$2_line])], ["b4_symbol([$1], [$2_file])"])
b4_symbol([$1], [$2]) b4_symbol([$1], [$2])
b4_syncline([@oline@], [@ofile@]) b4_syncline([@oline@], [@ofile@])
break; break;
m4_popdef([b4_at_dollar])dnl m4_popdef([b4_symbol_value])[]dnl
m4_popdef([b4_dollar_dollar])dnl b4_dollar_popdef[]dnl
])]) ])])
@@ -670,12 +670,10 @@ m4_if(b4_prefix, [yy], [],
YYCDEBUG << "Starting parse" << std::endl; YYCDEBUG << "Starting parse" << std::endl;
]m4_ifdef([b4_initial_action], [ ]m4_ifdef([b4_initial_action], [
m4_pushdef([b4_at_dollar], [yyla.location])dnl b4_dollar_pushdef([yyla.value], [], [yyla.location])dnl
m4_pushdef([b4_dollar_dollar], [yyla.value])dnl
/* User initialization code. */ /* User initialization code. */
b4_user_initial_action b4_user_initial_action
m4_popdef([b4_dollar_dollar])dnl b4_dollar_popdef])[]dnl
m4_popdef([b4_at_dollar])])dnl
[ /* Initialize the stack. The initial state will be set in [ /* Initialize the stack. The initial state will be set in
yynewstate, since the latter expects the semantical and the yynewstate, since the latter expects the semantical and the

View File

@@ -502,12 +502,10 @@ b4_lexer_if([[
yyerrstatus_ = 0; yyerrstatus_ = 0;
]m4_ifdef([b4_initial_action], [ ]m4_ifdef([b4_initial_action], [
m4_pushdef([b4_at_dollar], [yylloc])dnl b4_dollar_pushdef([yylval], [], [yylloc])dnl
m4_pushdef([b4_dollar_dollar], [yylval])dnl
/* User initialization code. */ /* User initialization code. */
b4_user_initial_action b4_user_initial_action
m4_popdef([b4_dollar_dollar])dnl b4_dollar_popdef])[]dnl
m4_popdef([b4_at_dollar])])dnl
[ /* Initialize the stack. */ [ /* Initialize the stack. */
yystack.push (yystate, yylval]b4_locations_if([, yylloc])[); yystack.push (yystate, yylval]b4_locations_if([, yylloc])[);

View File

@@ -18,6 +18,7 @@ dist_pkgdata_DATA = \
data/bison.m4 \ data/bison.m4 \
data/c++-skel.m4 \ data/c++-skel.m4 \
data/c++.m4 \ data/c++.m4 \
data/c-like.m4 \
data/c-skel.m4 \ data/c-skel.m4 \
data/c.m4 \ data/c.m4 \
data/glr.c \ data/glr.c \

View File

@@ -1484,17 +1484,16 @@ b4_c_function_def([[yyparse]], [[int]], b4_parse_param)[
yylloc.first_column = yylloc.last_column = ]b4_location_initial_column[; yylloc.first_column = yylloc.last_column = ]b4_location_initial_column[;
#endif]]) #endif]])
m4_ifdef([b4_initial_action],[ m4_ifdef([b4_initial_action],[
m4_pushdef([b4_at_dollar], [m4_define([b4_at_dollar_used])yylloc])dnl b4_dollar_pushdef([m4_define([b4_dollar_dollar_used])yylval], [],
m4_pushdef([b4_dollar_dollar], [m4_define([b4_dollar_dollar_used])yylval])dnl [m4_define([b4_at_dollar_used])yylloc])dnl
/* User initialization code. */ /* User initialization code. */
b4_user_initial_action b4_user_initial_action
m4_popdef([b4_dollar_dollar])dnl b4_dollar_popdef[]dnl
m4_popdef([b4_at_dollar])])dnl
m4_ifdef([b4_dollar_dollar_used],[[ yyvsp[0] = yylval; m4_ifdef([b4_dollar_dollar_used],[[ yyvsp[0] = yylval;
]])dnl ]])dnl
m4_ifdef([b4_at_dollar_used], [[ yylsp[0] = yylloc; m4_ifdef([b4_at_dollar_used], [[ yylsp[0] = yylloc;
]])[ ]])])dnl
goto yysetstate; [ goto yysetstate;
/*------------------------------------------------------------. /*------------------------------------------------------------.
| yynewstate -- Push a new state, which is found in yystate. | | yynewstate -- Push a new state, which is found in yystate. |

View File

@@ -110,7 +110,7 @@ Reference sections:
* Glossary:: Basic concepts are explained. * Glossary:: Basic concepts are explained.
* Copying This Manual:: License for copying this manual. * Copying This Manual:: License for copying this manual.
* Bibliography:: Publications cited in this manual. * Bibliography:: Publications cited in this manual.
* Index:: Cross-references to the text. * Index of Terms:: Cross-references to the text.
@detailmenu @detailmenu
--- The Detailed Node Listing --- --- The Detailed Node Listing ---
@@ -4634,9 +4634,9 @@ code.
@deffn {Directive} %initial-action @{ @var{code} @} @deffn {Directive} %initial-action @{ @var{code} @}
@findex %initial-action @findex %initial-action
Declare that the braced @var{code} must be invoked before parsing each time Declare that the braced @var{code} must be invoked before parsing each time
@code{yyparse} is called. The @var{code} may use @code{$$} and @code{yyparse} is called. The @var{code} may use @code{$$} (or
@code{@@$} --- initial value and location of the lookahead --- and the @code{$<@var{tag}>$}) and @code{@@$} --- initial value and location of the
@code{%parse-param}. lookahead --- and the @code{%parse-param}.
@end deffn @end deffn
For instance, if your locations use a file name, you may use For instance, if your locations use a file name, you may use
@@ -4674,11 +4674,11 @@ symbol is automatically discarded.
@deffn {Directive} %destructor @{ @var{code} @} @var{symbols} @deffn {Directive} %destructor @{ @var{code} @} @var{symbols}
@findex %destructor @findex %destructor
Invoke the braced @var{code} whenever the parser discards one of the Invoke the braced @var{code} whenever the parser discards one of the
@var{symbols}. @var{symbols}. Within @var{code}, @code{$$} (or @code{$<@var{tag}>$})
Within @var{code}, @code{$$} designates the semantic value associated designates the semantic value associated with the discarded symbol, and
with the discarded symbol, and @code{@@$} designates its location. @code{@@$} designates its location. The additional parser parameters are
The additional parser parameters are also available (@pxref{Parser Function, , also available (@pxref{Parser Function, , The Parser Function
The Parser Function @code{yyparse}}). @code{yyparse}}).
When a symbol is listed among @var{symbols}, its @code{%destructor} is called a When a symbol is listed among @var{symbols}, its @code{%destructor} is called a
per-symbol @code{%destructor}. per-symbol @code{%destructor}.
@@ -4816,10 +4816,11 @@ Decl, , Freeing Discarded Symbols}).
@c This is the same text as for %destructor. @c This is the same text as for %destructor.
Invoke the braced @var{code} whenever the parser displays one of the Invoke the braced @var{code} whenever the parser displays one of the
@var{symbols}. Within @var{code}, @code{yyoutput} denotes the output stream @var{symbols}. Within @var{code}, @code{yyoutput} denotes the output stream
(a @code{FILE*} in C, and an @code{std::ostream&} in C++), (a @code{FILE*} in C, and an @code{std::ostream&} in C++), @code{$$} (or
@code{$$} designates the semantic value associated with the symbol, and @code{$<@var{tag}>$}) designates the semantic value associated with the
@code{@@$} its location. The additional parser parameters are also symbol, and @code{@@$} its location. The additional parser parameters are
available (@pxref{Parser Function, , The Parser Function @code{yyparse}}). also available (@pxref{Parser Function, , The Parser Function
@code{yyparse}}).
The @var{symbols} are defined as for @code{%destructor} (@pxref{Destructor The @var{symbols} are defined as for @code{%destructor} (@pxref{Destructor
Decl, , Freeing Discarded Symbols}.): they can be per-type (e.g., Decl, , Freeing Discarded Symbols}.): they can be per-type (e.g.,
@@ -12375,8 +12376,8 @@ London, Department of Computer Science, TR-00-12 (December 2000).
@uref{http://www.cs.rhul.ac.uk/research/languages/publications/tomita_style_1.ps} @uref{http://www.cs.rhul.ac.uk/research/languages/publications/tomita_style_1.ps}
@end table @end table
@node Index @node Index of Terms
@unnumbered Index @unnumbered Index of Terms
@printindex cp @printindex cp

2
gnulib

Submodule gnulib updated: 2f67aa79c6...dbd914496c

View File

@@ -177,10 +177,10 @@ static void
muscle_syncline_grow (char const *key, location loc) muscle_syncline_grow (char const *key, location loc)
{ {
char *extension = NULL; char *extension = NULL;
obstack_fgrow1 (&muscle_obstack, "]b4_syncline(%d, [[", loc.start.line); obstack_fgrow1 (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
MUSCLE_OBSTACK_SGROW (&muscle_obstack, obstack_quote (&muscle_obstack,
quotearg_style (c_quoting_style, loc.start.file)); quotearg_style (c_quoting_style, loc.start.file));
obstack_sgrow (&muscle_obstack, "]])["); obstack_sgrow (&muscle_obstack, ")[");
obstack_1grow (&muscle_obstack, 0); obstack_1grow (&muscle_obstack, 0);
extension = obstack_finish (&muscle_obstack); extension = obstack_finish (&muscle_obstack);
muscle_grow (key, extension, ""); muscle_grow (key, extension, "");
@@ -205,11 +205,11 @@ void muscle_pair_list_grow (const char *muscle,
const char *a1, const char *a2) const char *a1, const char *a2)
{ {
char *pair; char *pair;
obstack_sgrow (&muscle_obstack, "[[["); obstack_sgrow (&muscle_obstack, "[");
MUSCLE_OBSTACK_SGROW (&muscle_obstack, a1); obstack_quote (&muscle_obstack, a1);
obstack_sgrow (&muscle_obstack, "]], [["); obstack_sgrow (&muscle_obstack, ", ");
MUSCLE_OBSTACK_SGROW (&muscle_obstack, a2); obstack_quote (&muscle_obstack, a2);
obstack_sgrow (&muscle_obstack, "]]]"); obstack_sgrow (&muscle_obstack, "]");
obstack_1grow (&muscle_obstack, 0); obstack_1grow (&muscle_obstack, 0);
pair = obstack_finish (&muscle_obstack); pair = obstack_finish (&muscle_obstack);
muscle_grow (muscle, pair, ",\n"); muscle_grow (muscle, pair, ",\n");
@@ -259,53 +259,61 @@ muscle_find (char const *key)
} }
void /* In the format `file_name:line.column', append BOUND to MUSCLE. Use
digraphs for special characters in the file name. */
static void
muscle_boundary_grow (char const *key, boundary bound) muscle_boundary_grow (char const *key, boundary bound)
{ {
char *extension; char *extension;
MUSCLE_OBSTACK_SGROW (&muscle_obstack, bound.file); obstack_sgrow (&muscle_obstack, "[[");
obstack_escape (&muscle_obstack, bound.file);
obstack_1grow (&muscle_obstack, ':'); obstack_1grow (&muscle_obstack, ':');
obstack_fgrow1 (&muscle_obstack, "%d", bound.line); obstack_fgrow1 (&muscle_obstack, "%d", bound.line);
obstack_1grow (&muscle_obstack, '.'); obstack_1grow (&muscle_obstack, '.');
obstack_fgrow1 (&muscle_obstack, "%d", bound.column); obstack_fgrow1 (&muscle_obstack, "%d", bound.column);
obstack_sgrow (&muscle_obstack, "]]");
obstack_1grow (&muscle_obstack, '\0'); obstack_1grow (&muscle_obstack, '\0');
extension = obstack_finish (&muscle_obstack); extension = obstack_finish (&muscle_obstack);
muscle_grow (key, extension, ""); muscle_grow (key, extension, "");
obstack_free (&muscle_obstack, extension); obstack_free (&muscle_obstack, extension);
} }
void
/* In the format `[[file_name:line.column]], [[file_name:line.column]]',
append LOC to MUSCLE. Use digraphs for special characters in each
file name. */
static void
muscle_location_grow (char const *key, location loc) muscle_location_grow (char const *key, location loc)
{ {
muscle_grow (key, "[[", "");
muscle_boundary_grow (key, loc.start); muscle_boundary_grow (key, loc.start);
muscle_grow (key, "]], [[", ""); muscle_grow (key, "", ", ");
muscle_boundary_grow (key, loc.end); muscle_boundary_grow (key, loc.end);
muscle_grow (key, "]]", "");
} }
#define MUSCLE_COMMON_DECODE(Value) \ #define COMMON_DECODE(Value) \
case '$': \ case '$': \
aver (*++(Value) == ']'); \ aver (*++(Value) == ']'); \
aver (*++(Value) == '['); \ aver (*++(Value) == '['); \
obstack_sgrow (&muscle_obstack, "$"); \ obstack_sgrow (&muscle_obstack, "$"); \
break; \ break; \
case '@': \ case '@': \
switch (*++(Value)) \ switch (*++(Value)) \
{ \ { \
case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \ case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \ case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \ case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
default: aver (false); break; \ default: aver (false); break; \
} \ } \
break; \ break; \
default: \ default: \
obstack_1grow (&muscle_obstack, *(Value)); \ obstack_1grow (&muscle_obstack, *(Value)); \
break; break;
/* Reverse of MUSCLE_OBSTACK_SGROW. */ /* Reverse of obstack_escape. */
static char * static char *
muscle_string_decode (char const *key) string_decode (char const *key)
{ {
char const *value; char const *value;
char *value_decoded; char *value_decoded;
@@ -317,7 +325,7 @@ muscle_string_decode (char const *key)
do { do {
switch (*value) switch (*value)
{ {
MUSCLE_COMMON_DECODE (value) COMMON_DECODE (value)
case '[': case '[':
case ']': case ']':
aver (false); aver (false);
@@ -332,7 +340,7 @@ muscle_string_decode (char const *key)
/* Reverse of muscle_location_grow. */ /* Reverse of muscle_location_grow. */
static location static location
muscle_location_decode (char const *key) location_decode (char const *key)
{ {
location loc; location loc;
char const *value = muscle_find_const (key); char const *value = muscle_find_const (key);
@@ -342,7 +350,7 @@ muscle_location_decode (char const *key)
while (*++value) while (*++value)
switch (*value) switch (*value)
{ {
MUSCLE_COMMON_DECODE (value) COMMON_DECODE (value)
case '[': case '[':
aver (false); aver (false);
break; break;
@@ -491,7 +499,7 @@ muscle_percent_define_get (char const *variable)
variable, ")"); variable, ")");
muscle_insert (usage_name, ""); muscle_insert (usage_name, "");
value = muscle_string_decode (name); value = string_decode (name);
if (!value) if (!value)
value = xstrdup (""); value = xstrdup ("");
return value; return value;
@@ -505,7 +513,7 @@ muscle_percent_define_get_loc (char const *variable)
if (!muscle_find_const (loc_name)) if (!muscle_find_const (loc_name))
complain (fatal, _("%s: undefined %%define variable %s"), complain (fatal, _("%s: undefined %%define variable %s"),
"muscle_percent_define_get_loc", quote (variable)); "muscle_percent_define_get_loc", quote (variable));
return muscle_location_decode (loc_name); return location_decode (loc_name);
} }
char const * char const *
@@ -610,7 +618,7 @@ muscle_percent_define_check_values (char const * const *values)
name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")"); name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
value = muscle_string_decode (name); value = string_decode (name);
if (value) if (value)
{ {
for (++values; *values; ++values) for (++values; *values; ++values)

View File

@@ -35,63 +35,48 @@ void muscle_free (void);
extern struct obstack muscle_obstack; extern struct obstack muscle_obstack;
#define MUSCLE_INSERT_BOOL(Key, Value) \ #define MUSCLE_INSERT_BOOL(Key, Value) \
do { \ do { \
int v__ = Value; \ int v__ = Value; \
MUSCLE_INSERT_INT (Key, v__); \ MUSCLE_INSERT_INT (Key, v__); \
} while(0) } while (0)
#define MUSCLE_INSERT_INT(Key, Value) \ #define MUSCLE_INSERT_INT(Key, Value) \
do { \ do { \
obstack_fgrow1 (&muscle_obstack, "%d", Value); \ obstack_fgrow1 (&muscle_obstack, "%d", Value); \
obstack_1grow (&muscle_obstack, 0); \ obstack_1grow (&muscle_obstack, 0); \
muscle_insert (Key, obstack_finish (&muscle_obstack)); \ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
} while(0) } while (0)
#define MUSCLE_INSERT_LONG_INT(Key, Value) \ #define MUSCLE_INSERT_LONG_INT(Key, Value) \
do { \ do { \
obstack_fgrow1 (&muscle_obstack, "%ld", Value); \ obstack_fgrow1 (&muscle_obstack, "%ld", Value); \
obstack_1grow (&muscle_obstack, 0); \ obstack_1grow (&muscle_obstack, 0); \
muscle_insert (Key, obstack_finish (&muscle_obstack)); \ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
} while(0) } while (0)
/* Key -> Value, but don't apply escaping to Value. */ /* Key -> Value, but don't apply escaping to Value. */
#define MUSCLE_INSERT_STRING_RAW(Key, Value) \ #define MUSCLE_INSERT_STRING_RAW(Key, Value) \
do { \ do { \
obstack_sgrow (&muscle_obstack, Value); \ obstack_sgrow (&muscle_obstack, Value); \
obstack_1grow (&muscle_obstack, 0); \ obstack_1grow (&muscle_obstack, 0); \
muscle_insert (Key, obstack_finish (&muscle_obstack)); \ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
} while(0) } while (0)
/* Key -> Value, applying M4 escaping to Value. */ /* Key -> Value, applying M4 escaping to Value. */
#define MUSCLE_INSERT_STRING(Key, Value) \ #define MUSCLE_INSERT_STRING(Key, Value) \
do { \ do { \
MUSCLE_OBSTACK_SGROW (&muscle_obstack, Value); \ obstack_escape (&muscle_obstack, Value); \
obstack_1grow (&muscle_obstack, 0); \ obstack_1grow (&muscle_obstack, 0); \
muscle_insert (Key, obstack_finish (&muscle_obstack)); \ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
} while(0) } while (0)
#define MUSCLE_OBSTACK_SGROW(Obstack, Value) \
do { \
char const *p__; \
for (p__ = Value; *p__; p__++) \
switch (*p__) \
{ \
case '$': obstack_sgrow (Obstack, "$]["); break; \
case '@': obstack_sgrow (Obstack, "@@" ); break; \
case '[': obstack_sgrow (Obstack, "@{" ); break; \
case ']': obstack_sgrow (Obstack, "@}" ); break; \
default: obstack_1grow (Obstack, *p__); break; \
} \
} while(0)
#define MUSCLE_INSERT_C_STRING(Key, Value) \ #define MUSCLE_INSERT_C_STRING(Key, Value) \
do { \ do { \
MUSCLE_OBSTACK_SGROW (&muscle_obstack, \ obstack_escape (&muscle_obstack, \
quotearg_style (c_quoting_style, \ quotearg_style (c_quoting_style, Value)); \
Value)); \ obstack_1grow (&muscle_obstack, 0); \
obstack_1grow (&muscle_obstack, 0); \ muscle_insert (Key, obstack_finish (&muscle_obstack)); \
muscle_insert (Key, obstack_finish (&muscle_obstack)); \ } while (0)
} while(0)
/* Append VALUE to the current value of KEY. If KEY did not already /* Append VALUE to the current value of KEY. If KEY did not already
exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously
@@ -113,14 +98,6 @@ void muscle_code_grow (const char *key, const char *value, location loc);
void muscle_pair_list_grow (const char *muscle, void muscle_pair_list_grow (const char *muscle,
const char *a1, const char *a2); const char *a1, const char *a2);
/* In the format `[[file_name:line.column]], [[file_name:line.column]]', append
LOC to MUSCLE. Use digraphs for special characters in each file name. */
void muscle_location_grow (char const *key, location loc);
/* In the format `file_name:line.column', append BOUND to MUSCLE. Use digraphs
for special characters in the file name. */
void muscle_boundary_grow (char const *key, boundary bound);
/* Grow KEY for the occurrence of the name USER_NAME at LOC appropriately for /* Grow KEY for the occurrence of the name USER_NAME at LOC appropriately for
use with b4_check_user_names in ../data/bison.m4. USER_NAME is not escaped use with b4_check_user_names in ../data/bison.m4. USER_NAME is not escaped
with digraphs, so it must not contain `[' or `]'. */ with digraphs, so it must not contain `[' or `]'. */

View File

@@ -108,29 +108,39 @@ GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_symbol_number_table, symbol_number)
GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_state_number_table, state_number) GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_state_number_table, state_number)
/*--------------------------------------------------------------------. /*----------------------------------------------------------------.
| Print to OUT a representation of STRING escaped both for C and M4. | | Print to OUT a representation of CP quoted and escaped for M4. |
`--------------------------------------------------------------------*/ `----------------------------------------------------------------*/
static void static void
escaped_output (FILE *out, char const *string) quoted_output (FILE *out, char const *cp)
{ {
char const *p;
fprintf (out, "[["); fprintf (out, "[[");
for (p = quotearg_style (c_quoting_style, string); *p; p++) for (; *cp; cp++)
switch (*p) switch (*cp)
{ {
case '$': fputs ("$][", out); break; case '$': fputs ("$][", out); break;
case '@': fputs ("@@", out); break; case '@': fputs ("@@", out); break;
case '[': fputs ("@{", out); break; case '[': fputs ("@{", out); break;
case ']': fputs ("@}", out); break; case ']': fputs ("@}", out); break;
default: fputc (*p, out); break; default: fputc (*cp, out); break;
} }
fprintf (out, "]]"); fprintf (out, "]]");
} }
/*----------------------------------------------------------------.
| Print to OUT a representation of STRING quoted and escaped both |
| for C and M4. |
`----------------------------------------------------------------*/
static void
string_output (FILE *out, char const *string)
{
quoted_output (out, quotearg_style (c_quoting_style, string));
}
/*------------------------------------------------------------------. /*------------------------------------------------------------------.
| Prepare the muscles related to the symbols: translate, tname, and | | Prepare the muscles related to the symbols: translate, tname, and |
@@ -174,7 +184,7 @@ prepare_symbols (void)
if (i) if (i)
obstack_1grow (&format_obstack, ' '); obstack_1grow (&format_obstack, ' ');
MUSCLE_OBSTACK_SGROW (&format_obstack, cp); obstack_escape (&format_obstack, cp);
free (cp); free (cp);
obstack_1grow (&format_obstack, ','); obstack_1grow (&format_obstack, ',');
j += width; j += width;
@@ -355,7 +365,7 @@ user_actions_output (FILE *out)
fprintf (out, "b4_%scase(%d, [b4_syncline(%d, ", fprintf (out, "b4_%scase(%d, [b4_syncline(%d, ",
rules[r].is_predicate ? "predicate_" : "", rules[r].is_predicate ? "predicate_" : "",
r + 1, rules[r].action_location.start.line); r + 1, rules[r].action_location.start.line);
escaped_output (out, rules[r].action_location.start.file); string_output (out, rules[r].action_location.start.file);
fprintf (out, ")\n[ %s]])\n\n", rules[r].action); fprintf (out, ")\n[ %s]])\n\n", rules[r].action);
} }
fputs ("])\n\n", out); fputs ("])\n\n", out);

View File

@@ -389,10 +389,15 @@ grammar_declaration:
} }
| code_props_type "{...}" generic_symlist | code_props_type "{...}" generic_symlist
{ {
symbol_list *list; code_props code;
for (list = $3; list; list = list->next) code_props_symbol_action_init (&code, $2, @2);
symbol_list_code_props_set (list, $1, @2, $2); code_props_translate_code (&code);
symbol_list_free ($3); {
symbol_list *list;
for (list = $3; list; list = list->next)
symbol_list_code_props_set (list, $1, &code);
symbol_list_free ($3);
}
} }
| "%default-prec" | "%default-prec"
{ {

View File

@@ -45,7 +45,10 @@ typedef struct code_props {
CODE_PROPS_SYMBOL_ACTION, CODE_PROPS_RULE_ACTION CODE_PROPS_SYMBOL_ACTION, CODE_PROPS_RULE_ACTION
} kind; } kind;
/** \c NULL iff \c code_props::kind is \c CODE_PROPS_NONE. */ /**
* \c NULL iff \c code_props::kind is \c CODE_PROPS_NONE.
* Memory is allocated in an obstack freed elsewhere.
*/
char const *code; char const *code;
/** Undefined iff \c code_props::code is \c NULL. */ /** Undefined iff \c code_props::code is \c NULL. */
location location; location location;

View File

@@ -47,6 +47,9 @@ YY_DECL;
#define YY_USER_ACTION location_compute (loc, &loc->end, yytext, yyleng); #define YY_USER_ACTION location_compute (loc, &loc->end, yytext, yyleng);
static char *fetch_type_name (char *cp, char const **type_name,
location dollar_loc);
static void handle_action_dollar (symbol_list *rule, char *cp, static void handle_action_dollar (symbol_list *rule, char *cp,
location dollar_loc); location dollar_loc);
static void handle_action_at (symbol_list *rule, char *cp, location at_loc); static void handle_action_at (symbol_list *rule, char *cp, location at_loc);
@@ -96,11 +99,15 @@ ref -?[0-9]+|{id}|"["{id}"]"|"$"
int braces_level = 0; int braces_level = 0;
/* Whether a semicolon is probably needed. /* Whether a semicolon is probably needed.
The heuristic is that a semicolon is not needed after '{', '}', ';',
or a C preprocessor directive, and that whitespaces and comments The heuristic is that a semicolon is not needed after '{', '}',
do not affect this flag. ';', or a C preprocessor directive, and that whitespaces and
Note that '{' does not need a semicolon because of '{}'. comments do not affect this flag. Note that '{' does not need a
A semicolon may be needed before a cpp direcive, but don't bother. */ semicolon because of '{}'. A semicolon may be needed before a
cpp directive, but don't bother.
While it is maintained in several start-conditions (factoring
opportunities), it is meaningful only for SC_RULE_ACTION. */
bool need_semicolon = false; bool need_semicolon = false;
/* Whether in a C preprocessor directive. Don't use a start condition /* Whether in a C preprocessor directive. Don't use a start condition
@@ -158,7 +165,8 @@ ref -?[0-9]+|{id}|"["{id}"]"|"$"
} }
<SC_RULE_ACTION,SC_SYMBOL_ACTION>{ <SC_RULE_ACTION,SC_SYMBOL_ACTION>
{
"'" { "'" {
STRING_GROW; STRING_GROW;
BEGIN SC_CHARACTER; BEGIN SC_CHARACTER;
@@ -177,42 +185,31 @@ ref -?[0-9]+|{id}|"["{id}"]"|"$"
STRING_GROW; STRING_GROW;
BEGIN SC_LINE_COMMENT; BEGIN SC_LINE_COMMENT;
} }
[$@] {
complain_at (*loc, Wother, _("stray '%s'"), yytext);
obstack_escape (&obstack_for_string, yytext);
need_semicolon = true;
}
[\[\]] {
obstack_escape (&obstack_for_string, yytext);
need_semicolon = true;
}
} }
<SC_RULE_ACTION> <SC_RULE_ACTION>
{ {
"$"("<"{tag}">")?{ref} { "$"("<"{tag}">")?{ref} {
ref_tail_fields = 0; ref_tail_fields = NULL;
handle_action_dollar (self->rule, yytext, *loc); handle_action_dollar (self->rule, yytext, *loc);
if (ref_tail_fields) { if (ref_tail_fields)
obstack_sgrow (&obstack_for_string, ref_tail_fields); obstack_sgrow (&obstack_for_string, ref_tail_fields);
}
need_semicolon = true; need_semicolon = true;
} }
"@"{ref} { "@"{ref} {
ref_tail_fields = 0; ref_tail_fields = NULL;
handle_action_at (self->rule, yytext, *loc); handle_action_at (self->rule, yytext, *loc);
if (ref_tail_fields) { if (ref_tail_fields)
obstack_sgrow (&obstack_for_string, ref_tail_fields); obstack_sgrow (&obstack_for_string, ref_tail_fields);
}
need_semicolon = true;
}
"$" {
complain_at (*loc, Wother, _("stray '$'"));
obstack_sgrow (&obstack_for_string, "$][");
need_semicolon = true;
}
"@" {
complain_at (*loc, Wother, _("stray '@'"));
obstack_sgrow (&obstack_for_string, "@@");
need_semicolon = true;
}
"[" {
obstack_sgrow (&obstack_for_string, "@{");
need_semicolon = true;
}
"]" {
obstack_sgrow (&obstack_for_string, "@}");
need_semicolon = true; need_semicolon = true;
} }
@@ -253,8 +250,12 @@ ref -?[0-9]+|{id}|"["{id}"]"|"$"
<SC_SYMBOL_ACTION> <SC_SYMBOL_ACTION>
{ {
"$$" { "$"("<"{tag}">")?"$" {
obstack_sgrow (&obstack_for_string, "]b4_dollar_dollar["); const char *type_name = NULL;
fetch_type_name (yytext + 1, &type_name, *loc)[-1] = 0;
obstack_sgrow (&obstack_for_string, "]b4_dollar_dollar(");
obstack_quote (&obstack_for_string, type_name);
obstack_sgrow (&obstack_for_string, ")[");
self->is_value_used = true; self->is_value_used = true;
} }
"@$" { "@$" {
@@ -264,29 +265,17 @@ ref -?[0-9]+|{id}|"["{id}"]"|"$"
} }
/*-----------------------------------------.
| Escape M4 quoting characters in C code. |
`-----------------------------------------*/
<*> <*>
{ {
\$ obstack_sgrow (&obstack_for_string, "$]["); /* Escape M4 quoting characters in C code. */
\@ obstack_sgrow (&obstack_for_string, "@@"); [$@\[\]] obstack_escape (&obstack_for_string, yytext);
\[ obstack_sgrow (&obstack_for_string, "@{");
\] obstack_sgrow (&obstack_for_string, "@}");
}
/*-----------------------------------------------------. /* By default, grow the string obstack with the input. */
| By default, grow the string obstack with the input. | .|\n STRING_GROW;
`-----------------------------------------------------*/
<*>.|\n STRING_GROW;
/* End of processing. */ /* End of processing. */
<*><<EOF>> { <<EOF>> STRING_FINISH; return last_string;
STRING_FINISH; }
return last_string;
}
%% %%
@@ -335,7 +324,7 @@ typedef struct
not visible from current midrule. */ not visible from current midrule. */
#define VARIANT_NOT_VISIBLE_FROM_MIDRULE (1 << 2) #define VARIANT_NOT_VISIBLE_FROM_MIDRULE (1 << 2)
static variant *variant_table = 0; static variant *variant_table = NULL;
static unsigned variant_table_size = 0; static unsigned variant_table_size = 0;
static unsigned variant_count = 0; static unsigned variant_count = 0;
@@ -357,7 +346,7 @@ static void
variant_table_free (void) variant_table_free (void)
{ {
free (variant_table); free (variant_table);
variant_table = 0; variant_table = NULL;
variant_table_size = variant_count = 0; variant_table_size = variant_count = 0;
} }
@@ -681,6 +670,32 @@ parse_ref (char *cp, symbol_list *rule, int rule_length,
int max_left_semantic_context = 0; int max_left_semantic_context = 0;
/* If CP points to a typename (i.e., <.*?>), set TYPE_NAME to its
beginning (i.e., after the opening "<", and return the pointer
immediately after it. */
static
char *
fetch_type_name (char *cp, char const **type_name,
location dollar_loc)
{
if (*cp == '<')
{
*type_name = ++cp;
while (*cp != '>')
++cp;
/* The '>' symbol will be later replaced by '\0'. Original
'text' is needed for error messages. */
++cp;
if (untyped_var_seen)
complain_at (dollar_loc, complaint,
_("explicit type given in untyped grammar"));
tag_seen = true;
}
return cp;
}
/*------------------------------------------------------------------. /*------------------------------------------------------------------.
| TEXT is pointing to a wannabee semantic value (i.e., a '$'). | | TEXT is pointing to a wannabee semantic value (i.e., a '$'). |
| | | |
@@ -694,7 +709,6 @@ handle_action_dollar (symbol_list *rule, char *text, location dollar_loc)
{ {
char const *type_name = NULL; char const *type_name = NULL;
char *cp = text + 1; char *cp = text + 1;
char *gt_ptr = 0;
symbol_list *effective_rule; symbol_list *effective_rule;
int effective_rule_length; int effective_rule_length;
int n; int n;
@@ -711,27 +725,14 @@ handle_action_dollar (symbol_list *rule, char *text, location dollar_loc)
} }
/* Get the type name if explicit. */ /* Get the type name if explicit. */
if (*cp == '<') cp = fetch_type_name (cp, &type_name, dollar_loc);
{
type_name = ++cp;
while (*cp != '>')
++cp;
/* The '>' symbol will be later replaced by '\0'. Original
'text' is needed for error messages. */
gt_ptr = cp;
++cp;
if (untyped_var_seen)
complain_at (dollar_loc, complaint,
_("explicit type given in untyped grammar"));
tag_seen = true;
}
n = parse_ref (cp, effective_rule, effective_rule_length, n = parse_ref (cp, effective_rule, effective_rule_length,
rule->midrule_parent_rhs_index, text, dollar_loc, '$'); rule->midrule_parent_rhs_index, text, dollar_loc, '$');
if (gt_ptr) /* End type_name. */
*gt_ptr = '\0'; if (type_name)
cp[-1] = '\0';
switch (n) switch (n)
{ {
@@ -759,11 +760,11 @@ handle_action_dollar (symbol_list *rule, char *text, location dollar_loc)
} }
else else
untyped_var_seen = true; untyped_var_seen = true;
type_name = "";
} }
obstack_fgrow1 (&obstack_for_string, obstack_sgrow (&obstack_for_string, "]b4_lhs_value(");
"]b4_lhs_value([%s])[", type_name); obstack_quote (&obstack_for_string, type_name);
obstack_sgrow (&obstack_for_string, ")[");
rule->action_props.is_value_used = true; rule->action_props.is_value_used = true;
break; break;
@@ -781,12 +782,12 @@ handle_action_dollar (symbol_list *rule, char *text, location dollar_loc)
quote (effective_rule->content.sym->tag)); quote (effective_rule->content.sym->tag));
else else
untyped_var_seen = true; untyped_var_seen = true;
type_name = "";
} }
obstack_fgrow3 (&obstack_for_string, obstack_fgrow2 (&obstack_for_string,
"]b4_rhs_value(%d, %d, [%s])[", "]b4_rhs_value(%d, %d, ", effective_rule_length, n);
effective_rule_length, n, type_name); obstack_quote (&obstack_for_string, type_name);
obstack_sgrow (&obstack_for_string, ")[");
if (n > 0) if (n > 0)
symbol_list_n_get (effective_rule, n)->action_props.is_value_used = symbol_list_n_get (effective_rule, n)->action_props.is_value_used =
true; true;

View File

@@ -72,8 +72,8 @@ static void fail_for_invalid_at (char const *at);
"@@" fputc ('@', yyout); "@@" fputc ('@', yyout);
"@{" fputc ('[', yyout); "@{" fputc ('[', yyout);
"@}" fputc (']', yyout); "@}" fputc (']', yyout);
"@`" /* Empty. Used by b4_cat in ../data/bison.m4. */ "@`" continue; /* Used by b4_cat in ../data/bison.m4. */
@\n /* Likewise. */ @\n continue;
"@oline@" fprintf (yyout, "%d", out_lineno + 1); "@oline@" fprintf (yyout, "%d", out_lineno + 1);
"@ofile@" QPUTS (outname); "@ofile@" QPUTS (outname);
@@ -91,7 +91,7 @@ static void fail_for_invalid_at (char const *at);
\n out_lineno++; ECHO; \n out_lineno++; ECHO;
[^@\n]+ ECHO; [^@\n]+ ECHO;
<INITIAL><<EOF>> { <<EOF>> {
if (outname) if (outname)
{ {
free (outname); free (outname);
@@ -100,15 +100,15 @@ static void fail_for_invalid_at (char const *at);
return EOF; return EOF;
} }
<SC_AT_DIRECTIVE_ARGS>{ <SC_AT_DIRECTIVE_ARGS>
[^@]+ { STRING_GROW; } {
[^@]+ STRING_GROW;
"@@" { obstack_1grow (&obstack_for_string, '@'); } "@@" obstack_1grow (&obstack_for_string, '@');
"@{" { obstack_1grow (&obstack_for_string, '['); } "@{" obstack_1grow (&obstack_for_string, '[');
"@}" { obstack_1grow (&obstack_for_string, ']'); } "@}" obstack_1grow (&obstack_for_string, ']');
"@`" /* Empty. Useful for starting an argument "@`" continue; /* For starting an argument that begins with whitespace. */
that begins with whitespace. */ @\n continue;
@\n /* Empty. */
@[,)] { @[,)] {
if (at_directive_argc >= AT_DIRECTIVE_ARGC_MAX) if (at_directive_argc >= AT_DIRECTIVE_ARGC_MAX)
@@ -131,15 +131,17 @@ static void fail_for_invalid_at (char const *at);
} }
} }
@.? { fail_for_invalid_at (yytext); } @.? fail_for_invalid_at (yytext);
} }
<SC_AT_DIRECTIVE_SKIP_WS>{ <SC_AT_DIRECTIVE_SKIP_WS>
[ \t\r\n] {
[ \t\r\n] continue;
. { yyless (0); BEGIN SC_AT_DIRECTIVE_ARGS; } . { yyless (0); BEGIN SC_AT_DIRECTIVE_ARGS; }
} }
<SC_AT_DIRECTIVE_ARGS,SC_AT_DIRECTIVE_SKIP_WS>{ <SC_AT_DIRECTIVE_ARGS,SC_AT_DIRECTIVE_SKIP_WS>
{
<<EOF>> { <<EOF>> {
complain (fatal, _("unclosed %s directive in skeleton"), complain (fatal, _("unclosed %s directive in skeleton"),
at_directive_argv[0]); at_directive_argv[0]);

View File

@@ -191,15 +191,12 @@ symbol_list_null (symbol_list *node)
void void
symbol_list_code_props_set (symbol_list *node, code_props_type kind, symbol_list_code_props_set (symbol_list *node, code_props_type kind,
location loc, char const *code) code_props const *cprops)
{ {
code_props cprops;
code_props_symbol_action_init (&cprops, code, loc);
code_props_translate_code (&cprops);
switch (node->content_type) switch (node->content_type)
{ {
case SYMLIST_SYMBOL: case SYMLIST_SYMBOL:
symbol_code_props_set (node->content.sym, kind, &cprops); symbol_code_props_set (node->content.sym, kind, cprops);
if (node->content.sym->status == undeclared) if (node->content.sym->status == undeclared)
node->content.sym->status = used; node->content.sym->status = used;
break; break;
@@ -207,7 +204,7 @@ symbol_list_code_props_set (symbol_list *node, code_props_type kind,
semantic_type_code_props_set semantic_type_code_props_set
(semantic_type_get (node->content.sem_type->tag, (semantic_type_get (node->content.sem_type->tag,
&node->content.sem_type->location), &node->content.sem_type->location),
kind, &cprops); kind, cprops);
if (node->content.sem_type->status == undeclared) if (node->content.sem_type->status == undeclared)
node->content.sem_type->status = used; node->content.sem_type->status = used;
break; break;

View File

@@ -113,9 +113,8 @@ uniqstr symbol_list_n_type_name_get (symbol_list *l, location loc, int n);
/* Check whether the node is a border element of a rule. */ /* Check whether the node is a border element of a rule. */
bool symbol_list_null (symbol_list *node); bool symbol_list_null (symbol_list *node);
/** Set the \c \%destructor or \c \%printer for \c node as \c code at /** Set the \c \%destructor or \c \%printer for \c node as \c cprops. */
\c loc. */
void symbol_list_code_props_set (symbol_list *node, code_props_type kind, void symbol_list_code_props_set (symbol_list *node, code_props_type kind,
location loc, char const *code); code_props const *cprops);
#endif /* !SYMLIST_H_ */ #endif /* !SYMLIST_H_ */

View File

@@ -92,8 +92,14 @@ struct symbol
/** The location of its first occurrence. */ /** The location of its first occurrence. */
location location; location location;
/** Its \c \%type. */ /** Its \c \%type.
Beware that this is the type_name as was entered by the user,
including silly things such as "]" if she entered "%token <]> t".
Therefore, when outputting type_name to M4, be sure to escape it
into "@}". See quoted_output for instance. */
uniqstr type_name; uniqstr type_name;
/** Its \c \%type's location. */ /** Its \c \%type's location. */
location type_location; location type_location;
@@ -101,9 +107,9 @@ struct symbol
symbol. symbol.
Access this field only through <tt>symbol</tt>'s interface functions. For Access this field only through <tt>symbol</tt>'s interface functions. For
Example, if <tt>symbol::destructor = NULL</tt> (resp. <tt>symbol::printer example, if <tt>symbol::destructor = NULL</tt> (resp. <tt>symbol::printer
= NULL</tt>), a default \c \%destructor (resp. \%printer) or a per-type = NULL</tt>), a default \c \%destructor (resp. \%printer) or a per-type
\c symbol_destructor_printer_get will compute the corect one. */ \c symbol_destructor_printer_get will compute the correct one. */
code_props props[CODE_PROPS_SIZE]; code_props props[CODE_PROPS_SIZE];
symbol_number number; symbol_number number;

View File

@@ -177,32 +177,75 @@ typedef size_t uintptr_t;
obstack_grow (Obs, Str, strlen (Str)) obstack_grow (Obs, Str, strlen (Str))
#define obstack_fgrow1(Obs, Format, Arg1) \ #define obstack_fgrow1(Obs, Format, Arg1) \
do { \ do { \
char buf[4096]; \ char buf[4096]; \
sprintf (buf, Format, Arg1); \ sprintf (buf, Format, Arg1); \
obstack_grow (Obs, buf, strlen (buf)); \ obstack_grow (Obs, buf, strlen (buf)); \
} while (0) } while (0)
#define obstack_fgrow2(Obs, Format, Arg1, Arg2) \ #define obstack_fgrow2(Obs, Format, Arg1, Arg2) \
do { \ do { \
char buf[4096]; \ char buf[4096]; \
sprintf (buf, Format, Arg1, Arg2); \ sprintf (buf, Format, Arg1, Arg2); \
obstack_grow (Obs, buf, strlen (buf)); \ obstack_grow (Obs, buf, strlen (buf)); \
} while (0) } while (0)
#define obstack_fgrow3(Obs, Format, Arg1, Arg2, Arg3) \ #define obstack_fgrow3(Obs, Format, Arg1, Arg2, Arg3) \
do { \ do { \
char buf[4096]; \ char buf[4096]; \
sprintf (buf, Format, Arg1, Arg2, Arg3); \ sprintf (buf, Format, Arg1, Arg2, Arg3); \
obstack_grow (Obs, buf, strlen (buf)); \ obstack_grow (Obs, buf, strlen (buf)); \
} while (0) } while (0)
#define obstack_fgrow4(Obs, Format, Arg1, Arg2, Arg3, Arg4) \ #define obstack_fgrow4(Obs, Format, Arg1, Arg2, Arg3, Arg4) \
do { \ do { \
char buf[4096]; \ char buf[4096]; \
sprintf (buf, Format, Arg1, Arg2, Arg3, Arg4); \ sprintf (buf, Format, Arg1, Arg2, Arg3, Arg4); \
obstack_grow (Obs, buf, strlen (buf)); \ obstack_grow (Obs, buf, strlen (buf)); \
} while (0) } while (0)
/* Output Str escaped for our postprocessing (i.e., escape M4 special
characters).
For instance "[foo]" -> "@{foo@}", "$$" -> "$][$][". */
# define obstack_escape(Obs, Str) \
do { \
char const *p__; \
for (p__ = Str; *p__; p__++) \
switch (*p__) \
{ \
case '$': obstack_sgrow (Obs, "$]["); break; \
case '@': obstack_sgrow (Obs, "@@" ); break; \
case '[': obstack_sgrow (Obs, "@{" ); break; \
case ']': obstack_sgrow (Obs, "@}" ); break; \
default: obstack_1grow (Obs, *p__ ); break; \
} \
} while (0)
/* Output Str both quoted for M4 (i.e., embed in [[...]]), and escaped
for our postprocessing (i.e., escape M4 special characters). If
Str is empty (or NULL), output "[]" instead of "[[]]" as it make M4
programming easier (m4_ifval can be used).
For instance "[foo]" -> "[[@{foo@}]]", "$$" -> "[[$][$][]]". */
# define obstack_quote(Obs, Str) \
do { \
char const* obstack_quote_p = Str; \
if (obstack_quote_p && obstack_quote_p[0]) \
{ \
obstack_sgrow (Obs, "[["); \
obstack_escape (Obs, obstack_quote_p); \
obstack_sgrow (Obs, "]]"); \
} \
else \
obstack_sgrow (Obs, "[]"); \
} while (0)
@@ -218,10 +261,6 @@ do { \
# define TAB_EXT ".tab" # define TAB_EXT ".tab"
#endif #endif
#ifndef DEFAULT_TMPDIR
# define DEFAULT_TMPDIR "/tmp"
#endif
/*---------------------. /*---------------------.

View File

@@ -1255,6 +1255,143 @@ AT_CHECK_ACTION_LOCATIONS([[%destructor]])
AT_CHECK_ACTION_LOCATIONS([[%printer]]) AT_CHECK_ACTION_LOCATIONS([[%printer]])
## ------------------------- ##
## Qualified $$ in actions. ##
## ------------------------- ##
# Check that we can used qualified $$ (v.g., $<type>$) not only in
# rule actions, but also where $$ is valid: %printer and %destructor.
#
# FIXME: Not actually checking %desctructor, but it's the same code as
# %printer...
#
# To do that, use a semantic value that has two fields (sem_type),
# declare symbols to have only one of these types (INT, float), and
# use $<type>$ to get the other one. Including for symbols that are
# not typed (UNTYPED).
m4_pushdef([AT_TEST],
[AT_SETUP([[Qualified $$ in actions: $1]])
AT_BISON_OPTION_PUSHDEFS([%locations %skeleton "$1"])
AT_DATA_GRAMMAR([[input.y]],
[[%skeleton "$1"
%defines // FIXME: Mandated by lalr1.cc in Bison 2.6.
%locations // FIXME: Mandated by lalr1.cc in Bison 2.6.
%debug
%code requires
{
# include <stdio.h>
typedef struct sem_type
{
int ival;
float fval;
} sem_type;
# define YYSTYPE sem_type
#ifdef __cplusplus
# include <iostream>
static void
report (std::ostream& yyo, int ival, float fval)
{
yyo << "ival: " << ival << ", fval: " << fval;
}
#else
static void
report (FILE* yyo, int ival, float fval)
{
fprintf (yyo, "ival: %d, fval: %1.1f", ival, fval);
}
#endif
}
%code
{
]AT_YYERROR_DECLARE[
]AT_YYLEX_DECLARE[
}
%token UNTYPED
%token <ival> INT
%type <fval> float
%printer { report (yyo, $$, $<fval>$); } <ival>;
%printer { report (yyo, $<ival>$, $$ ); } <fval>;
%printer { report (yyo, $<ival>$, $<fval>$); } <>;
]AT_SKEL_CC_IF([[
/* The lalr1.cc skeleton, for backward compatibility, defines
a constructor for position that initializes the filename. The
glr.cc skeleton does not (and in fact cannot: location/position
are stored in a union, from which objects with constructors are
excluded in C++). */
%initial-action {
@$.initialize ();
}
]])[
%initial-action
{
$<ival>$ = 42;
$<fval>$ = 4.2;
}
%%
float: UNTYPED INT
{
$$ = $<fval>1 + $<fval>2;
$<ival>$ = $<ival>1 + $][2;
};
%%
]AT_YYERROR_DEFINE[
]AT_YYLEX_DEFINE(AT_SKEL_CC_IF([[{yy::parser::token::UNTYPED,
yy::parser::token::INT,
EOF}]],
[[{UNTYPED, INT, EOF}]]),
[AT_VAL.ival = toknum * 10; AT_VAL.fval = toknum / 10.0;])[
int
main (void)
{]AT_SKEL_CC_IF([[
yy::parser p;
p.set_debug_level(1);
return p.parse ();]], [[
yydebug = 1;
return yyparse ();]])[
}
]])
AT_FULL_COMPILE([[input]])
AT_PARSER_CHECK([./input], 0, [], [stderr])
# Don't be too picky on the traces, GLR is not exactly the same. Keep
# only the lines from the printer.
#
# Don't care about locations. FIXME: remove their removal when Bison
# supports C++ without locations.
AT_CHECK([[sed -ne 's/([-0-9.]*: /(/;/ival:/p' stderr]], 0,
[[Reading a token: Next token is token UNTYPED (ival: 10, fval: 0.1)
Shifting token UNTYPED (ival: 10, fval: 0.1)
Reading a token: Next token is token INT (ival: 20, fval: 0.2)
Shifting token INT (ival: 20, fval: 0.2)
$][1 = token UNTYPED (ival: 10, fval: 0.1)
$][2 = token INT (ival: 20, fval: 0.2)
-> $$ = nterm float (ival: 30, fval: 0.3)
Cleanup: popping nterm float (ival: 30, fval: 0.3)
]])
AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])
AT_TEST([yacc.c])
AT_TEST([glr.c])
AT_TEST([lalr1.cc])
AT_TEST([glr.cc])
m4_popdef([AT_TEST])
## ----------------------------------------------- ## ## ----------------------------------------------- ##
## Fix user actions without a trailing semicolon. ## ## Fix user actions without a trailing semicolon. ##
## ----------------------------------------------- ## ## ----------------------------------------------- ##

View File

@@ -1491,3 +1491,102 @@ AT_TEST([%define api.prefix foo], [-p bar], [input.y:1.9-18])
m4_popdef([AT_TEST]) m4_popdef([AT_TEST])
AT_CLEANUP AT_CLEANUP
## -------------- ##
## Stray $ or @. ##
## -------------- ##
AT_SETUP([[Stray $ or @]])
# Give %printer and %destructor "<*> exp TOK" instead of "<*>" to
# check that the warnings are reported once, not three times.
AT_DATA_GRAMMAR([[input.y]],
[[%type <TYPE> exp
%token <TYPE> TOK TOK2
%destructor { $%; @%; } <*> exp TOK;
%initial-action { $%; @%; };
%printer { $%; @%; } <*> exp TOK;
%%
exp: TOK { $%; @%; $$ = $1; };
]])
AT_BISON_CHECK([[input.y]], 0, [],
[[input.y:11.19: warning: stray '$' [-Wother]
input.y:11.23: warning: stray '@' [-Wother]
input.y:12.19: warning: stray '$' [-Wother]
input.y:12.23: warning: stray '@' [-Wother]
input.y:13.19: warning: stray '$' [-Wother]
input.y:13.23: warning: stray '@' [-Wother]
input.y:15.19: warning: stray '$' [-Wother]
input.y:15.23: warning: stray '@' [-Wother]
]])
AT_CLEANUP
## ---------------- ##
## Code injection. ##
## ---------------- ##
AT_SETUP([[Code injection]])
m4_pattern_allow([^m4_errprintn$])
# AT_TEST([MACRO])
# ----------------
# Try to have MACRO be run by bison.
m4_pushdef([AT_TEST],
[AT_DATA([[input.y]],
[[%type <$1(DEAD %type)> exp
%token <$1(DEAD %token)> a
%token b
%initial-action
{
$$;
$<$1(DEAD %initial-action)>$
};
%printer
{
$$
$<$1(DEAD %printer)>$
} <> <*>;
%lex-param
{
$1(DEAD %lex-param)
};
%parse-param
{
$1(DEAD %parse-param)
};
%%
exp:
a a[name] b
{
$$;
$][1;
$<$1(DEAD action 1)>$
$<$1(DEAD action 2)>1
$<$1(DEAD action 3)>name
$<$1(DEAD action 4)>0
;
};
]])
# FIXME: Provide a means to iterate over all the skeletons.
AT_BISON_CHECK([[-d input.y]])
AT_BISON_CHECK([[-d -S glr.c input.y]])
AT_BISON_CHECK([[-d -S lalr1.cc input.y]])
AT_BISON_CHECK([[-d -S glr.cc input.y]])
AT_BISON_CHECK([[ -S lalr1.java input.y]])
])
AT_TEST([m4_errprintn])
AT_TEST([@:>@m4_errprintn])
m4_popdef([AT_TEST])
AT_CLEANUP

View File

@@ -338,7 +338,7 @@ static
static size_t toknum = 0; static size_t toknum = 0;
int res; int res;
]AT_USE_LEX_ARGS[; ]AT_USE_LEX_ARGS[;
assert (toknum < sizeof input); assert (toknum < sizeof input / sizeof input[0]);
res = input[toknum++]; res = input[toknum++];
]$2[;]AT_LOCATION_IF([[ ]$2[;]AT_LOCATION_IF([[
]AT_LOC_FIRST_LINE[ = ]AT_LOC_LAST_LINE[ = 1; ]AT_LOC_FIRST_LINE[ = ]AT_LOC_LAST_LINE[ = 1;

View File

@@ -27,6 +27,11 @@ AT_BANNER([[User Actions.]])
# errors. # errors.
m4_define([AT_SYNCLINES_COMPILE], m4_define([AT_SYNCLINES_COMPILE],
[AT_CHECK([$CC $CFLAGS $CPPFLAGS -c $1], [ignore], [], [stderr]) [AT_CHECK([$CC $CFLAGS $CPPFLAGS -c $1], [ignore], [], [stderr])
# Transform stderr into something like this:
#
# input.y:4: #error "4"
#
# In case GCC displays column information, strip it down. # In case GCC displays column information, strip it down.
# #
# input.y:4:2: #error "4" or # input.y:4:2: #error "4" or
@@ -42,6 +47,11 @@ m4_define([AT_SYNCLINES_COMPILE],
# => # =>
# input.y:4: #error "8" # input.y:4: #error "8"
# #
# The message may include a caret-error:
#
# input.y:1:2: error: #error "1"
# #error "1"
# ^
# #
# And possibly distcc adds its bits. # And possibly distcc adds its bits.
# #
@@ -54,12 +64,15 @@ m4_define([AT_SYNCLINES_COMPILE],
# distcc[35882] (dcc_connect_by_name) ERROR: failed to look up host "chrisimac": Unknown host # distcc[35882] (dcc_connect_by_name) ERROR: failed to look up host "chrisimac": Unknown host
# distcc[35882] Warning: failed to distribute input.c to chrisimac/4, running locally instead # distcc[35882] Warning: failed to distribute input.c to chrisimac/4, running locally instead
AT_CHECK([[sed -e '/^distcc\[[0-9]*\] /d' \ AT_CHECK([[perl -p -0777 -f - stderr <<\EOF
-e 's/^\([^:]*:[^:.]*\)[.:][^:]*:\(.*\)$/\1:\2/' \ s/^distcc\[\d+\] .*\n//gm;
-e 's/^\([^:]*:[^:]*:\)[^@%:@]*\( @%:@error\)/\1\2/' \ s/^([^:]*:\d+)[.:][^:]*:(.*)$/$][1:$][2/gm;
-e "/^[^:]*: In function '[^\']*':$/d" \ s/^([^:]*:\d+:)[^#]*( #error)/$][1$][2/gm;
stderr]], s/^[^:]*: In function '[^']*':\n//gm;
0, [stdout]) s/^\ +#error.*\n\ *\^\n//gm;
EOF
]],
0, [stdout])
]) ])
# AT_TEST_SYNCLINE(TITLE, INPUT, ERROR-MSG) # AT_TEST_SYNCLINE(TITLE, INPUT, ERROR-MSG)