From 211c818502252259ed149a28c4c3139249fad990 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 9 Oct 2012 12:12:52 +0200 Subject: [PATCH 01/12] maint: more macros * src/output.c (ARRAY_CARDINALITY): Move to... * src/system.h: here. (STREQ, STRNEQ): new. --- src/output.c | 2 -- src/system.h | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/output.c b/src/output.c index e77a2d1a..a99ef4cd 100644 --- a/src/output.c +++ b/src/output.c @@ -41,8 +41,6 @@ #include "symtab.h" #include "tables.h" -# define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array)) - static struct obstack format_obstack; diff --git a/src/system.h b/src/system.h index bf7f59f9..a8b0f584 100644 --- a/src/system.h +++ b/src/system.h @@ -41,6 +41,10 @@ # include # include +#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. */ From 2aa5b2599509ca941dd817bcab47207f5d8cee1d Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 9 Oct 2012 12:13:55 +0200 Subject: [PATCH 02/12] muscles: a function for backward compatibility Based on commit 171ad99d6421935a278656be6dc7161591835d00 from master. * src/muscle-tab.c (muscle_percent_variable_update): New. (muscle_percent_define_insert): Use it. Define the variables with their initial value. --- src/muscle-tab.c | 61 +++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/muscle-tab.c b/src/muscle-tab.c index 37a0f0e8..0136d821 100644 --- a/src/muscle-tab.c +++ b/src/muscle-tab.c @@ -396,31 +396,45 @@ muscle_user_name_list_grow (char const *key, char const *user_name, muscle_grow (key, "]]", ""); } +/** If the \a variable name is obsolete, return the name to use, + * otherwise \a variable. */ +static +char const * +muscle_percent_variable_update (char const *variable) +{ + typedef struct + { + const char *obsolete; + const char *updated; + } conversion_type; + const conversion_type conversion[] = + { + { "api.push_pull", "api.push-pull", }, + { "lr.keep_unreachable_states", "lr.keep-unreachable-states", }, + }; + char const *res = variable; + int i; + for (i = 0; i < ARRAY_CARDINALITY (conversion); ++i) + if (STREQ (conversion[i].obsolete, variable)) + { + res = conversion[i].updated; + break; + } + return res; +} + 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 *variable_tr = NULL; - char const *name; - char const *loc_name; - char const *syncline_name; - char const *how_name; - - /* Permit certain names with underscores for backward compatibility. */ - if (0 == strcmp (variable, "api.push_pull") - || 0 == strcmp (variable, "lr.keep_unreachable_states")) - { - variable_tr = strdup (variable); - tr (variable_tr, '_', '-'); - variable = variable_tr; - } - - 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); + 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 @@ -430,10 +444,7 @@ muscle_percent_define_insert (char const *variable, location variable_loc, muscle_percent_define_how how_old = atoi (muscle_find_const (how_name)); if (how_old == MUSCLE_PERCENT_DEFINE_F) - { - free (variable_tr); - return; - } + return; complain_at_indent (variable_loc, &i, _("%%define variable %s redefined"), quote (variable)); i += SUB_INDENT; @@ -449,8 +460,6 @@ muscle_percent_define_insert (char const *variable, location variable_loc, muscle_user_name_list_grow ("percent_define_user_variables", variable, variable_loc); MUSCLE_INSERT_INT (how_name, how); - - free (variable_tr); } char * From db8ab2be3337ef87629b761078ebc46a01e7f876 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 9 Oct 2012 12:09:59 +0200 Subject: [PATCH 03/12] c++: api.location.type This feature was introduced in 95a2de5695670ae0df98cb3c42141cad549f0204 (which is part of 2.5), but not documented. Give it a proper name, and make it public. * data/c++.m4, data/lalr1.cc, data/glr.cc, data/java.m4: Use api.location.type instead of location_type. * src/muscle-tab.c (muscle_percent_variable_update): Map the latter to the former. * tests/local.at: Adjust. * tests/calc.at: Use api.location.type. Leave tests/java.at with location_type, at least for the time being, to cover both names. * doc/bison.texi: Document api.location.type. (User Defined Location Type): New. * NEWS: Update. --- NEWS | 15 ++++++++ data/c++.m4 | 2 +- data/glr.cc | 6 +-- data/java.m4 | 4 +- data/lalr1.cc | 6 +-- doc/bison.texi | 98 +++++++++++++++++++++++++++++++++++++++++++----- src/muscle-tab.c | 1 + tests/calc.at | 4 +- tests/local.at | 2 +- 9 files changed, 117 insertions(+), 21 deletions(-) diff --git a/NEWS b/NEWS index 1fe419f4..a20898fc 100644 --- a/NEWS +++ b/NEWS @@ -65,6 +65,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 let the others + simply resue these types and files. + + 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 diff --git a/data/c++.m4 b/data/c++.m4 index 45c4ddaf..8b98b8c1 100644 --- a/data/c++.m4 +++ b/data/c++.m4 @@ -29,7 +29,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([[namespace]], m4_defn([b4_prefix])) diff --git a/data/glr.cc b/data/glr.cc index 826bc80e..6527b0a2 100644 --- a/data/glr.cc +++ b/data/glr.cc @@ -54,7 +54,7 @@ b4_defines_if([], [b4_fatal([b4_skeleton[: using %%defines is mandatory]])]) m4_include(b4_pkgdatadir/[c++.m4]) -b4_percent_define_ifdef([[location_type]], [], +b4_percent_define_ifdef([[api.location.type]], [], [m4_include(b4_pkgdatadir/[location.cc])]) m4_define([b4_parser_class_name], @@ -238,7 +238,7 @@ b4_copyright([Skeleton interface for Bison GLR parsers in C++], # include # include -]b4_percent_define_ifdef([[location_type]], [], +]b4_percent_define_ifdef([[api.location.type]], [], [[# include "location.hh"]])[ ]b4_YYDEBUG_define[ @@ -262,7 +262,7 @@ b4_user_stype typedef ]b4_api_PREFIX[STYPE semantic_type; # endif /// Symbol locations. - typedef ]b4_percent_define_get([[location_type]], + typedef ]b4_percent_define_get([[api.location.type]], [[location]])[ location_type; /// Tokens. struct token diff --git a/data/java.m4 b/data/java.m4 index 18ea30b5..351f0f0d 100644 --- a/data/java.m4 +++ b/data/java.m4 @@ -169,8 +169,8 @@ m4_define([b4_lex_throws], [b4_percent_define_get([[lex_throws]])]) b4_percent_define_default([[throws]], [])]) m4_define([b4_throws], [b4_percent_define_get([[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]])]) diff --git a/data/lalr1.cc b/data/lalr1.cc index 3b8c9215..46e58ae2 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -24,7 +24,7 @@ m4_define([b4_parser_class_name], b4_defines_if([], [b4_fatal([b4_skeleton[: using %%defines is mandatory]])]) -b4_percent_define_ifdef([[location_type]], [], +b4_percent_define_ifdef([[api.location.type]], [], [# Backward compatibility. m4_define([b4_location_constructors]) m4_include(b4_pkgdatadir/[location.cc])]) @@ -52,7 +52,7 @@ b4_copyright([Skeleton interface for Bison LALR(1) parsers in C++], #include #include #include "stack.hh" -]b4_percent_define_ifdef([[location_type]], [], +]b4_percent_define_ifdef([[api.location.type]], [], [[#include "location.hh"]])[ ]b4_YYDEBUG_define[ @@ -77,7 +77,7 @@ b4_user_stype typedef ]b4_api_PREFIX[STYPE semantic_type; #endif /// Symbol locations. - typedef ]b4_percent_define_get([[location_type]], + typedef ]b4_percent_define_get([[api.location.type]], [[location]])[ location_type; /// Tokens. struct token diff --git a/doc/bison.texi b/doc/bison.texi index ce1ebd11..75e80183 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -327,6 +327,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 @@ -5325,6 +5326,23 @@ Unaccepted @var{variable}s produce an error. Some of the accepted @var{variable}s are: @itemize @bullet +@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 @code{api.prefix} @findex %define api.prefix @@ -5332,7 +5350,7 @@ Some of the accepted @var{variable}s are: @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 @@ -9210,8 +9228,9 @@ generated 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. @xref{C++ Location Values}. +The definition of the classes @code{position} and @code{location}, used for +location tracking. 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. @@ -9267,18 +9286,22 @@ Symbols}. @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 genuine code only the latter is used. @menu -* C++ position:: One point in the source file -* C++ location:: Two points in the source file +* 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 @@ -9382,6 +9405,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 @} +@end example + @node C++ Parser Interface @subsection C++ Parser Interface @c - define parser_class_name diff --git a/src/muscle-tab.c b/src/muscle-tab.c index 0136d821..936af700 100644 --- a/src/muscle-tab.c +++ b/src/muscle-tab.c @@ -410,6 +410,7 @@ muscle_percent_variable_update (char const *variable) const conversion_type conversion[] = { { "api.push_pull", "api.push-pull", }, + { "location_type", "api.location.type", }, { "lr.keep_unreachable_states", "lr.keep-unreachable-states", }, }; char const *res = variable; diff --git a/tests/calc.at b/tests/calc.at index 9518c3c3..647d6589 100644 --- a/tests/calc.at +++ b/tests/calc.at @@ -713,7 +713,7 @@ m4_define([AT_CHECK_CALC_LALR1_CC], [AT_CHECK_CALC([%language "C++" %defines %locations] $@)]) AT_CHECK_CALC_LALR1_CC([]) -AT_CHECK_CALC_LALR1_CC([%define location_type Span]) +AT_CHECK_CALC_LALR1_CC([%define api.location.type Span]) AT_CHECK_CALC_LALR1_CC([%error-verbose %name-prefix "calc" %verbose %yacc]) AT_CHECK_CALC_LALR1_CC([%error-verbose %define api.prefix "calc" %verbose %yacc]) AT_CHECK_CALC_LALR1_CC([%error-verbose %debug %name-prefix "calc" %verbose %yacc]) @@ -742,7 +742,7 @@ m4_define([AT_CHECK_CALC_GLR_CC], [AT_CHECK_CALC([%language "C++" %glr-parser %defines %locations] $@)]) AT_CHECK_CALC_GLR_CC([]) -AT_CHECK_CALC_GLR_CC([%define location_type Span]) +AT_CHECK_CALC_GLR_CC([%define api.location.type Span]) AT_CHECK_CALC_GLR_CC([%error-verbose %name-prefix "calc" %verbose %yacc]) AT_CHECK_CALC_GLR_CC([%error-verbose %define api.prefix "calc" %verbose %yacc]) diff --git a/tests/local.at b/tests/local.at index 036b0a1d..65ff8870 100644 --- a/tests/local.at +++ b/tests/local.at @@ -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], From 47a31596c62b2d25dd68ca11df30dccef4944e13 Mon Sep 17 00:00:00 2001 From: Theophile Ranquet Date: Wed, 10 Oct 2012 17:14:01 +0000 Subject: [PATCH 04/12] obstack: import obstack_finish0 from master * src/system.h (obstack_finish0): New. Signed-off-by: Akim Demaille --- src/system.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/system.h b/src/system.h index a8b0f584..3a82e7f3 100644 --- a/src/system.h +++ b/src/system.h @@ -202,7 +202,10 @@ typedef size_t uintptr_t; } while (0) +/* Append the ending 0, finish Obs, and return the string. */ +# define obstack_finish0(Obs) \ + (obstack_1grow (Obs, '\0'), (char *) obstack_finish (Obs)) /*-----------------------------------------. From 2be37f19fe2165fcfd8752a30b55308a5bdb9b84 Mon Sep 17 00:00:00 2001 From: Theophile Ranquet Date: Wed, 10 Oct 2012 17:14:02 +0000 Subject: [PATCH 05/12] graphs: style: prefix rules and change shapes * src/graphviz.c (start_graph): Use box rather than ellipsis. * src/print_graph.c (print_core): Prefix rules with their number. Signed-off-by: Akim Demaille --- src/graphviz.c | 1 + src/print_graph.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/graphviz.c b/src/graphviz.c index 46c22a8c..c4eaa9f5 100644 --- a/src/graphviz.c +++ b/src/graphviz.c @@ -51,6 +51,7 @@ start_graph (FILE *fout) "digraph %s\n" "{\n", quote (grammar_file)); + fprintf (fout, "node [shape=box]\n"); } void diff --git a/src/print_graph.c b/src/print_graph.c index f5695a7a..88b2ceea 100644 --- a/src/print_graph.c +++ b/src/print_graph.c @@ -68,7 +68,7 @@ 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, "\n%d: %s -> ", r, rules[r].lhs->tag); for (sp = rules[r].rhs; sp < sp1; sp++) obstack_printf (oout, "%s ", symbols[*sp]->tag); From a13121f75994966dfbb7bed4de31dd7bb2516350 Mon Sep 17 00:00:00 2001 From: Theophile Ranquet Date: Mon, 8 Oct 2012 15:53:44 +0000 Subject: [PATCH 06/12] graphs: style: use left justification for states The label text of nodes is centered "by default" (by the use of '\n' as a line feed). This gives bad readability to the grammar rules shown in state nodes, a left justification is much nicer. This is done by using '\l' as the line feed. In order to allow \l in the DOT file, changes to the quoting system seem necessary. * src/print_graph.c (print_core): Escape tokens here, instead of... * src/graphviz.c (output_node): Here... (escape): Using this, new. Signed-off-by: Akim Demaille --- src/graphviz.c | 14 ++++++++++--- src/graphviz.h | 4 ++++ src/print_graph.c | 51 +++++++++++++++++++++++++---------------------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/graphviz.c b/src/graphviz.c index c4eaa9f5..6498884a 100644 --- a/src/graphviz.c +++ b/src/graphviz.c @@ -30,7 +30,7 @@ /* 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); @@ -57,12 +57,12 @@ start_graph (FILE *fout) 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 output_edge (int source, int destination, char const *label, - char const *style, FILE *fout) + char const *style, FILE *fout) { fprintf (fout, " %d -> %d [style=%s", source, destination, style); if (label) @@ -70,6 +70,14 @@ 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; +} + void finish_graph (FILE *fout) { diff --git a/src/graphviz.h b/src/graphviz.h index 556fdda1..62f26fb4 100644 --- a/src/graphviz.h +++ b/src/graphviz.h @@ -46,4 +46,8 @@ void output_edge (int source, int destination, char const *label, /// \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_ */ diff --git a/src/print_graph.c b/src/print_graph.c index 88b2ceea..d1496af7 100644 --- a/src/print_graph.c +++ b/src/print_graph.c @@ -18,6 +18,7 @@ along with this program. If not, see . */ #include +#include #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, "%d\\n", s->number); for (i = 0; i < snritems; i++) { item_number *sp; @@ -64,43 +65,45 @@ print_core (struct obstack *oout, state *s) sp1 = sp = ritem + sitems[i]; while (*sp >= 0) - sp++; + sp++; r = item_number_as_rule_number (*sp); - obstack_printf (oout, "\n%d: %s -> ", r, 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 && item_number_is_rule_number (*sp1)) - { - /* Find the reduction we are handling. */ - reductions *reds = s->reductions; - int redno = state_reduction_find (s, &rules[r]); + { + /* Find the reduction we are handling. */ + reductions *reds = s->reductions; + int redno = state_reduction_find (s, &rules[r]); - /* Print them if there are. */ - if (reds->lookahead_tokens && redno != -1) - { - bitset_iterator biter; - int k; - char const *sep = ""; - obstack_sgrow (oout, "["); - BITSET_FOR_EACH (biter, reds->lookahead_tokens[redno], k, 0) - { - obstack_printf (oout, "%s%s", sep, symbols[k]->tag); - sep = ", "; - } - obstack_sgrow (oout, "]"); - } - } + /* Print them if there are. */ + if (reds->lookahead_tokens && redno != -1) + { + bitset_iterator biter; + int k; + char const *sep = ""; + obstack_1grow (oout, '['); + BITSET_FOR_EACH (biter, reds->lookahead_tokens[redno], k, 0) + { + obstack_sgrow (oout, sep); + obstack_sgrow (oout, escape (symbols[k]->tag)); + sep = ", "; + } + obstack_1grow (oout, ']'); + } + } + obstack_sgrow (oout, "\\l"); } } From 9fc99ca35009c1be76ce1c73133833ad82562a8b Mon Sep 17 00:00:00 2001 From: Theophile Ranquet Date: Wed, 10 Oct 2012 17:14:04 +0000 Subject: [PATCH 07/12] graphs: style: prefix state number with "state" * src/print_graph.c (print_core): Here. Signed-off-by: Akim Demaille --- src/print_graph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/print_graph.c b/src/print_graph.c index d1496af7..2e3fd460 100644 --- a/src/print_graph.c +++ b/src/print_graph.c @@ -55,7 +55,7 @@ print_core (struct obstack *oout, state *s) snritems = nitemset; } - obstack_printf (oout, "%d\\n", s->number); + obstack_printf (oout, "state %d\\n", s->number); for (i = 0; i < snritems; i++) { item_number *sp; From 83bae26d3f9b374fb189703aa8795ecb3240bab2 Mon Sep 17 00:00:00 2001 From: Theophile Ranquet Date: Mon, 8 Oct 2012 06:11:41 +0000 Subject: [PATCH 08/12] graphs: show reductions * src/graphviz.c (output_red): New, show reductions on the graph. (no_reduce_bitset_init): New, initialize a bitset. (print_token): New, print a lookahead token. (escape): New, print "foo" as \"foo\" because Dot doesn't like quotes within a label. * src/graphviz.h : Adjust. * src/print_graph.c (print_actions): Call output_red here. Signed-off-by: Akim Demaille --- src/graphviz.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++ src/graphviz.h | 10 +++++- src/print_graph.c | 3 ++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/graphviz.c b/src/graphviz.c index 6498884a..a2baa160 100644 --- a/src/graphviz.c +++ b/src/graphviz.c @@ -25,7 +25,9 @@ #include #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. */ @@ -78,6 +80,86 @@ escape (char const *name) 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) +{ + int source = s->number; + int i, j; + bitset no_reduce_set; + no_reduce_bitset_init (s, &no_reduce_set); + + struct obstack oout; + obstack_init (&oout); + + for (j = 0; j < reds->num; ++j) + { + bool first = true; + bool disabled = false; + 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 + 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. This most be done later + because the we need the previously determined boolean to know if this + reduction is disabled or not. */ + 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) { diff --git a/src/graphviz.h b/src/graphviz.h index 62f26fb4..371b15c5 100644 --- a/src/graphviz.h +++ b/src/graphviz.h @@ -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); @@ -40,7 +42,13 @@ void output_node (int id, char const *label, FILE *fout); /// \param style Dot style of the edge (e.g., "dotted" or "solid"). /// \param fout output stream. void output_edge (int source, int destination, char const *label, - char const *style, FILE *fout); + 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. diff --git a/src/print_graph.c b/src/print_graph.c index 2e3fd460..b9021014 100644 --- a/src/print_graph.c +++ b/src/print_graph.c @@ -120,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; From d79683fa95d91c3afd4de8ee010d0d013a84a222 Mon Sep 17 00:00:00 2001 From: Theophile Ranquet Date: Thu, 11 Oct 2012 16:09:03 +0000 Subject: [PATCH 09/12] graphs: minor style changes * src/graphviz.c (output_red): Fix C90 issues. Reduce variable scopes. Signed-off-by: Akim Demaille --- src/graphviz.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/graphviz.c b/src/graphviz.c index a2baa160..b37a28e0 100644 --- a/src/graphviz.c +++ b/src/graphviz.c @@ -107,20 +107,21 @@ print_token (struct obstack *out, bool first, char const *tok) void output_red (state const *s, reductions const *reds, FILE *fout) { - int source = s->number; - int i, j; bitset no_reduce_set; - no_reduce_bitset_init (s, &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 first = true; 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]; @@ -131,13 +132,16 @@ output_red (state const *s, reductions const *reds, FILE *fout) if (default_reduction && default_reduction == reds->rules[j]) first = print_token (&oout, true, "$default"); else - for (i = 0; i < ntokens; i++) + { + 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. This most be done later From 43eb7674aaa06d60ac612965d2f8b1a08afc0b73 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Thu, 11 Oct 2012 16:58:03 +0200 Subject: [PATCH 10/12] graphs: stylistic changes. * src/graphviz.c (output_red): Comment and formatting changes. --- src/graphviz.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/graphviz.c b/src/graphviz.c index b37a28e0..e62ee1d4 100644 --- a/src/graphviz.c +++ b/src/graphviz.c @@ -144,12 +144,12 @@ output_red (state const *s, reductions const *reds, FILE *fout) } obstack_sgrow (&oout, "\" style=solid]\n"); - /* Then, print the reduction's representation. This most be done later - because the we need the previously determined boolean to know if this - reduction is disabled or not. */ - obstack_printf (&oout, " \"%dR%d\" " - "[style=filled shape=diamond fillcolor=%s " - "label=\"R%d\"]\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); From d74d8cb6c547a726e0af8ddc12b7d4ff426ce078 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Fri, 12 Oct 2012 10:09:40 +0200 Subject: [PATCH 11/12] tests: minor simplification * tests/headers.at (Several parsers): Use *.y even for C++. --- tests/headers.at | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/headers.at b/tests/headers.at index 8e70a7eb..96a75583 100644 --- a/tests/headers.at +++ b/tests/headers.at @@ -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. From e94ca80bbb9e2fe181a0c5376403113c4d3bc153 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Fri, 12 Oct 2012 10:10:18 +0200 Subject: [PATCH 12/12] tests: check %no-lines * tests/synclines.at: here. --- tests/synclines.at | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/synclines.at b/tests/synclines.at index 041ae194..63ae6858 100644 --- a/tests/synclines.at +++ b/tests/synclines.at @@ -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])