summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.prev-version2
-rw-r--r--NEWS97
-rw-r--r--README-hacking25
-rw-r--r--TODO12
-rw-r--r--cfg.mk1
-rw-r--r--configure.ac17
-rw-r--r--data/c.m42
-rw-r--r--data/java.m42
-rw-r--r--data/xslt/xml2dot.xsl26
-rw-r--r--data/yacc.c8
-rw-r--r--doc/bison.texi112
-rw-r--r--doc/figs/example-reduce.dot11
-rw-r--r--doc/figs/example-reduce.txt13
-rw-r--r--doc/figs/example-shift.dot9
-rw-r--r--doc/figs/example-shift.txt12
-rw-r--r--doc/local.mk30
m---------gnulib0
-rw-r--r--src/graphviz.c110
-rw-r--r--src/location.h2
-rw-r--r--src/parse-gram.y8
-rw-r--r--src/print_graph.c37
-rw-r--r--src/reader.h4
-rw-r--r--src/scan-gram.h2
-rw-r--r--tests/local.at12
-rw-r--r--tests/output.at365
-rw-r--r--tests/torture.at2
26 files changed, 793 insertions, 128 deletions
diff --git a/.prev-version b/.prev-version
index 097a15a2..2714f531 100644
--- a/.prev-version
+++ b/.prev-version
@@ -1 +1 @@
-2.6.2
+2.6.4
diff --git a/NEWS b/NEWS
index 346c4da4..a2ea735e 100644
--- a/NEWS
+++ b/NEWS
@@ -242,6 +242,61 @@ GNU Bison NEWS
* Noteworthy changes in release ?.? (????-??-??) [?]
+** Changes in the format of error messages
+
+ This used to be the format of many error reports:
+
+ foo.y:5.10-24: result type clash on merge function 'merge': <t3> != <t2>
+ foo.y:4.13-27: previous declaration
+
+ It is now:
+
+ foo.y:5.10-25: result type clash on merge function 'merge': <t3> != <t2>
+ foo.y:4.13-27: previous declaration
+
+** Exception safety (lalr1.cc)
+
+ The parse function now catches exceptions, uses the %destructors to
+ release memory (the lookahead symbol and the symbols pushed on the stack)
+ before re-throwing the exception.
+
+ This feature is somewhat experimental. User feedback would be
+ appreciated.
+
+** New %define variable: api.location.type (glr.cc, lalr1.cc, lalr1.java)
+
+ 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).
+
+ For consistency, lalr1.java's %define variables location_type and
+ position_type are deprecated in favor of api.location.type and
+ api.position.type.
+
+** Graphviz improvements
+
+ The graphical presentation of the states is more readable: their shape is
+ now rectangular, the state number is clearly displayed, and the items are
+ numbered and left-justified.
+
+ The reductions are now explicitly represented as transitions to other
+ diamond shaped nodes.
+
+* Noteworthy changes in release 2.6.4 (2012-10-23) [stable]
+
+ Bison 2.6.3's --version was incorrect. This release fixes this issue.
+
+* Noteworthy changes in release 2.6.3 (2012-10-22) [stable]
+
** Bug fixes
Bugs and portability issues in the test suite have been fixed.
@@ -256,18 +311,6 @@ GNU Bison NEWS
All the generated headers are self-contained.
-** Changes in the format of error messages
-
- This used to be the format of many error reports:
-
- foo.y:5.10-24: result type clash on merge function 'merge': <t3> != <t2>
- foo.y:4.13-27: previous declaration
-
- It is now:
-
- foo.y:5.10-25: result type clash on merge function 'merge': <t3> != <t2>
- foo.y:4.13-27: previous declaration
-
** Header guards (yacc.c, glr.c, glr.cc)
In order to avoid collisions, the header guards are now
@@ -279,15 +322,6 @@ GNU Bison NEWS
will use YY_CALC_LIB_PARSE_H_INCLUDED as guard.
-** Exception safety (lalr1.cc)
-
- The parse function now catches exceptions, uses the %destructors to
- release memory (the lookahead symbol and the symbols pushed on the stack)
- before re-throwing the exception.
-
- This feature is somewhat experimental. User feedback would be
- appreciated.
-
** Fix compiler warnings in the generated parser (yacc.c, glr.c)
The compilation of pure parsers (%define api.pure) can trigger GCC
@@ -305,25 +339,6 @@ GNU Bison NEWS
"function declared 'noreturn' should not return") have also been
addressed.
-** New %define variable: api.location.type (glr.cc, lalr1.cc, lalr1.java)
-
- 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).
-
- For consistency, lalr1.java's %define variables location_type and
- position_type are deprecated in favor of api.location.type and
- api.position.type.
-
* Noteworthy changes in release 2.6.2 (2012-08-03) [stable]
** Bug fixes
@@ -380,7 +395,7 @@ GNU Bison NEWS
* Noteworthy changes in release 2.6 (2012-07-19) [stable]
-** Future changes:
+** Future changes
The next major release of Bison will drop support for the following
deprecated features. Please report disagreements to bug-bison@gnu.org.
diff --git a/README-hacking b/README-hacking
index ff5b4345..71680100 100644
--- a/README-hacking
+++ b/README-hacking
@@ -50,16 +50,17 @@ These requirements do not apply when building from a distribution tarball.
** Requirements
-We've opted to keep only the highest-level sources in the repository.
-This eases our maintenance burden, (fewer merges etc.), but imposes more
+We've opted to keep only the highest-level sources in the repository. This
+eases our maintenance burden, (fewer merges etc.), but imposes more
requirements on anyone wishing to build from the just-checked-out sources.
For example, you have to use the latest stable versions of the maintainer
tools we depend upon, including:
-- Automake <http://www.gnu.org/software/automake/>
- Autoconf <http://www.gnu.org/software/autoconf/>
+- Automake <http://www.gnu.org/software/automake/>
- Flex <http://www.gnu.org/software/flex/>
- Gettext <http://www.gnu.org/software/gettext/>
+- Graphviz <http://www.graphviz.org>
- Gzip <http://www.gnu.org/software/gzip/>
- Perl <http://www.cpan.org/>
- Rsync <http://samba.anu.edu.au/rsync/>
@@ -68,16 +69,16 @@ tools we depend upon, including:
Valgrind <http://valgrind.org/> is also highly recommended, if it supports
your architecture.
-Bison is written using Bison grammars, so there are bootstrapping
-issues. The bootstrap script attempts to discover when the C code
-generated from the grammars is out of date, and to bootstrap with an
-out-of-date version of the C code, but the process is not foolproof.
-Also, you may run into similar problems yourself if you modify Bison.
+Bison is written using Bison grammars, so there are bootstrapping issues.
+The bootstrap script attempts to discover when the C code generated from the
+grammars is out of date, and to bootstrap with an out-of-date version of the
+C code, but the process is not foolproof. Also, you may run into similar
+problems yourself if you modify Bison.
-Only building the initial full source tree will be a bit painful.
-Later, after synchronizing from the repository a plain 'make' should
-be sufficient. Note, however, that when gnulib is updated, running
-'./bootstrap' again might be needed.
+Only building the initial full source tree will be a bit painful. Later,
+after synchronizing from the repository a plain 'make' should be sufficient.
+Note, however, that when gnulib is updated, running './bootstrap' again
+might be needed.
** First checkout
diff --git a/TODO b/TODO
index 40127468..e8509e3c 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,16 @@
* Short term
+** Graphviz display code thoughts
+The code for the --graph option is over two files: print_graph, and
+graphviz. I believe this is because Bison used to also produce VCG graphs,
+but since this is no longer true, maybe we could consider these files for
+fusion.
+
+Little effort factoring seems to have been given to factoring in these files,
+and their print-xml and print counterpart. We would very much like to re-use
+the pretty format of states from .output in the .dot
+
+Also, the underscore in print_graph.[ch] isn't very fitting considering
+the dashes in the other filenames.
** push-parser
Check it too when checking the different kinds of parsers. And be
diff --git a/cfg.mk b/cfg.mk
index e50c6293..8e5a8e10 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -24,6 +24,7 @@ regen: _version
# Used in maint.mk's web-manual rule
manual_title = The Yacc-compatible Parser Generator
+gendocs_options_ = -I $(abs_top_srcdir)/doc -I $(abs_top_builddir)/doc
# It's useful to run maintainer-*check* targets during development, but we
# don't want to wait on a recompile because of an update to $(VERSION). Thus,
diff --git a/configure.ac b/configure.ac
index d6a86a73..8a297ff5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -75,6 +75,18 @@ if test "$enable_gcc_warnings" = yes; then
warn_cxx='-Wnoexcept'
AC_LANG_PUSH([C])
+ # Clang supports many of GCC's -W options, but only issues warnings
+ # on the ones it does not recognize. In that case, gl_WARN_ADD
+ # thinks the option is supported, and unknown options are then added
+ # to CFLAGS. But then, when -Werror is added in the test suite for
+ # instance, the warning about the unknown option turns into an
+ # error.
+ #
+ # This should be addressed by gnulib's gl_WARN_ADD, but in the
+ # meanwhile, turn warnings about unknown options into errors in
+ # CFLAGS, and restore CFLAGS after the tests.
+ save_CFLAGS=$CFLAGS
+ gl_WARN_ADD([-Werror=unknown-warning-option], [CFLAGS])
for i in $warn_common $warn_c;
do
gl_WARN_ADD([$i], [WARN_CFLAGS])
@@ -83,9 +95,12 @@ if test "$enable_gcc_warnings" = yes; then
# Warnings for the test suite only.
gl_WARN_ADD([-Wundef], [WARN_CFLAGS_TEST])
gl_WARN_ADD([-pedantic], [WARN_CFLAGS_TEST])
+ CFLAGS=$save_CFLAGS
AC_LANG_POP([C])
AC_LANG_PUSH([C++])
+ save_CXXFLAGS=$CXXFLAGS
+ gl_WARN_ADD([-Werror=unknown-warning-option], [CXXFLAGS])
for i in $warn_common $warn_cxx;
do
gl_WARN_ADD([$i], [WARN_CXXFLAGS])
@@ -96,6 +111,7 @@ if test "$enable_gcc_warnings" = yes; then
# Warnings for the test suite only.
gl_WARN_ADD([-Wundef], [WARN_CXXFLAGS_TEST])
gl_WARN_ADD([-pedantic], [WARN_CXXFLAGS_TEST])
+ CXXFLAGS=$save_CXXFLAGS
AC_LANG_POP([C++])
fi
@@ -118,6 +134,7 @@ AC_SUBST([YACC_SCRIPT])
AC_SUBST([YACC_LIBRARY])
# Checks for programs.
+AM_MISSING_PROG([DOT], [dot])
AC_PROG_LEX
$LEX_IS_FLEX || AC_MSG_ERROR([Flex is required])
AC_PROG_YACC
diff --git a/data/c.m4 b/data/c.m4
index 179743c9..51ffbe3b 100644
--- a/data/c.m4
+++ b/data/c.m4
@@ -557,7 +557,7 @@ m4_define([b4_YYDEBUG_define],
# endif
# else /* ! defined YYDEBUG */
# define ]b4_api_PREFIX[DEBUG ]b4_parse_trace_if([1], [0])[
-# endif /* ! defined ]b4_api_PREFIX[DEBUG */
+# endif /* ! defined YYDEBUG */
#endif /* ! defined ]b4_api_PREFIX[DEBUG */]])[]dnl
])
diff --git a/data/java.m4 b/data/java.m4
index 2bbd09ac..90d01b33 100644
--- a/data/java.m4
+++ b/data/java.m4
@@ -200,7 +200,7 @@ m4_define([b4_init_throws], [b4_percent_define_get([[init_throws]])])
b4_percent_define_default([[api.location.type]], [Location])
m4_define([b4_location_type], [b4_percent_define_get([[api.location.type]])])
-b4_percent_define_default([[api.position.type]], [Position])])
+b4_percent_define_default([[api.position.type]], [Position])
m4_define([b4_position_type], [b4_percent_define_get([[api.position.type]])])
diff --git a/data/xslt/xml2dot.xsl b/data/xslt/xml2dot.xsl
index 49f454bb..111613ce 100644
--- a/data/xslt/xml2dot.xsl
+++ b/data/xslt/xml2dot.xsl
@@ -55,7 +55,11 @@
<xsl:call-template name="escape">
<xsl:with-param name="subject" select="$filename"/>
</xsl:call-template>
- <xsl:text>"&#10;{&#10;</xsl:text>
+ <xsl:text>&#10;{
+ node [fontname = courier, shape = box, colorscheme = paired6]
+ edge [fontname = courier]
+
+</xsl:text>
<xsl:apply-templates select="state"/>
<xsl:text>}&#10;</xsl:text>
</xsl:template>
@@ -124,20 +128,20 @@
<xsl:with-param name="dst" select="@state"/>
<xsl:with-param name="style">
<xsl:choose>
- <xsl:when test="@symbol = 'error'">
- <xsl:text>dotted</xsl:text>
- </xsl:when>
- <xsl:when test="@type = 'shift'">
- <xsl:text>solid</xsl:text>
- </xsl:when>
- <xsl:otherwise>
- <xsl:text>dashed</xsl:text>
- </xsl:otherwise>
+ <xsl:when test="@symbol = 'error'">
+ <xsl:text>dotted</xsl:text>
+ </xsl:when>
+ <xsl:when test="@type = 'shift'">
+ <xsl:text>solid</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>dashed</xsl:text>
+ </xsl:otherwise>
</xsl:choose>
</xsl:with-param>
<xsl:with-param name="label">
<xsl:if test="not(@symbol = 'error')">
- <xsl:value-of select="@symbol"/>
+ <xsl:value-of select="@symbol"/>
</xsl:if>
</xsl:with-param>
</xsl:call-template>
diff --git a/data/yacc.c b/data/yacc.c
index a1d45c43..9ff20322 100644
--- a/data/yacc.c
+++ b/data/yacc.c
@@ -685,18 +685,14 @@ while (0)
# else
# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
# endif
-#endif]], [[
-
-
-/* This macro is provided for backward compatibility. */
-
+#endif]],
+[[/* This macro is provided for backward compatibility. */
#ifndef YY_LOCATION_PRINT
# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
#endif]])[
/* YYLEX -- calling `yylex' with the right arguments. */
-
#ifdef YYLEX_PARAM
# define YYLEX yylex (]b4_pure_if([&yylval[]b4_locations_if([, &yylloc]), ])[YYLEX_PARAM)
#else
diff --git a/doc/bison.texi b/doc/bison.texi
index 84ec16d9..3b9f2da2 100644
--- a/doc/bison.texi
+++ b/doc/bison.texi
@@ -298,6 +298,7 @@ Handling Context Dependencies
Debugging Your Parser
* Understanding:: Understanding the structure of your parser.
+* Graphviz:: Getting a visual representation of the parser.
* Tracing:: Tracing the execution of your parser.
Tracing Your Parser
@@ -8422,6 +8423,7 @@ automaton, and how to enable and understand the parser run-time traces.
@menu
* Understanding:: Understanding the structure of your parser.
+* Graphviz:: Getting a visual representation of the parser.
* Tracing:: Tracing the execution of your parser.
@end menu
@@ -8838,6 +8840,114 @@ precedence of @samp{/} with respect to @samp{+}, @samp{-}, and
@samp{*}, but also because the
associativity of @samp{/} is not specified.
+@c ================================================= Graphical Representation
+
+@node Graphviz
+@section Visualizing Your Parser
+@cindex dot
+
+As another means to gain better understanding of the shift/reduce
+automaton corresponding to the Bison parser, a DOT file can be generated. Note
+that debugging a real grammar with this is tedious at best, and impractical
+most of the times, because the generated files are huge (the generation of
+a PDF or PNG file from it will take very long, and more often than not it will
+fail due to memory exhaustion). This option was rather designed for beginners,
+to help them understand LR parsers.
+
+This file is generated when the @option{--graph} option is specified (see
+@pxref{Invocation, , Invoking Bison}). Its name is made by removing
+@samp{.tab.c} or @samp{.c} from the parser implementation file name, and
+adding @samp{.dot} instead. If the grammar file is @file{foo.y}, the
+Graphviz output file is called @file{foo.dot}.
+
+The following grammar file, @file{rr.y}, will be used in the sequel:
+
+@example
+%%
+@group
+exp: a ";" | b ".";
+a: "0";
+b: "0";
+@end group
+@end example
+
+The graphical output is very similar to the textual one, and as such it is
+easier understood by making direct comparisons between them. See
+@ref{Debugging, , Debugging Your Parser} for a detailled analysis of the
+textual report.
+
+@subheading Graphical Representation of States
+
+The items (pointed rules) for each state are grouped together in graph nodes.
+Their numbering is the same as in the verbose file. See the following points,
+about transitions, for examples
+
+When invoked with @option{--report=lookaheads}, the lookahead tokens, when
+needed, are shown next to the relevant rule between square brackets as a
+comma separated list. This is the case in the figure for the representation of
+reductions, below.
+
+@sp 1
+
+The transitions are represented as directed edges between the current and
+the target states.
+
+@subheading Graphical Representation of Shifts
+
+Shifts are shown as solid arrows, labelled with the lookahead token for that
+shift. The following describes a reduction in the @file{rr.output} file:
+
+@example
+@group
+state 3
+
+ 1 exp: a . ";"
+
+ ";" shift, and go to state 6
+@end group
+@end example
+
+A Graphviz rendering of this portion of the graph could be:
+
+@center @image{figs/example-shift, 100pt}
+
+@subheading Graphical Representation of Reductions
+
+Reductions are shown as solid arrows, leading to a diamond-shaped node
+bearing the number of the reduction rule. The arrow is labelled with the
+appropriate comma separated lookahead tokens. If the reduction is the default
+action for the given state, there is no such label.
+
+This is how reductions are represented in the verbose file @file{rr.output}:
+@example
+state 1
+
+ 3 a: "0" . [";"]
+ 4 b: "0" . ["."]
+
+ "." reduce using rule 4 (b)
+ $default reduce using rule 3 (a)
+@end example
+
+A Graphviz rendering of this portion of the graph could be:
+
+@center @image{figs/example-reduce, 120pt}
+
+When unresolved conflicts are present, because in deterministic parsing
+a single decision can be made, Bison can arbitrarily choose to disable a
+reduction, see @ref{Shift/Reduce, , Shift/Reduce Conflicts}. Discarded actions
+are distinguished by a red filling color on these nodes, just like how they are
+reported between square brackets in the verbose file.
+
+The reduction corresponding to the rule number 0 is the acceptation state. It
+is shown as a blue diamond, labelled "Acc".
+
+@subheading Graphical representation of go tos
+
+The @samp{go to} jump transitions are represented as dotted lines bearing
+the name of the rule being jumped to.
+
+@c ================================================= Tracing
@node Tracing
@section Tracing Your Parser
@@ -12580,9 +12690,9 @@ London, Department of Computer Science, TR-00-12 (December 2000).
@c LocalWords: subdirectory Solaris nonassociativity perror schemas Malloy ints
@c LocalWords: Scannerless ispell american ChangeLog smallexample CSTYPE CLTYPE
@c LocalWords: clval CDEBUG cdebug deftypeopx yyterminate LocationType
+@c LocalWords: errorVerbose
@c Local Variables:
@c ispell-dictionary: "american"
@c fill-column: 76
@c End:
-@c LocalWords: errorVerbose
diff --git a/doc/figs/example-reduce.dot b/doc/figs/example-reduce.dot
new file mode 100644
index 00000000..fdd99c5d
--- /dev/null
+++ b/doc/figs/example-reduce.dot
@@ -0,0 +1,11 @@
+digraph "reduce.y"
+{
+ node [fontname=courier shape=box]
+ edge [fontname=courier]
+
+ 1 [label="State 1\n 3 a: \"0\" . [\".\"]\l 4 b: \"0\" . [\";\"]\l"]
+ 1 -> "1R3" [label="" style=solid]
+ "1R3" [style=filled shape=diamond fillcolor=yellowgreen label="R3"]
+ 1 -> "1R4" [label="[\";\"]" style=solid]
+ "1R4" [style=filled shape=diamond fillcolor=yellowgreen label="R4"]
+}
diff --git a/doc/figs/example-reduce.txt b/doc/figs/example-reduce.txt
new file mode 100644
index 00000000..d4e8219f
--- /dev/null
+++ b/doc/figs/example-reduce.txt
@@ -0,0 +1,13 @@
+ .------------------.
+ | State 1 |
+ | 3 a: "0" . [";"] |
+ | 4 b: "0" . ["."] |
+ `------------------'
+ / \
+ / \ ["."]
+ / \
+ v v
+ / \ / \
+ / R \ / R \
+(green) \ 3 / \ 4 / (green)
+ \ / \ /
diff --git a/doc/figs/example-shift.dot b/doc/figs/example-shift.dot
new file mode 100644
index 00000000..995ba0e4
--- /dev/null
+++ b/doc/figs/example-shift.dot
@@ -0,0 +1,9 @@
+digraph "shift.y"
+{
+ node [fontname=courier shape=box]
+ edge [fontname=courier]
+
+ 3 [label="State 3\n 1 exp: a . \".\"\l"]
+ 3 -> 6 [style=solid label="\".\""]
+ 6 [label="State 6\n 1 exp: a \".\" .\l"]
+}
diff --git a/doc/figs/example-shift.txt b/doc/figs/example-shift.txt
new file mode 100644
index 00000000..43b14122
--- /dev/null
+++ b/doc/figs/example-shift.txt
@@ -0,0 +1,12 @@
+.----------------.
+| State 3 |
+| 1 exp: a . ";" |
+`----------------'
+ |
+ | ";"
+ |
+ v
+.----------------.
+| State 6 |
+| 1 exp: a ";" . |
+`----------------'
diff --git a/doc/local.mk b/doc/local.mk
index 54c03ebf..53c0142d 100644
--- a/doc/local.mk
+++ b/doc/local.mk
@@ -112,6 +112,36 @@ $(top_srcdir)/doc/bison.1: doc/bison.help doc/bison.x $(top_srcdir)/configure
nodist_man_MANS = doc/yacc.1
+## ----------------------------- ##
+## Graphviz examples generation. ##
+## ----------------------------- ##
+
+CLEANDIRS += doc/figs
+FIGS_DOT = doc/figs/example-reduce.dot doc/figs/example-shift.dot
+EXTRA_DIST += \
+ $(FIGS_DOT) \
+ $(FIGS_DOT:.dot=.eps) $(FIGS_DOT:.dot=.pdf) $(FIGS_DOT:.dot=.png)
+SUFFIXES += .dot .eps .pdf .png
+
+bison.dvi: $(FIGS_DOT:.dot=.eps)
+bison.html: $(FIGS_DOT:.dot=.png)
+bison.pdf: $(FIGS_DOT:.dot=.pdf)
+
+.dot.eps:
+ $(AM_V_GEN) $(MKDIR_P) `echo "./$@" | sed -e 's,/[^/]*$$,,'`
+ $(AM_V_at) $(DOT) -Gmargin=0 -Teps $< >$@.tmp
+ $(AM_V_at) mv $@.tmp $@
+
+.dot.pdf:
+ $(AM_V_GEN) $(MKDIR_P) `echo "./$@" | sed -e 's,/[^/]*$$,,'`
+ $(AM_V_at) $(DOT) -Gmargin=0 -Tpdf $< >$@.tmp
+ $(AM_V_at) mv $@.tmp $@
+
+.dot.png:
+ $(AM_V_GEN) $(MKDIR_P) `echo "./$@" | sed -e 's,/[^/]*$$,,'`
+ $(AM_V_at) $(DOT) -Gmargin=0 -Tpng $< >$@.tmp
+ $(AM_V_at) mv $@.tmp $@
+
## -------------- ##
## Doxygenation. ##
## -------------- ##
diff --git a/gnulib b/gnulib
-Subproject dcf27bef48c9800d5a2be8349226f73f1b8ff2e
+Subproject 6061979365c067965ee376b3d0a65819779a89c
diff --git a/src/graphviz.c b/src/graphviz.c
index e62ee1d4..3ae0b546 100644
--- a/src/graphviz.c
+++ b/src/graphviz.c
@@ -53,7 +53,10 @@ start_graph (FILE *fout)
"digraph %s\n"
"{\n",
quote (grammar_file));
- fprintf (fout, "node [shape=box]\n");
+ fprintf (fout,
+ " node [fontname = courier, shape = box, colorscheme = paired6]\n"
+ " edge [fontname = courier]\n"
+ "\n");
}
void
@@ -93,13 +96,54 @@ no_reduce_bitset_init (state const *s, bitset *no_reduce_set)
bitset_set (*no_reduce_set, s->errs->symbols[n]->number);
}
+static void
+conclude_red (struct obstack *out, int source, rule_number ruleno,
+ bool enabled, bool first, FILE *fout)
+{
+ /* If no lookahead tokens were valid transitions, this reduction is
+ actually hidden, so cancel everything. */
+ if (first)
+ return (void) obstack_finish0 (out);
+ else
+ {
+ char const *ed = enabled ? "e" : "d";
+ char const *color = enabled ? ruleno ? "3" : "1" : "5";
+
+ /* First, build the edge's head. The name of reduction nodes is "nRm",
+ with n the source state and m the rule number. This is because we
+ don't want all the reductions bearing a same rule number to point to
+ the same state, since that is not the desired format. */
+ fprintf (fout, " %1$d -> \"%1$dR%2$d%3$s\" [",
+ source, ruleno, ed);
+
+ if (! obstack_empty_p (out))
+ /* (The lookahead tokens have been added to the beginning of the
+ obstack, in the caller function.) */
+ fprintf (fout, "label = \"[%s]\" ", obstack_finish0 (out));
+
+ /* Then, the edge's tail. */
+ fprintf (fout, "style = solid]\n");
+
+ /* Build the associated diamond representation of the target rule. */
+ fprintf (fout, " \"%dR%d%s\" [style = filled, "
+ "shape = diamond, fillcolor = %s, ",
+ source, ruleno, ed, color);
+
+ if (ruleno)
+ fprintf (fout, "label = \"R%d\"]\n", ruleno);
+ else
+ fprintf (fout, "label = \"Acc\"]\n");
+
+ }
+}
+
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, ", ");
obstack_sgrow (out, q);
return false;
}
@@ -110,58 +154,56 @@ output_red (state const *s, reductions const *reds, FILE *fout)
bitset no_reduce_set;
int j;
int source = s->number;
- struct obstack oout;
+
+ /* Two obstacks are needed: one for the enabled reductions, and one
+ for the disabled reductions, because in the end we want two
+ separate edges, even though in most cases only one will actually
+ be printed. */
+ struct obstack dout;
+ struct obstack eout;
no_reduce_bitset_init (s, &no_reduce_set);
- obstack_init (&oout);
+ obstack_init (&dout);
+ obstack_init (&eout);
for (j = 0; j < reds->num; ++j)
{
- bool disabled = false;
- bool first = true;
- int ruleno = reds->rules[j]->user_number;
+ bool defaulted = false;
+ bool firstd = true;
+ bool firste = true;
+ rule_number 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);
+ /* Build the lookahead tokens lists, one for enabled transitions and one
+ for disabled transistions. */
if (default_reduction && default_reduction == reds->rules[j])
- first = print_token (&oout, true, "$default");
- else
+ defaulted = true;
+ if (reds->lookahead_tokens)
{
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;
+ firstd = print_token (&dout, firstd, symbols[i]->tag);
+ else
+ {
+ if (! defaulted)
+ firste = print_token (&eout, firste, symbols[i]->tag);
+ bitset_set (no_reduce_set, i);
+ }
}
}
- 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));
+
+ /* Do the actual output. */
+ conclude_red (&eout, source, ruleno, true, firste && !defaulted, fout);
+ conclude_red (&dout, source, ruleno, false, firstd, fout);
}
- obstack_free (&oout, 0);
+ obstack_free (&eout, 0);
+ obstack_free (&dout, 0);
}
void
diff --git a/src/location.h b/src/location.h
index 17da73ca..369125b7 100644
--- a/src/location.h
+++ b/src/location.h
@@ -88,7 +88,7 @@ typedef struct
} location;
-#define YYLTYPE location
+#define GRAM_LTYPE location
#define EMPTY_LOCATION_INIT {{NULL, 0, 0}, {NULL, 0, 0}}
extern location const empty_location;
diff --git a/src/parse-gram.y b/src/parse-gram.y
index 1624dde5..6e58835a 100644
--- a/src/parse-gram.y
+++ b/src/parse-gram.y
@@ -87,15 +87,15 @@ static char const *char_name (char);
#define YYTYPE_UINT8 uint_fast8_t
}
-%verbose
-%defines
-%define locations
+%define api.prefix "gram_"
%define api.pure
+%define locations
%define parse.error verbose
%define parse.lac full
%define parse.trace
-%name-prefix "gram_"
+%defines
%expect 0
+%verbose
%initial-action
{
diff --git a/src/print_graph.c b/src/print_graph.c
index ca1dc24e..5aa3cc62 100644
--- a/src/print_graph.c
+++ b/src/print_graph.c
@@ -40,11 +40,32 @@
| Construct the node labels. |
`----------------------------*/
+/* Print the lhs of a rule in such a manner that there is no vertical
+ repetition, like in *.output files. */
+
+static void
+print_lhs (struct obstack *oout, rule *previous_rule, rule *r)
+{
+ if (previous_rule && STREQ (previous_rule->lhs->tag, r->lhs->tag))
+ {
+ int i;
+ for (i = 0; i < strlen (r->lhs->tag); ++i)
+ obstack_1grow (oout, ' ');
+ obstack_1grow (oout, '|');
+ }
+ else
+ {
+ obstack_sgrow (oout, escape (r->lhs->tag));
+ obstack_1grow (oout, ':');
+ }
+}
+
static void
print_core (struct obstack *oout, state *s)
{
- size_t i;
item_number *sitems = s->items;
+ rule *previous_rule = NULL;
+ size_t i;
size_t snritems = s->nitems;
/* Output all the items of a state, not only its kernel. */
@@ -55,7 +76,8 @@ print_core (struct obstack *oout, state *s)
snritems = nitemset;
}
- obstack_printf (oout, "state %d\\n", s->number);
+ obstack_printf (oout, _("State %d"), s->number);
+ obstack_sgrow (oout, "\\n");
for (i = 0; i < snritems; i++)
{
item_number *sp;
@@ -69,12 +91,14 @@ print_core (struct obstack *oout, state *s)
r = item_number_as_rule_number (*sp);
- obstack_printf (oout, "%d: %s -> ", r, escape (rules[r].lhs->tag));
+ obstack_printf (oout, "%3d ", r);
+ print_lhs (oout, previous_rule, &rules[r]);
+ previous_rule = &rules[r];
for (sp = rules[r].rhs; sp < sp1; sp++)
obstack_printf (oout, "%s ", escape (symbols[*sp]->tag));
- obstack_1grow (oout, '.');
+ obstack_sgrow (oout, " .");
for (/* Nothing */; *sp >= 0; ++sp)
obstack_printf (oout, " %s", escape (symbols[*sp]->tag));
@@ -93,7 +117,7 @@ print_core (struct obstack *oout, state *s)
bitset_iterator biter;
int k;
char const *sep = "";
- obstack_1grow (oout, '[');
+ obstack_sgrow (oout, " [");
BITSET_FOR_EACH (biter, reds->lookahead_tokens[redno], k, 0)
{
obstack_sgrow (oout, sep);
@@ -116,9 +140,8 @@ print_core (struct obstack *oout, state *s)
static void
print_actions (state const *s, FILE *fgraph)
{
- int i;
-
transitions const *trans = s->transitions;
+ int i;
/* Display reductions. */
output_red (s, s->reductions, fgraph);
diff --git a/src/reader.h b/src/reader.h
index 2a78f30a..badd372d 100644
--- a/src/reader.h
+++ b/src/reader.h
@@ -51,9 +51,9 @@ void grammar_current_rule_prec_set (symbol *precsym, location loc);
void grammar_current_rule_dprec_set (int dprec, location loc);
void grammar_current_rule_merge_set (uniqstr name, location loc);
void grammar_current_rule_symbol_append (symbol *sym, location loc,
- named_ref *named_ref);
+ named_ref *nref);
void grammar_current_rule_action_append (const char *action, location loc,
- named_ref *named_ref, bool);
+ named_ref *nref, bool);
void reader (void);
void free_merger_functions (void);
diff --git a/src/scan-gram.h b/src/scan-gram.h
index ed973c78..72138a27 100644
--- a/src/scan-gram.h
+++ b/src/scan-gram.h
@@ -32,7 +32,7 @@ void gram_scanner_last_string_free (void);
extern FILE *gram_out;
extern int gram_lineno;
-# define GRAM_LEX_DECL int gram_lex (YYSTYPE *val, location *loc)
+# define GRAM_LEX_DECL int gram_lex (GRAM_STYPE *val, location *loc)
GRAM_LEX_DECL;
#endif /* !SCAN_GRAM_H_ */
diff --git a/tests/local.at b/tests/local.at
index ac266daa..bddcb00e 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -465,10 +465,14 @@ m4_define([AT_BISON_CHECK_WARNINGS],
[m4_null_if([$2], [AT_BISON_CHECK_WARNINGS_($@)])])])
m4_define([AT_BISON_CHECK_WARNINGS_],
-[[# Defining POSIXLY_CORRECT causes bison to complain if options
- # are added after the grammar file name, so skip these checks
- # in that case.
- if test -z "${POSIXLY_CORRECT+set}"; then
+[[# Defining POSIXLY_CORRECT causes bison to complain if options are
+# added after the grammar file name, so skip these checks in that
+# case.
+#
+# Don't just check if $POSIXLY_CORRECT is set, as Bash, when launched
+# as /bin/sh, sets the shell variable POSIXLY_CORRECT to y, but not
+# the environment variable.
+if env | grep '^POSIXLY_CORRECT=' >/dev/null; then :; else
]AT_SAVE_SPECIAL_FILES[
# To avoid expanding it repeatedly, store specified stdout.
diff --git a/tests/output.at b/tests/output.at
index d3e3e6e8..81710245 100644
--- a/tests/output.at
+++ b/tests/output.at
@@ -251,3 +251,368 @@ AT_CHECK_OUTPUT_FILE_NAME([[@{]])
AT_CHECK_OUTPUT_FILE_NAME([[@}]])
AT_CHECK_OUTPUT_FILE_NAME([[@<:@]])
AT_CHECK_OUTPUT_FILE_NAME([[@:>@]])
+
+
+# AT_TEST(SETUP-NAME, GRAMMAR, DOT-BODY)
+# --------------------------------------
+# Check that the DOT graph for GRAMMAR is DOT-BODY.
+m4_pushdef([AT_TEST],
+[AT_SETUP([$1])
+AT_KEYWORDS([[graph]])
+AT_DATA([[input.y]], [$2])
+AT_BISON_CHECK([[-rall --graph input.y]], [0], [[]], [[ignore]])
+AT_CHECK([[grep -v // input.dot]], [0],
+[[
+digraph "input.y"
+{
+ node [fontname = courier, shape = box, colorscheme = paired6]
+ edge [fontname = courier]
+ ]$3[}
+]])
+AT_CLEANUP
+])
+
+
+## ------------------------ ##
+## Graph with no conflicts. ##
+## ------------------------ ##
+
+AT_TEST([Graph with no conflicts],
+[[%%
+exp: a '?' b;
+a: ;
+b: 'b';
+]],
+[[
+ 0 [label="State 0\n 0 $accept: . exp $end\l 1 exp: . a '?' b\l 2 a: .\l"]
+ 0 -> "0R2e" [style = solid]
+ "0R2e" [style = filled, shape = diamond, fillcolor = 3, label = "R2"]
+ 0 -> 1 [style=dashed label="exp"]
+ 0 -> 2 [style=dashed label="a"]
+ 1 [label="State 1\n 0 $accept: exp . $end\l"]
+ 1 -> 3 [style=solid label="$end"]
+ 2 [label="State 2\n 1 exp: a . '?' b\l"]
+ 2 -> 4 [style=solid label="'?'"]
+ 3 [label="State 3\n 0 $accept: exp $end .\l"]
+ 3 -> "3R0e" [style = solid]
+ "3R0e" [style = filled, shape = diamond, fillcolor = 1, label = "Acc"]
+ 4 [label="State 4\n 1 exp: a '?' . b\l 3 b: . 'b'\l"]
+ 4 -> 5 [style=solid label="'b'"]
+ 4 -> 6 [style=dashed label="b"]
+ 5 [label="State 5\n 3 b: 'b' .\l"]
+ 5 -> "5R3e" [style = solid]
+ "5R3e" [style = filled, shape = diamond, fillcolor = 3, label = "R3"]
+ 6 [label="State 6\n 1 exp: a '?' b .\l"]
+ 6 -> "6R1e" [style = solid]
+ "6R1e" [style = filled, shape = diamond, fillcolor = 3, label = "R1"]
+]])
+
+## ------------------------ ##
+## Graph with unsolved S/R. ##
+## ------------------------ ##
+
+AT_TEST([Graph with unsolved S/R],
+[[%%
+start:
+ 'a'
+ | empty_a 'a'
+ | 'b'
+ | empty_b 'b'
+ | 'c'
+ | empty_c 'c'
+ ;
+empty_a: %prec 'a';
+empty_b: %prec 'b';
+empty_c: %prec 'c';
+]],
+[[
+ 0 [label="State 0\n 0 $accept: . start $end\l 1 start: . 'a'\l 2 | . empty_a 'a'\l 3 | . 'b'\l 4 | . empty_b 'b'\l 5 | . 'c'\l 6 | . empty_c 'c'\l 7 empty_a: . ['a']\l 8 empty_b: . ['b']\l 9 empty_c: . ['c']\l"]
+ 0 -> "0R7d" [label = "['a']" style = solid]
+ "0R7d" [style = filled, shape = diamond, fillcolor = 5, label = "R7"]
+ 0 -> "0R8d" [label = "['b']" style = solid]
+ "0R8d" [style = filled, shape = diamond, fillcolor = 5, label = "R8"]
+ 0 -> "0R9d" [label = "['c']" style = solid]
+ "0R9d" [style = filled, shape = diamond, fillcolor = 5, label = "R9"]
+ 0 -> 1 [style=solid label="'a'"]
+ 0 -> 2 [style=solid label="'b'"]
+ 0 -> 3 [style=solid label="'c'"]
+ 0 -> 4 [style=dashed label="start"]
+ 0 -> 5 [style=dashed label="empty_a"]
+ 0 -> 6 [style=dashed label="empty_b"]
+ 0 -> 7 [style=dashed label="empty_c"]
+ 1 [label="State 1\n 1 start: 'a' .\l"]
+ 1 -> "1R1e" [style = solid]
+ "1R1e" [style = filled, shape = diamond, fillcolor = 3, label = "R1"]
+ 2 [label="State 2\n 3 start: 'b' .\l"]
+ 2 -> "2R3e" [style = solid]
+ "2R3e" [style = filled, shape = diamond, fillcolor = 3, label = "R3"]
+ 3 [label="State 3\n 5 start: 'c' .\l"]
+ 3 -> "3R5e" [style = solid]
+ "3R5e" [style = filled, shape = diamond, fillcolor = 3, label = "R5"]
+ 4 [label="State 4\n 0 $accept: start . $end\l"]
+ 4 -> 8 [style=solid label="$end"]
+ 5 [label="State 5\n 2 start: empty_a . 'a'\l"]
+ 5 -> 9 [style=solid label="'a'"]
+ 6 [label="State 6\n 4 start: empty_b . 'b'\l"]
+ 6 -> 10 [style=solid label="'b'"]
+ 7 [label="State 7\n 6 start: empty_c . 'c'\l"]
+ 7 -> 11 [style=solid label="'c'"]
+ 8 [label="State 8\n 0 $accept: start $end .\l"]
+ 8 -> "8R0e" [style = solid]
+ "8R0e" [style = filled, shape = diamond, fillcolor = 1, label = "Acc"]
+ 9 [label="State 9\n 2 start: empty_a 'a' .\l"]
+ 9 -> "9R2e" [style = solid]
+ "9R2e" [style = filled, shape = diamond, fillcolor = 3, label = "R2"]
+ 10 [label="State 10\n 4 start: empty_b 'b' .\l"]
+ 10 -> "10R4e" [style = solid]
+ "10R4e" [style = filled, shape = diamond, fillcolor = 3, label = "R4"]
+ 11 [label="State 11\n 6 start: empty_c 'c' .\l"]
+ 11 -> "11R6e" [style = solid]
+ "11R6e" [style = filled, shape = diamond, fillcolor = 3, label = "R6"]
+]])
+
+## ---------------------- ##
+## Graph with solved S/R. ##
+## ---------------------- ##
+
+AT_TEST([Graph with solved S/R],
+[[%left 'a'
+%right 'b'
+%right 'c'
+%%
+start:
+ 'a'
+ | empty_a 'a'
+ | 'b'
+ | empty_b 'b'
+ | 'c'
+ | empty_c 'c'
+ ;
+empty_a: %prec 'a';
+empty_b: %prec 'b';
+empty_c: %prec 'c';
+]],
+[[
+ 0 [label="State 0\n 0 $accept: . start $end\l 1 start: . 'a'\l 2 | . empty_a 'a'\l 3 | . 'b'\l 4 | . empty_b 'b'\l 5 | . 'c'\l 6 | . empty_c 'c'\l 7 empty_a: . ['a']\l 8 empty_b: . []\l 9 empty_c: . []\l"]
+ 0 -> "0R7e" [style = solid]
+ "0R7e" [style = filled, shape = diamond, fillcolor = 3, label = "R7"]
+ 0 -> 1 [style=solid label="'b'"]
+ 0 -> 2 [style=solid label="'c'"]
+ 0 -> 3 [style=dashed label="start"]
+ 0 -> 4 [style=dashed label="empty_a"]
+ 0 -> 5 [style=dashed label="empty_b"]
+ 0 -> 6 [style=dashed label="empty_c"]
+ 1 [label="State 1\n 3 start: 'b' .\l"]
+ 1 -> "1R3e" [style = solid]
+ "1R3e" [style = filled, shape = diamond, fillcolor = 3, label = "R3"]
+ 2 [label="State 2\n 5 start: 'c' .\l"]
+ 2 -> "2R5e" [style = solid]
+ "2R5e" [style = filled, shape = diamond, fillcolor = 3, label = "R5"]
+ 3 [label="State 3\n 0 $accept: start . $end\l"]
+ 3 -> 7 [style=solid label="$end"]
+ 4 [label="State 4\n 2 start: empty_a . 'a'\l"]
+ 4 -> 8 [style=solid label="'a'"]
+ 5 [label="State 5\n 4 start: empty_b . 'b'\l"]
+ 5 -> 9 [style=solid label="'b'"]
+ 6 [label="State 6\n 6 start: empty_c . 'c'\l"]
+ 6 -> 10 [style=solid label="'c'"]
+ 7 [label="State 7\n 0 $accept: start $end .\l"]
+ 7 -> "7R0e" [style = solid]
+ "7R0e" [style = filled, shape = diamond, fillcolor = 1, label = "Acc"]
+ 8 [label="State 8\n 2 start: empty_a 'a' .\l"]
+ 8 -> "8R2e" [style = solid]
+ "8R2e" [style = filled, shape = diamond, fillcolor = 3, label = "R2"]
+ 9 [label="State 9\n 4 start: empty_b 'b' .\l"]
+ 9 -> "9R4e" [style = solid]
+ "9R4e" [style = filled, shape = diamond, fillcolor = 3, label = "R4"]
+ 10 [label="State 10\n 6 start: empty_c 'c' .\l"]
+ 10 -> "10R6e" [style = solid]
+ "10R6e" [style = filled, shape = diamond, fillcolor = 3, label = "R6"]
+]])
+
+## ---------------- ##
+## Graph with R/R. ##
+## ---------------- ##
+
+AT_TEST([Graph with R/R],
+[[%%
+exp: a | b;
+a: ;
+b: ;
+]],
+[[
+ 0 [label="State 0\n 0 $accept: . exp $end\l 1 exp: . a\l 2 | . b\l 3 a: . [$end]\l 4 b: . [$end]\l"]
+ 0 -> "0R3e" [style = solid]
+ "0R3e" [style = filled, shape = diamond, fillcolor = 3, label = "R3"]
+ 0 -> "0R4d" [label = "[$end]" style = solid]
+ "0R4d" [style = filled, shape = diamond, fillcolor = 5, label = "R4"]
+ 0 -> 1 [style=dashed label="exp"]
+ 0 -> 2 [style=dashed label="a"]
+ 0 -> 3 [style=dashed label="b"]
+ 1 [label="State 1\n 0 $accept: exp . $end\l"]
+ 1 -> 4 [style=solid label="$end"]
+ 2 [label="State 2\n 1 exp: a .\l"]
+ 2 -> "2R1e" [style = solid]
+ "2R1e" [style = filled, shape = diamond, fillcolor = 3, label = "R1"]
+ 3 [label="State 3\n 2 exp: b .\l"]
+ 3 -> "3R2e" [style = solid]
+ "3R2e" [style = filled, shape = diamond, fillcolor = 3, label = "R2"]
+ 4 [label="State 4\n 0 $accept: exp $end .\l"]
+ 4 -> "4R0e" [style = solid]
+ "4R0e" [style = filled, shape = diamond, fillcolor = 1, label = "Acc"]
+]])
+
+## ---------------------------------------- ##
+## Graph with reductions with multiple LAT. ##
+## ---------------------------------------- ##
+
+AT_TEST([Graph with reductions with multiple LAT],
+[[%%
+exp: a ';' | a ';' | a '.' | b '?' | b '!' | c '?' | c ';';
+a: ;
+b: ;
+c: ;
+]],
+[[
+ 0 [label="State 0\n 0 $accept: . exp $end\l 1 exp: . a ';'\l 2 | . a ';'\l 3 | . a '.'\l 4 | . b '?'\l 5 | . b '!'\l 6 | . c '?'\l 7 | . c ';'\l 8 a: . [';', '.']\l 9 b: . ['?', '!']\l 10 c: . [';', '?']\l"]
+ 0 -> "0R8e" [style = solid]
+ "0R8e" [style = filled, shape = diamond, fillcolor = 3, label = "R8"]
+ 0 -> "0R9e" [label = "['?', '!']" style = solid]
+ "0R9e" [style = filled, shape = diamond, fillcolor = 3, label = "R9"]
+ 0 -> "0R10d" [label = "[';', '?']" style = solid]
+ "0R10d" [style = filled, shape = diamond, fillcolor = 5, label = "R10"]
+ 0 -> 1 [style=dashed label="exp"]
+ 0 -> 2 [style=dashed label="a"]
+ 0 -> 3 [style=dashed label="b"]
+ 0 -> 4 [style=dashed label="c"]
+ 1 [label="State 1\n 0 $accept: exp . $end\l"]
+ 1 -> 5 [style=solid label="$end"]
+ 2 [label="State 2\n 1 exp: a . ';'\l 2 | a . ';'\l 3 | a . '.'\l"]
+ 2 -> 6 [style=solid label="';'"]
+ 2 -> 7 [style=solid label="'.'"]
+ 3 [label="State 3\n 4 exp: b . '?'\l 5 | b . '!'\l"]
+ 3 -> 8 [style=solid label="'?'"]
+ 3 -> 9 [style=solid label="'!'"]
+ 4 [label="State 4\n 6 exp: c . '?'\l 7 | c . ';'\l"]
+ 4 -> 10 [style=solid label="';'"]
+ 4 -> 11 [style=solid label="'?'"]
+ 5 [label="State 5\n 0 $accept: exp $end .\l"]
+ 5 -> "5R0e" [style = solid]
+ "5R0e" [style = filled, shape = diamond, fillcolor = 1, label = "Acc"]
+ 6 [label="State 6\n 1 exp: a ';' . [$end]\l 2 | a ';' . [$end]\l"]
+ 6 -> "6R1e" [style = solid]
+ "6R1e" [style = filled, shape = diamond, fillcolor = 3, label = "R1"]
+ 6 -> "6R2d" [label = "[$end]" style = solid]
+ "6R2d" [style = filled, shape = diamond, fillcolor = 5, label = "R2"]
+ 7 [label="State 7\n 3 exp: a '.' .\l"]
+ 7 -> "7R3e" [style = solid]
+ "7R3e" [style = filled, shape = diamond, fillcolor = 3, label = "R3"]
+ 8 [label="State 8\n 4 exp: b '?' .\l"]
+ 8 -> "8R4e" [style = solid]
+ "8R4e" [style = filled, shape = diamond, fillcolor = 3, label = "R4"]
+ 9 [label="State 9\n 5 exp: b '!' .\l"]
+ 9 -> "9R5e" [style = solid]
+ "9R5e" [style = filled, shape = diamond, fillcolor = 3, label = "R5"]
+ 10 [label="State 10\n 7 exp: c ';' .\l"]
+ 10 -> "10R7e" [style = solid]
+ "10R7e" [style = filled, shape = diamond, fillcolor = 3, label = "R7"]
+ 11 [label="State 11\n 6 exp: c '?' .\l"]
+ 11 -> "11R6e" [style = solid]
+ "11R6e" [style = filled, shape = diamond, fillcolor = 3, label = "R6"]
+]])
+
+## ------------------------------------------------------ ##
+## Graph with a reduction rule both enabled and disabled. ##
+## ------------------------------------------------------ ##
+
+AT_TEST([Graph with a reduction rule both enabled and disabled],
+[[%%
+exp: ifexp | opexp | imm;
+ifexp: "if" exp "then" exp elseexp;
+elseexp: "else" exp | ;
+opexp: exp '+' exp;
+imm: '0';
+]],
+[[
+ 0 [label="State 0\n 0 $accept: . exp $end\l 1 exp: . ifexp\l 2 | . opexp\l 3 | . imm\l 4 ifexp: . \"if\" exp \"then\" exp elseexp\l 7 opexp: . exp '+' exp\l 8 imm: . '0'\l"]
+ 0 -> 1 [style=solid label="\"if\""]
+ 0 -> 2 [style=solid label="'0'"]
+ 0 -> 3 [style=dashed label="exp"]
+ 0 -> 4 [style=dashed label="ifexp"]
+ 0 -> 5 [style=dashed label="opexp"]
+ 0 -> 6 [style=dashed label="imm"]
+ 1 [label="State 1\n 1 exp: . ifexp\l 2 | . opexp\l 3 | . imm\l 4 ifexp: . \"if\" exp \"then\" exp elseexp\l 4 | \"if\" . exp \"then\" exp elseexp\l 7 opexp: . exp '+' exp\l 8 imm: . '0'\l"]
+ 1 -> 1 [style=solid label="\"if\""]
+ 1 -> 2 [style=solid label="'0'"]
+ 1 -> 7 [style=dashed label="exp"]
+ 1 -> 4 [style=dashed label="ifexp"]
+ 1 -> 5 [style=dashed label="opexp"]
+ 1 -> 6 [style=dashed label="imm"]
+ 2 [label="State 2\n 8 imm: '0' .\l"]
+ 2 -> "2R8e" [style = solid]
+ "2R8e" [style = filled, shape = diamond, fillcolor = 3, label = "R8"]
+ 3 [label="State 3\n 0 $accept: exp . $end\l 7 opexp: exp . '+' exp\l"]
+ 3 -> 8 [style=solid label="$end"]
+ 3 -> 9 [style=solid label="'+'"]
+ 4 [label="State 4\n 1 exp: ifexp .\l"]
+ 4 -> "4R1e" [style = solid]
+ "4R1e" [style = filled, shape = diamond, fillcolor = 3, label = "R1"]
+ 5 [label="State 5\n 2 exp: opexp .\l"]
+ 5 -> "5R2e" [style = solid]
+ "5R2e" [style = filled, shape = diamond, fillcolor = 3, label = "R2"]
+ 6 [label="State 6\n 3 exp: imm .\l"]
+ 6 -> "6R3e" [style = solid]
+ "6R3e" [style = filled, shape = diamond, fillcolor = 3, label = "R3"]
+ 7 [label="State 7\n 4 ifexp: \"if\" exp . \"then\" exp elseexp\l 7 opexp: exp . '+' exp\l"]
+ 7 -> 10 [style=solid label="\"then\""]
+ 7 -> 9 [style=solid label="'+'"]
+ 8 [label="State 8\n 0 $accept: exp $end .\l"]
+ 8 -> "8R0e" [style = solid]
+ "8R0e" [style = filled, shape = diamond, fillcolor = 1, label = "Acc"]
+ 9 [label="State 9\n 1 exp: . ifexp\l 2 | . opexp\l 3 | . imm\l 4 ifexp: . \"if\" exp \"then\" exp elseexp\l 7 opexp: . exp '+' exp\l 7 | exp '+' . exp\l 8 imm: . '0'\l"]
+ 9 -> 1 [style=solid label="\"if\""]
+ 9 -> 2 [style=solid label="'0'"]
+ 9 -> 11 [style=dashed label="exp"]
+ 9 -> 4 [style=dashed label="ifexp"]
+ 9 -> 5 [style=dashed label="opexp"]
+ 9 -> 6 [style=dashed label="imm"]
+ 10 [label="State 10\n 1 exp: . ifexp\l 2 | . opexp\l 3 | . imm\l 4 ifexp: . \"if\" exp \"then\" exp elseexp\l 4 | \"if\" exp \"then\" . exp elseexp\l 7 opexp: . exp '+' exp\l 8 imm: . '0'\l"]
+ 10 -> 1 [style=solid label="\"if\""]
+ 10 -> 2 [style=solid label="'0'"]
+ 10 -> 12 [style=dashed label="exp"]
+ 10 -> 4 [style=dashed label="ifexp"]
+ 10 -> 5 [style=dashed label="opexp"]
+ 10 -> 6 [style=dashed label="imm"]
+ 11 [label="State 11\n 7 opexp: exp . '+' exp\l 7 | exp '+' exp . [$end, \"then\", \"else\", '+']\l"]
+ 11 -> "11R7e" [style = solid]
+ "11R7e" [style = filled, shape = diamond, fillcolor = 3, label = "R7"]
+ 11 -> "11R7d" [label = "['+']" style = solid]
+ "11R7d" [style = filled, shape = diamond, fillcolor = 5, label = "R7"]
+ 11 -> 9 [style=solid label="'+'"]
+ 12 [label="State 12\n 4 ifexp: \"if\" exp \"then\" exp . elseexp\l 5 elseexp: . \"else\" exp\l 6 | . [$end, \"then\", \"else\", '+']\l 7 opexp: exp . '+' exp\l"]
+ 12 -> "12R6e" [style = solid]
+ "12R6e" [style = filled, shape = diamond, fillcolor = 3, label = "R6"]
+ 12 -> "12R6d" [label = "[\"else\", '+']" style = solid]
+ "12R6d" [style = filled, shape = diamond, fillcolor = 5, label = "R6"]
+ 12 -> 13 [style=solid label="\"else\""]
+ 12 -> 9 [style=solid label="'+'"]
+ 12 -> 14 [style=dashed label="elseexp"]
+ 13 [label="State 13\n 1 exp: . ifexp\l 2 | . opexp\l 3 | . imm\l 4 ifexp: . \"if\" exp \"then\" exp elseexp\l 5 elseexp: \"else\" . exp\l 7 opexp: . exp '+' exp\l 8 imm: . '0'\l"]
+ 13 -> 1 [style=solid label="\"if\""]
+ 13 -> 2 [style=solid label="'0'"]
+ 13 -> 15 [style=dashed label="exp"]
+ 13 -> 4 [style=dashed label="ifexp"]
+ 13 -> 5 [style=dashed label="opexp"]
+ 13 -> 6 [style=dashed label="imm"]
+ 14 [label="State 14\n 4 ifexp: \"if\" exp \"then\" exp elseexp .\l"]
+ 14 -> "14R4e" [style = solid]
+ "14R4e" [style = filled, shape = diamond, fillcolor = 3, label = "R4"]
+ 15 [label="State 15\n 5 elseexp: \"else\" exp . [$end, \"then\", \"else\", '+']\l 7 opexp: exp . '+' exp\l"]
+ 15 -> "15R5e" [style = solid]
+ "15R5e" [style = filled, shape = diamond, fillcolor = 3, label = "R5"]
+ 15 -> "15R5d" [label = "['+']" style = solid]
+ "15R5d" [style = filled, shape = diamond, fillcolor = 5, label = "R5"]
+ 15 -> 9 [style=solid label="'+'"]
+]])
+
+m4_popdef([AT_TEST])
diff --git a/tests/torture.at b/tests/torture.at
index a5e244b6..5aa18900 100644
--- a/tests/torture.at
+++ b/tests/torture.at
@@ -431,7 +431,7 @@ int
main (int argc, const char **argv)
{
YYSTYPE yylval_init = get_args (argc, argv);
- int status;
+ int status = 0;
int count;
]m4_bmatch([$2], [api.push-pull both],
[[ yypstate *ps = yypstate_new ();