Merge branch 'maint'

* origin/maint:
  tests: check %no-lines
  tests: minor simplification
  graphs: stylistic changes.
  graphs: minor style changes
  graphs: show reductions
  graphs: style: prefix state number with "state"
  graphs: style: use left justification for states
  graphs: style: prefix rules and change shapes
  obstack: import obstack_finish0 from master
  c++: api.location.type
  muscles: a function for backward compatibility
  maint: more macros

Conflicts:
	data/glr.cc
	data/java.m4
	data/lalr1.cc
	doc/bison.texi
	src/muscle-tab.c
	src/system.h
	tests/calc.at
This commit is contained in:
Akim Demaille
2012-10-12 12:39:52 +02:00
16 changed files with 303 additions and 48 deletions

15
NEWS
View File

@@ -301,6 +301,21 @@ GNU Bison NEWS
"function declared 'noreturn' should not return") have also been
addressed.
** New %define variable: api.location.type (glr.cc, lalr1.cc)
The %define variable api.location.type defines the name of the type to use
for locations. When defined, Bison no longer generates the position.hh
and location.hh files, nor does the parser will include them: the user is
then responsible to define her type.
This can be used in programs with several parsers to factor their location
and position files: let one of them generate them, and the others just use
them.
This feature was actually introduced, but not documented, in Bison 2.5,
under the name "location_type" (which is maintained for backward
compatibility).
* Noteworthy changes in release 2.6.2 (2012-08-03) [stable]
** Bug fixes

View File

@@ -28,7 +28,7 @@ b4_percent_define_default([[parser_class_name]], [[parser]])
# Don't do that so that we remember whether we're using a user
# request, or the default value.
#
# b4_percent_define_default([[location_type]], [[location]])
# b4_percent_define_default([[api.location.type]], [[location]])
b4_percent_define_default([[filename_type]], [[std::string]])
b4_percent_define_default([[api.namespace]], m4_defn([b4_prefix]))
@@ -130,7 +130,7 @@ m4_define([b4_public_types_declare],
typedef ]b4_api_PREFIX[STYPE semantic_type;
#endif]b4_locations_if([
/// Symbol locations.
typedef b4_percent_define_get([[location_type]],
typedef b4_percent_define_get([[api.location.type]],
[[location]]) location_type;])[
/// Syntax errors thrown from user actions.

View File

@@ -47,7 +47,7 @@
m4_define([b4_pure_flag], [1])
m4_include(b4_pkgdatadir/[c++.m4])
b4_locations_if([b4_percent_define_ifdef([[location_type]], [],
b4_locations_if([b4_percent_define_ifdef([[api.location.type]], [],
[m4_include(b4_pkgdatadir/[location.cc])])])
m4_define([b4_parser_class_name],
@@ -219,14 +219,14 @@ b4_percent_code_get([[requires]])[
#include <stdexcept>
#include <string>
#include <iostream>]b4_defines_if([
b4_locations_if([b4_percent_define_ifdef([[location_type]], [],
b4_locations_if([b4_percent_define_ifdef([[api.location.type]], [],
[[#include "location.hh"]])])])[
]b4_YYDEBUG_define[
]b4_namespace_open[
]b4_defines_if([],
[b4_locations_if([b4_percent_define_ifdef([[location_type]], [],
[b4_locations_if([b4_percent_define_ifdef([[api.location.type]], [],
[b4_position_define
b4_location_define])])])[

View File

@@ -197,8 +197,8 @@ m4_define([b4_throws], [b4_percent_define_get([[throws]])])
b4_percent_define_default([[init_throws]], [])
m4_define([b4_init_throws], [b4_percent_define_get([[init_throws]])])
b4_percent_define_default([[location_type]], [Location])
m4_define([b4_location_type], [b4_percent_define_get([[location_type]])])
b4_percent_define_default([[api.location.type]], [Location])
m4_define([b4_location_type], [b4_percent_define_get([[api.location.type]])])
b4_percent_define_default([[position_type]], [Position])
m4_define([b4_position_type], [b4_percent_define_get([[position_type]])])

View File

@@ -120,7 +120,7 @@ m4_pushdef([b4_copyright_years],
m4_define([b4_parser_class_name],
[b4_percent_define_get([[parser_class_name]])])
b4_locations_if([b4_percent_define_ifdef([[location_type]], [],
b4_locations_if([b4_percent_define_ifdef([[api.location.type]], [],
[# Backward compatibility.
m4_define([b4_location_constructors])
m4_include(b4_pkgdatadir/[location.cc])])])
@@ -139,7 +139,7 @@ m4_define([b4_shared_declarations],
# include <stdexcept>
# include <string>]b4_defines_if([[
# include "stack.hh"
]b4_locations_if([b4_percent_define_ifdef([[location_type]], [],
]b4_locations_if([b4_percent_define_ifdef([[api.location.type]], [],
[[# include "location.hh"]])])])[
]b4_YYDEBUG_define[
@@ -148,7 +148,7 @@ m4_define([b4_shared_declarations],
]b4_defines_if([],
[b4_stack_define
b4_locations_if([b4_percent_define_ifdef([[location_type]], [],
b4_locations_if([b4_percent_define_ifdef([[api.location.type]], [],
[b4_position_define
b4_location_define])])])[

View File

@@ -331,6 +331,7 @@ C++ Location Values
* C++ position:: One point in the source file
* C++ location:: Two points in the source file
* User Defined Location Type:: Required interface for locations
A Complete C++ Example
@@ -5473,6 +5474,22 @@ The parser namespace is @code{foo} and @code{yylex} is referenced as
@end itemize
@c namespace
@c ================================================== api.location.type
@item @code{api.location.type}
@findex %define api.location.type
@itemize @bullet
@item Language(s): C++
@item Purpose: Define the location type.
@xref{User Defined Location Type}.
@item Accepted Values: String
@item Default Value: none
@item History: introduced in Bison 2.7
@end itemize
@c ================================================== api.prefix
@item api.prefix
@@ -5481,7 +5498,7 @@ The parser namespace is @code{foo} and @code{yylex} is referenced as
@itemize @bullet
@item Language(s): All
@item Purpose: Rename exported symbols
@item Purpose: Rename exported symbols.
@xref{Multiple Parsers, ,Multiple Parsers in the Same Program}.
@item Accepted Values: String
@@ -9564,8 +9581,10 @@ in the following files:
@table @file
@item position.hh
@itemx location.hh
The definition of the classes @code{position} and @code{location},
used for location tracking when enabled. @xref{C++ Location Values}.
The definition of the classes @code{position} and @code{location}, used for
location tracking when enabled. These files are not generated if the
@code{%define} variable @code{api.location.type} is defined. @xref{C++
Location Values}.
@item stack.hh
An auxiliary class @code{stack} used by the parser.
@@ -9724,10 +9743,13 @@ is some time and/or some talented C++ hacker willing to contribute to Bison.
@c - %define filename_type "const symbol::Symbol"
When the directive @code{%locations} is used, the C++ parser supports
location tracking, see @ref{Tracking Locations}. Two auxiliary classes
define a @code{position}, a single point in a file, and a @code{location}, a
range composed of a pair of @code{position}s (possibly spanning several
files).
location tracking, see @ref{Tracking Locations}.
By default, two auxiliary classes define a @code{position}, a single point
in a file, and a @code{location}, a range composed of a pair of
@code{position}s (possibly spanning several files). But if the
@code{%define} variable @code{api.location.type} is defined, then these
classes will not be generated, and the user defined type will be used.
@tindex uint
In this section @code{uint} is an abbreviation for @code{unsigned int}: in
@@ -9736,6 +9758,7 @@ genuine code only the latter is used.
@menu
* C++ position:: One point in the source file
* C++ location:: Two points in the source file
* User Defined Location Type:: Required interface for locations
@end menu
@node C++ position
@@ -9839,6 +9862,63 @@ Report @var{p} on @var{o}, taking care of special cases such as: no
@code{filename} defined, or equal filename/line or column.
@end deftypefun
@node User Defined Location Type
@subsubsection User Defined Location Type
@findex %define api.location.type
Instead of using the built-in types you may use the @code{%define} variable
@code{api.location.type} to specify your own type:
@example
%define api.location.type @var{LocationType}
@end example
The requirements over your @var{LocationType} are:
@itemize
@item
it must be copyable;
@item
in order to compute the (default) value of @code{@@$} in a reduction, the
parser basically runs
@example
@@$.begin = @@$1.begin;
@@$.end = @@$@var{N}.end; // The location of last right-hand side symbol.
@end example
@noindent
so there must be copyable @code{begin} and @code{end} members;
@item
alternatively you may redefine the computation of the default location, in
which case these members are not required (@pxref{Location Default Action});
@item
if traces are enabled, then there must exist an @samp{std::ostream&
operator<< (std::ostream& o, const @var{LocationType}& s)} function.
@end itemize
@sp 1
In programs with several C++ parsers, you may also use the @code{%define}
variable @code{api.location.type} to share a common set of built-in
definitions for @code{position} and @code{location}. For instance, one
parser @file{master/parser.yy} might use:
@example
%defines
%locations
%define namespace "master::"
@end example
@noindent
to generate the @file{master/position.hh} and @file{master/location.hh}
files, reused by other parsers as follows:
@example
%define location_type "master::location"
%code requires @{ #include <master/location.hh> @}
@end example
@node C++ Parser Interface
@subsection C++ Parser Interface
@c - define parser_class_name

View File

@@ -25,12 +25,14 @@
#include <quotearg.h>
#include "files.h"
#include "gram.h"
#include "graphviz.h"
#include "tables.h"
/* Return an unambiguous printable representation for NAME, suitable
for C strings. Use slot 2 since the user may use slots 0 and 1. */
static char const *
static char *
quote (char const *name)
{
return quotearg_n_style (2, c_quoting_style, name);
@@ -51,12 +53,13 @@ start_graph (FILE *fout)
"digraph %s\n"
"{\n",
quote (grammar_file));
fprintf (fout, "node [shape=box]\n");
}
void
output_node (int id, char const *label, FILE *fout)
{
fprintf (fout, " %d [label=%s]\n", id, quote (label));
fprintf (fout, " %d [label=\"%s\"]\n", id, label);
}
void
@@ -69,6 +72,98 @@ output_edge (int source, int destination, char const *label,
fputs ("]\n", fout);
}
char const *
escape (char const *name)
{
char *q = quote (name);
q[strlen (q) - 1] = '\0';
return q + 1;
}
static void
no_reduce_bitset_init (state const *s, bitset *no_reduce_set)
{
int n;
*no_reduce_set = bitset_create (ntokens, BITSET_FIXED);
bitset_zero (*no_reduce_set);
FOR_EACH_SHIFT (s->transitions, n)
bitset_set (*no_reduce_set, TRANSITION_SYMBOL (s->transitions, n));
for (n = 0; n < s->errs->num; ++n)
if (s->errs->symbols[n])
bitset_set (*no_reduce_set, s->errs->symbols[n]->number);
}
static bool
print_token (struct obstack *out, bool first, char const *tok)
{
char const *q = escape (tok);
if (! first)
obstack_sgrow (out, ",");
obstack_sgrow (out, q);
return false;
}
void
output_red (state const *s, reductions const *reds, FILE *fout)
{
bitset no_reduce_set;
int j;
int source = s->number;
struct obstack oout;
no_reduce_bitset_init (s, &no_reduce_set);
obstack_init (&oout);
for (j = 0; j < reds->num; ++j)
{
bool disabled = false;
bool first = true;
int ruleno = reds->rules[j]->user_number;
rule *default_reduction = NULL;
if (yydefact[s->number] != 0)
default_reduction = &rules[yydefact[s->number] - 1];
/* First, print the edges that represent each possible reduction for
the given state. */
obstack_printf (&oout, " %1$d -> \"%1$dR%2$d\" [label=\"",
source, ruleno);
if (default_reduction && default_reduction == reds->rules[j])
first = print_token (&oout, true, "$default");
else
{
int i;
for (i = 0; i < ntokens; i++)
if (bitset_test (reds->lookahead_tokens[j], i))
{
first = print_token (&oout, first, symbols[i]->tag);
if (bitset_test (no_reduce_set, i))
disabled = true;
}
}
obstack_sgrow (&oout, "\" style=solid]\n");
/* Then, print the reduction's representation. Done later since
we need to know whether this reduction is disabled. */
obstack_printf (&oout,
" \"%dR%d\" "
"[style=filled shape=diamond fillcolor=%s "
"label=\"R%d\"]\n",
source, ruleno,
disabled ? "firebrick1" : "yellowgreen",
ruleno);
/* If no lookahead tokens were valid transitions, this reduction is
actually disabled, so don't print it. */
if (first)
(void) obstack_finish0 (&oout);
else
fprintf (fout, obstack_finish0 (&oout));
}
obstack_free (&oout, 0);
}
void
finish_graph (FILE *fout)
{

View File

@@ -22,6 +22,8 @@
#ifndef GRAPHVIZ_H_
# define GRAPHVIZ_H_
#include "state.h"
/// Begin a Dot graph.
/// \param fout output stream.
void start_graph (FILE *fout);
@@ -42,8 +44,18 @@ void output_node (int id, char const *label, FILE *fout);
void output_edge (int source, int destination, char const *label,
char const *style, FILE *fout);
/// Output a reduction.
/// \param s current state
/// \param reds the set of reductions
/// \param fout output stream.
void output_red (state const *s, reductions const *reds, FILE *fout);
/// End a Dot graph.
/// \param fout output stream.
void finish_graph (FILE *fout);
/// Escape a lookahead token.
/// \param name the token.
char const *escape (char const *name);
#endif /* ! GRAPHVIZ_H_ */

View File

@@ -398,6 +398,7 @@ muscle_percent_variable_update (char const *variable, location variable_loc)
const conversion_type conversion[] =
{
{ "api.push_pull", "api.push-pull", },
{ "location_type", "api.location.type", },
{ "lr.keep_unreachable_states", "lr.keep-unreachable-states", },
{ "namespace", "api.namespace", },
};
@@ -416,23 +417,17 @@ muscle_percent_variable_update (char const *variable, location variable_loc)
}
void
muscle_percent_define_insert (char const *variable, location variable_loc,
muscle_percent_define_insert (char const *var, location variable_loc,
char const *value,
muscle_percent_define_how how)
{
char const *name;
char const *loc_name;
char const *syncline_name;
char const *how_name;
/* Permit certain names with underscores for backward compatibility. */
variable = muscle_percent_variable_update (variable, variable_loc);
name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
syncline_name =
/* Backward compatibility. */
char const *variable = muscle_percent_variable_update (var, variable_loc);
char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
char const *syncline_name =
UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
char const *how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
/* Command-line options are processed before the grammar file. */
if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE

View File

@@ -18,6 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include <quotearg.h>
#include "system.h"
#include "LR0.h"
@@ -54,7 +55,7 @@ print_core (struct obstack *oout, state *s)
snritems = nitemset;
}
obstack_printf (oout, "%d", s->number);
obstack_printf (oout, "state %d\\n", s->number);
for (i = 0; i < snritems; i++)
{
item_number *sp;
@@ -68,15 +69,15 @@ print_core (struct obstack *oout, state *s)
r = item_number_as_rule_number (*sp);
obstack_printf (oout, "\n%s -> ", rules[r].lhs->tag);
obstack_printf (oout, "%d: %s -> ", r, escape (rules[r].lhs->tag));
for (sp = rules[r].rhs; sp < sp1; sp++)
obstack_printf (oout, "%s ", symbols[*sp]->tag);
obstack_printf (oout, "%s ", escape (symbols[*sp]->tag));
obstack_1grow (oout, '.');
for (/* Nothing */; *sp >= 0; ++sp)
obstack_printf (oout, " %s", symbols[*sp]->tag);
obstack_printf (oout, " %s", escape (symbols[*sp]->tag));
/* Experimental feature: display the lookahead tokens. */
if (report_flag & report_lookahead_tokens
@@ -92,15 +93,17 @@ print_core (struct obstack *oout, state *s)
bitset_iterator biter;
int k;
char const *sep = "";
obstack_sgrow (oout, "[");
obstack_1grow (oout, '[');
BITSET_FOR_EACH (biter, reds->lookahead_tokens[redno], k, 0)
{
obstack_printf (oout, "%s%s", sep, symbols[k]->tag);
obstack_sgrow (oout, sep);
obstack_sgrow (oout, escape (symbols[k]->tag));
sep = ", ";
}
obstack_sgrow (oout, "]");
obstack_1grow (oout, ']');
}
}
obstack_sgrow (oout, "\\l");
}
}
@@ -117,6 +120,9 @@ print_actions (state const *s, FILE *fgraph)
transitions const *trans = s->transitions;
/* Display reductions. */
output_red (s, s->reductions, fgraph);
if (!trans->num && !s->reductions)
return;

View File

@@ -55,6 +55,10 @@
#include <unistd.h>
#include <inttypes.h>
#define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
#define STREQ(L, R) (strcmp(L, R) == 0)
#define STRNEQ(L, R) (!STREQ(L, R))
#ifndef UINTPTR_MAX
/* This isn't perfect, but it's good enough for Bison, which needs
only to hash pointers. */
@@ -220,8 +224,6 @@ typedef size_t uintptr_t;
(obstack_1grow (Obs, '\0'), (char *) obstack_finish (Obs))
/*-----------------------------------------.
| Extensions to use for the output files. |
`-----------------------------------------*/

View File

@@ -716,7 +716,7 @@ m4_define([AT_CHECK_CALC_LALR1_CC],
AT_CHECK_CALC_LALR1_CC([])
AT_CHECK_CALC_LALR1_CC([%locations])
AT_CHECK_CALC_LALR1_CC([%locations %define location_type Span])
AT_CHECK_CALC_LALR1_CC([%locations %define api.location.type Span])
AT_CHECK_CALC_LALR1_CC([%defines %locations %define parse.error verbose %name-prefix "calc" %verbose %yacc])
AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %define api.prefix "calc" %verbose %yacc])
@@ -750,7 +750,7 @@ m4_define([AT_CHECK_CALC_GLR_CC],
AT_CHECK_CALC_GLR_CC([])
AT_CHECK_CALC_GLR_CC([%locations])
AT_CHECK_CALC_GLR_CC([%locations %define location_type Span])
AT_CHECK_CALC_GLR_CC([%locations %define api.location.type Span])
AT_CHECK_CALC_GLR_CC([%defines %define parse.error verbose %name-prefix "calc" %verbose %yacc])
AT_CHECK_CALC_GLR_CC([%define parse.error verbose %define api.prefix "calc" %verbose %yacc])

View File

@@ -131,7 +131,7 @@ AT_SETUP([Several parsers])
# self-contained, and can be compiled by a C++ compiler.
m4_pushdef([AT_TEST],
[AT_BISON_OPTION_PUSHDEFS([%define api.prefix "$1_" $2])
AT_DATA_GRAMMAR([$1.AT_SKEL_CC_IF([yy], [y])],
AT_DATA_GRAMMAR([$1.y],
[[%define api.prefix "$1_"
$2
%error-verbose
@@ -161,7 +161,7 @@ exp:
]AT_YYLEX_DEFINE(["$1"])[
]])
AT_BISON_CHECK([-d -o AT_SKEL_CC_IF([$1.cc $1.yy], [$1.c $1.y])])
AT_BISON_CHECK([-d -o $1.AT_SKEL_CC_IF([cc], [c]) $1.y])
# Check there is no 'yy' left.
# C++ output relies on namespaces and still uses yy a lot.

View File

@@ -751,7 +751,7 @@ AT_SETUP([Java stype, position_class and location_class])
AT_CHECK_JAVA_MINIMAL([[
%define stype "java.awt.Color"
%type<java.awt.Color> start;
%define location_type "MyLoc"
%define api.location.type "MyLoc"
%define position_type "MyPos"
%code { class MyPos {} }]], [[$$ = $<java.awt.Color>1;]], [[MyPos]])
AT_CHECK([[grep 'java.awt.Color' YYParser.java]], [0], [ignore])
@@ -761,7 +761,7 @@ AT_CHECK([[$EGREP -v ' */?\*' YYParser.java | grep 'Location']], [1], [ignore])
AT_CHECK_JAVA_MINIMAL_W_LEXER([[
%define stype "java.awt.Color"
%type<java.awt.Color> start;
%define location_type "MyLoc"
%define api.location.type "MyLoc"
%define position_type "MyPos"
%code { class MyPos {} }]], [], [[return EOF;]], [],
[[$$ = $<java.awt.Color>1;]],

View File

@@ -137,7 +137,7 @@ m4_pushdef([AT_LEXPARAM_IF],
m4_pushdef([AT_LOCATION_IF],
[m4_bmatch([$3], [%locations], [$1], [$2])])
m4_pushdef([AT_LOCATION_TYPE_IF],
[m4_bmatch([$3], [%define location_type], [$1], [$2])])
[m4_bmatch([$3], [%define \(api\.location\.type\|location_type\)], [$1], [$2])])
m4_pushdef([AT_PARAM_IF],
[m4_bmatch([$3], [%parse-param], [$1], [$2])])
m4_pushdef([AT_PURE_IF],

View File

@@ -216,4 +216,54 @@ exp: '0';
[input.y:8: #error "8"
])
## -------------------- ##
## %code top syncline. ##
## -------------------- ##
AT_TEST([%code top syncline],
[[%code top {
#error "2"
}
%{
]AT_YYERROR_DECLARE_EXTERN[
]AT_YYLEX_DECLARE_EXTERN[
%}
%%
exp: '0';
%%
]],
[input.y:2: #error "2"
])
m4_popdef([AT_TEST])
## ----------- ##
## %no-lines. ##
## ----------- ##
m4_pushdef([AT_TEST],
[AT_SETUP([%no-lines])
AT_BISON_OPTION_PUSHDEFS([%skeleton "$1" %defines])
AT_DATA_GRAMMAR([input.y],
[%skeleton "$1" %defines
%{
]AT_YYERROR_DECLARE_EXTERN[
]AT_YYLEX_DECLARE_EXTERN[
%}
%%
exp: '0'
])
AT_BISON_CHECK([--no-lines -o input.AT_SKEL_CC_IF([cc], [c]) -d input.y])
AT_CHECK([[grep '#line' ]AT_SKEL_CC_IF([*.cc *.hh], [*.c *.h])], 1)
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])