Compare commits

..
17 Commits
Author SHA1 Message Date
Akim Demaille a3efd13e44 version 3.0.2
* NEWS: Record release date.
2013-12-05 14:58:22 +01:00
Akim Demaille a4122000c6 gnulib: update
* gnulib: here.
2013-12-05 14:42:08 +01:00
Akim Demaille 461983270c output: do not generate source files when late errors are caught
Reported by Alexandre Duret-Lutz as "second problem" in:
http://lists.gnu.org/archive/html/bug-bison/2013-09/msg00015.html

* bootstrap.conf: We need the "unlink" module.
* src/files.h, src/files.c (unlink_generated_sources): New.
* src/output.c: Use it.
* tests/output.at: Check the case of late errors.
2013-12-04 15:53:01 +01:00
Akim Demaille ea99d6e6a0 output: record what generated files are source or report files
* src/files.h, src/files.c (output_file_name_check): Take an additional
argument to record whether a file is a source or report file.
* src/files.c (generated_file): New.
(file_names, file_names_count): Replace with...
(generated_files, generated_files_size): these.
* src/scan-skel.l: Adjust.
2013-12-04 15:53:01 +01:00
Akim Demaille 184b42c85b output: do not generate source files when early errors are caught
Reported by Alexandre Duret-Lutz as "second problem" in:
http://lists.gnu.org/archive/html/bug-bison/2013-09/msg00015.html

One problem is that some errors are caught early, before the
generation of output files, while others can only be detected
afterwards (since, for instance, skeletons can raise errors
themselves).

This will be addressed in two steps: early errors do not generate
source files at all, while later errors will remove the files that
have already been generated.

* src/scan-skel.l (yyout): Open to /dev/null when there are errors.
* tests/output.at (AT_CHECK_FILES): Factored out of...
(AT_CHECK_OUTPUT): this.
Fuse the "SHELLIO" argument in the "FLAGS" one.
Use $5 to denote the expected exit status.
Add a test case for early errors.
2013-12-04 15:53:01 +01:00
Akim Demaille be29c71dd8 xml: also use "%empty" with html output
* data/xslt/xml2xhtml.xsl: No longer issue an Epsilon, display as in
dot and text formats.
2013-11-26 16:28:22 +01:00
Akim Demaille d439985436 style: formatting changes
* src/print-xml.c: here.
2013-11-26 16:20:55 +01:00
Akim Demaille f3d2a1b2ac xml: also display %empty for empty right-hand sides
* data/xslt/xml2dot.xsl, data/xslt/xml2text.xsl: Display %empty where needed.
2013-11-26 16:20:52 +01:00
Akim Demaille 21cf80399f reports: display %empty in the generated pointed-rules
* src/print.c (print_core): Use %empty for empty rules.
* src/print_graph.c (print_core): Ditto.
* tests/conflicts.at, tests/output.at, tests/reduce.at: Adjust
expectations.
2013-11-26 15:31:52 +01:00
Akim Demaille 7b0ca050f7 news: YYERROR vs variants 2013-11-26 15:31:51 +01:00
Akim Demaille a339aef48a style: scope reduction in lalr.cc
* src/lalr.c: Shorten variable scopes.
(lookahead_tokens_print): Use the same variable name in two loops
iterating over the same structure.
2013-11-18 10:29:23 +01:00
Akim Demaille 44186fc4ec lalr1.cc: formatting changes
* data/lalr1.cc: Fix indentation.
2013-11-15 10:14:06 +01:00
Akim Demaille 5c77412162 lalr1.cc: fix the support of YYERROR with variants
When variant are enabled, the yylhs variable (the left-hand side of
the rule being reduced, i.e. $$ and @$) is explicitly destroyed when
YYERROR is called.  This is because before running the user code, $$
is initialized, so that the user can properly use it.

However, when quitting yyparse, yylhs is also reclaimed by the C++
compiler: the variable goes out of scope.

Instead of trying to be too smart, let the compiler do its job: reduce
the scope of yylhs to exactly the reduction.  This way, whatever the
type of scope exit (regular, exception, return, goto...) this variable
will be properly reclaimed.

Reported by Paolo Simone Gasparello.
<http://lists.gnu.org/archive/html/bug-bison/2013-10/msg00003.html>

* data/lalr1.cc (yyparse): Reduce the scope of yylhs.
* tests/c++.at: We now pass this test.
2013-11-15 10:14:05 +01:00
Akim Demaille 5cf6e669af tests: check $$'s destruction with variant, YYERROR, and no error recovery
When variant are enabled, the yylhs variable (the left-hand side of
the rule being reduced, i.e. $$ and @$) is explicitly destroyed when
YYERROR is called.  This is because before running the user code, $$
is initialized, so that the user can properly use it.

However, when quitting yyparse, yylhs is also reclaimed by the C++
compiler: the variable goes out of scope.

This was not detected by the test suite because (i) the Object tracker
was too weak, and (ii) the problem does not show when there is error
recovery.

Reported by Paolo Simone Gasparello.
<http://lists.gnu.org/archive/html/bug-bison/2013-10/msg00003.html>

* tests/c++.at (Exception safety): Improve the objects logger to make
sure that we never destroy twice an object.
Also track copy-constructors.
Use a set instead of a list.
Display the logs before running the function body, this is more
useful in case of failure.
Generalize to track with and without error recovery.
2013-11-15 10:13:47 +01:00
Akim Demaille 16bb9f1647 tests: simplify useless obfuscation
* tests/c++.at: $$ is not special for M4, there is no need to "escape"
it.
2013-11-15 09:38:15 +01:00
Akim Demaille edb2e90531 skeletons: use better names when computing a "goto"
* data/glr.c (yyLRgotoState): Name the symbol argument yysym, instead
of yylhs.
* data/lalr1.cc (yy_lr_goto_state_): Likewise.
* data/lalr1.java (yy_lr_goto_state_): New, modeled after the previous
two routines.
Use it.
2013-11-14 16:26:16 +01:00
Akim Demaille 6d94eebba7 maint: post-release administrivia
* NEWS: Add header line for next release.
* .prev-version: Record previous version.
* cfg.mk (old_NEWS_hash): Auto-update.
2013-11-12 18:37:14 +01:00
25 changed files with 334 additions and 233 deletions
+1 -1
View File
@@ -1 +1 @@
3.0 3.0.1
+24
View File
@@ -1,5 +1,29 @@
GNU Bison NEWS GNU Bison NEWS
* Noteworthy changes in release 3.0.2 (2013-12-05) [stable]
** Bug fixes
*** Generated source files when errors are reported
When warnings are issued and -Werror is set, bison would still generate
the source files (*.c, *.h...). As a consequence, some runs of "make"
could fail the first time, but not the second (as the files were generated
anyway).
This is fixed: bison no longer generates this source files, but, of
course, still produces the various reports (*.output, *.xml, etc.).
*** %empty is used in reports
Empty right-hand sides are denoted by '%empty' in all the reports (text,
dot, XML and formats derived from it).
*** YYERROR and variants
When C++ variant support is enabled, an error triggered via YYERROR, but
not caught via error recovery, resulted in a double deletion.
* Noteworthy changes in release 3.0.1 (2013-11-12) [stable] * Noteworthy changes in release 3.0.1 (2013-11-12) [stable]
** Bug fixes ** Bug fixes
+1
View File
@@ -96,6 +96,7 @@ Odd Arild Olsen [email protected]
Oleg Smolsky [email protected] Oleg Smolsky [email protected]
Oleksii Taran [email protected] Oleksii Taran [email protected]
Paolo Bonzini [email protected] Paolo Bonzini [email protected]
Paolo Simone Gasparello [email protected]
Pascal Bart [email protected] Pascal Bart [email protected]
Paul Eggert [email protected] Paul Eggert [email protected]
Paul Hilfinger [email protected] Paul Hilfinger [email protected]
+2 -1
View File
@@ -34,7 +34,8 @@ gnulib_modules='
readme-release readme-release
realloc-posix realloc-posix
spawn-pipe stdbool stpcpy strdup-posix strerror strtoul strverscmp spawn-pipe stdbool stpcpy strdup-posix strerror strtoul strverscmp
unistd unistd-safer unlocked-io update-copyright unsetenv verify unistd unistd-safer unlink unlocked-io
update-copyright unsetenv verify
warnings warnings
xalloc xalloc
xalloc-die xalloc-die
+7 -3
View File
@@ -910,14 +910,18 @@ yygetLRActions (yyStateNum yystate, int yytoken,
} }
} }
/** Compute post-reduction state.
* \param yystate the current state
* \param yysym the nonterminal to push on the stack
*/
static inline yyStateNum static inline yyStateNum
yyLRgotoState (yyStateNum yystate, yySymbol yylhs) yyLRgotoState (yyStateNum yystate, yySymbol yysym)
{ {
int yyr = yypgoto[yylhs - YYNTOKENS] + yystate; int yyr = yypgoto[yysym - YYNTOKENS] + yystate;
if (0 <= yyr && yyr <= YYLAST && yycheck[yyr] == yystate) if (0 <= yyr && yyr <= YYLAST && yycheck[yyr] == yystate)
return yytable[yyr]; return yytable[yyr];
else else
return yydefgoto[yylhs - YYNTOKENS]; return yydefgoto[yysym - YYNTOKENS];
} }
static inline yybool static inline yybool
+50 -52
View File
@@ -220,8 +220,8 @@ b4_location_define])])[
/// Compute post-reduction state. /// Compute post-reduction state.
/// \param yystate the current state /// \param yystate the current state
/// \param yylhs the nonterminal to push on the stack /// \param yysym the nonterminal to push on the stack
state_type yy_lr_goto_state_ (state_type yystate, int yylhs); state_type yy_lr_goto_state_ (state_type yystate, int yysym);
/// Whether the given \c yypact_ value indicates a defaulted state. /// Whether the given \c yypact_ value indicates a defaulted state.
/// \param yyvalue the value to check /// \param yyvalue the value to check
@@ -671,13 +671,13 @@ m4_if(b4_prefix, [yy], [],
#endif // ]b4_api_PREFIX[DEBUG #endif // ]b4_api_PREFIX[DEBUG
inline ]b4_parser_class_name[::state_type inline ]b4_parser_class_name[::state_type
]b4_parser_class_name[::yy_lr_goto_state_ (state_type yystate, int yylhs) ]b4_parser_class_name[::yy_lr_goto_state_ (state_type yystate, int yysym)
{ {
int yyr = yypgoto_[yylhs - yyntokens_] + yystate; int yyr = yypgoto_[yysym - yyntokens_] + yystate;
if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate) if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate)
return yytable_[yyr]; return yytable_[yyr];
else else
return yydefgoto_[yylhs - yyntokens_]; return yydefgoto_[yysym - yyntokens_];
} }
inline bool inline bool
@@ -700,6 +700,7 @@ m4_if(b4_prefix, [yy], [],
// State. // State.
int yyn; int yyn;
/// Length of the RHS of the rule being reduced.
int yylen = 0; int yylen = 0;
// Error handling. // Error handling.
@@ -712,9 +713,6 @@ m4_if(b4_prefix, [yy], [],
/// The locations where the error started and ended. /// The locations where the error started and ended.
stack_symbol_type yyerror_range[3];]])[ stack_symbol_type yyerror_range[3];]])[
/// $$ and @@$.
stack_symbol_type yylhs;
/// The return value of parse (). /// The return value of parse ().
int yyresult; int yyresult;
@@ -815,52 +813,55 @@ b4_dollar_popdef])[]dnl
`-----------------------------*/ `-----------------------------*/
yyreduce: yyreduce:
yylen = yyr2_[yyn]; yylen = yyr2_[yyn];
yylhs.state = yy_lr_goto_state_(yystack_[yylen].state, yyr1_[yyn]);]b4_variant_if([ {
/* Variants are always initialized to an empty instance of the stack_symbol_type yylhs;
correct type. The default $$=$1 action is NOT applied when using yylhs.state = yy_lr_goto_state_(yystack_[yylen].state, yyr1_[yyn]);]b4_variant_if([
variants. */ /* Variants are always initialized to an empty instance of the
b4_symbol_variant([[yyr1_@{yyn@}]], [yylhs.value], [build])],[ correct type. The default '$$ = $1' action is NOT applied
/* If YYLEN is nonzero, implement the default value of the action: when using variants. */
'$$ = $1'. Otherwise, use the top of the stack. b4_symbol_variant([[yyr1_@{yyn@}]], [yylhs.value], [build])], [
/* If YYLEN is nonzero, implement the default value of the
action: '$$ = $1'. Otherwise, use the top of the stack.
Otherwise, the following line sets YYLHS.VALUE to garbage. Otherwise, the following line sets YYLHS.VALUE to garbage.
This behavior is undocumented and Bison This behavior is undocumented and Bison users should not rely
users should not rely upon it. */ upon it. */
if (yylen) if (yylen)
yylhs.value = yystack_@{yylen - 1@}.value; yylhs.value = yystack_@{yylen - 1@}.value;
else else
yylhs.value = yystack_@{0@}.value;])[ yylhs.value = yystack_@{0@}.value;])[
]b4_locations_if([dnl ]b4_locations_if([dnl
[ [
// Compute the default @@$. // Compute the default @@$.
{
slice<stack_symbol_type, stack_type> slice (yystack_, yylen);
YYLLOC_DEFAULT (yylhs.location, slice, yylen);
}]])[
// Perform the reduction.
YY_REDUCE_PRINT (yyn);
try
{ {
switch (yyn) slice<stack_symbol_type, stack_type> slice (yystack_, yylen);
{ YYLLOC_DEFAULT (yylhs.location, slice, yylen);
}]])[
// Perform the reduction.
YY_REDUCE_PRINT (yyn);
try
{
switch (yyn)
{
]b4_user_actions[ ]b4_user_actions[
default: default:
break; break;
} }
} }
catch (const syntax_error& yyexc) catch (const syntax_error& yyexc)
{ {
error (yyexc); error (yyexc);
YYERROR; YYERROR;
} }
YY_SYMBOL_PRINT ("-> $$ =", yylhs); YY_SYMBOL_PRINT ("-> $$ =", yylhs);
yypop_ (yylen); yypop_ (yylen);
yylen = 0; yylen = 0;
YY_STACK_PRINT (); YY_STACK_PRINT ();
// Shift the result of the reduction. // Shift the result of the reduction.
yypush_ (YY_NULLPTR, yylhs); yypush_ (YY_NULLPTR, yylhs);
}
goto yynewstate; goto yynewstate;
/*--------------------------------------. /*--------------------------------------.
@@ -907,10 +908,7 @@ b4_dollar_popdef])[]dnl
code. */ code. */
if (false) if (false)
goto yyerrorlab;]b4_locations_if([[ goto yyerrorlab;]b4_locations_if([[
yyerror_range[1].location = yystack_[yylen - 1].location;]])b4_variant_if([[ yyerror_range[1].location = yystack_[yylen - 1].location;]])[
/* $$ was initialized before running the user action. */
YY_SYMBOL_PRINT ("Error: discarding", yylhs);
yylhs.~stack_symbol_type();]])[
/* Do not reclaim the symbols of the rule whose action triggered /* Do not reclaim the symbols of the rule whose action triggered
this YYERROR. */ this YYERROR. */
yypop_ (yylen); yypop_ (yylen);
+14 -8
View File
@@ -453,6 +453,19 @@ b4_define_state])[
return yyerrstatus_ == 0; return yyerrstatus_ == 0;
} }
/** Compute post-reduction state.
* @@param yystate the current state
* @@param yysym the nonterminal to push on the stack
*/
private int yy_lr_goto_state_ (int yystate, int yysym)
{
int yyr = yypgoto_[yysym - yyntokens_] + yystate;
if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate)
return yytable_[yyr];
else
return yydefgoto_[yysym - yyntokens_];
}
private int yyaction (int yyn, YYStack yystack, int yylen) ]b4_maybe_throws([b4_throws])[ private int yyaction (int yyn, YYStack yystack, int yylen) ]b4_maybe_throws([b4_throws])[
{ {
]b4_yystype[ yyval; ]b4_yystype[ yyval;
@@ -483,14 +496,7 @@ b4_define_state])[
yylen = 0; yylen = 0;
/* Shift the result of the reduction. */ /* Shift the result of the reduction. */
yyn = yyr1_[yyn]; int yystate = yy_lr_goto_state_ (yystack.stateAt (0), yyr1_[yyn]);
int yystate = yypgoto_[yyn - yyntokens_] + yystack.stateAt (0);
if (0 <= yystate && yystate <= yylast_
&& yycheck_[yystate] == yystack.stateAt (0))
yystate = yytable_[yystate];
else
yystate = yydefgoto_[yyn - yyntokens_];
yystack.push (yystate, yyval]b4_locations_if([, yyloc])[); yystack.push (yystate, yyval]b4_locations_if([, yyloc])[);
return YYNEWSTATE; return YYNEWSTATE;
} }
+5 -1
View File
@@ -201,6 +201,8 @@
<xsl:if test="$point = 0"> <xsl:if test="$point = 0">
<xsl:text> .</xsl:text> <xsl:text> .</xsl:text>
</xsl:if> </xsl:if>
<!-- RHS -->
<xsl:for-each select="rhs/symbol|rhs/empty"> <xsl:for-each select="rhs/symbol|rhs/empty">
<xsl:apply-templates select="."/> <xsl:apply-templates select="."/>
<xsl:if test="$point = position()"> <xsl:if test="$point = position()">
@@ -214,7 +216,9 @@
<xsl:value-of select="."/> <xsl:value-of select="."/>
</xsl:template> </xsl:template>
<xsl:template match="empty"/> <xsl:template match="empty">
<xsl:text> %empty</xsl:text>
</xsl:template>
<xsl:template match="lookaheads"> <xsl:template match="lookaheads">
<xsl:text> [</xsl:text> <xsl:text> [</xsl:text>
+1 -6
View File
@@ -350,12 +350,7 @@
<xsl:if test="position() = $point + 1"> <xsl:if test="position() = $point + 1">
<xsl:text> .</xsl:text> <xsl:text> .</xsl:text>
</xsl:if> </xsl:if>
<xsl:if test="$itemset = 'true' and name(.) != 'empty'"> <xsl:apply-templates select="."/>
<xsl:apply-templates select="."/>
</xsl:if>
<xsl:if test="$itemset != 'true'">
<xsl:apply-templates select="."/>
</xsl:if>
<xsl:if test="position() = last() and position() = $point"> <xsl:if test="position() = last() and position() = $point">
<xsl:text> .</xsl:text> <xsl:text> .</xsl:text>
</xsl:if> </xsl:if>
+2 -7
View File
@@ -532,12 +532,7 @@
<xsl:text> </xsl:text> <xsl:text> </xsl:text>
<span class="point">.</span> <span class="point">.</span>
</xsl:if> </xsl:if>
<xsl:if test="$itemset = 'true' and name(.) != 'empty'"> <xsl:apply-templates select="."/>
<xsl:apply-templates select="."/>
</xsl:if>
<xsl:if test="$itemset != 'true'">
<xsl:apply-templates select="."/>
</xsl:if>
<xsl:if test="position() = last() and position() = $point"> <xsl:if test="position() = last() and position() = $point">
<xsl:text> </xsl:text> <xsl:text> </xsl:text>
<span class="point">.</span> <span class="point">.</span>
@@ -563,7 +558,7 @@
</xsl:template> </xsl:template>
<xsl:template match="empty"> <xsl:template match="empty">
<xsl:text> &#949;</xsl:text> <xsl:text> %empty</xsl:text>
</xsl:template> </xsl:template>
<xsl:template match="lookaheads"> <xsl:template match="lookaheads">
+1 -1
Submodule gnulib updated: d208f3ab64...74540d44dc
+2
View File
@@ -272,3 +272,5 @@
/sig-handler.c /sig-handler.c
/unistd.c /unistd.c
/wctype-h.c /wctype-h.c
/lstat.c
/unlink.c
+3
View File
@@ -180,3 +180,6 @@
/obstack-printf.m4 /obstack-printf.m4
/extern-inline.m4 /extern-inline.m4
/non-recursive-gnulib-prefix-hack.m4 /non-recursive-gnulib-prefix-hack.m4
/absolute-header.m4
/lstat.m4
/unlink.m4
+35 -15
View File
@@ -51,8 +51,17 @@ char *spec_defines_file = NULL; /* for --defines. */
char *parser_file_name; char *parser_file_name;
/* All computed output file names. */ /* All computed output file names. */
static char **file_names = NULL; typedef struct generated_file
static int file_names_count = 0; {
/** File name. */
char *name;
/** Whether is a generated source file (e.g., *.c, *.java...), as
opposed to the report file (e.g., *.output). When late errors
are detected, generated source files are removed. */
bool is_source;
} generated_file;
static generated_file *generated_files = NULL;
static int generated_files_size = 0;
uniqstr grammar_file = NULL; uniqstr grammar_file = NULL;
uniqstr current_file = NULL; uniqstr current_file = NULL;
@@ -332,21 +341,21 @@ compute_output_file_names (void)
{ {
if (! spec_graph_file) if (! spec_graph_file)
spec_graph_file = concat2 (all_but_tab_ext, ".dot"); spec_graph_file = concat2 (all_but_tab_ext, ".dot");
output_file_name_check (&spec_graph_file); output_file_name_check (&spec_graph_file, false);
} }
if (xml_flag) if (xml_flag)
{ {
if (! spec_xml_file) if (! spec_xml_file)
spec_xml_file = concat2 (all_but_tab_ext, ".xml"); spec_xml_file = concat2 (all_but_tab_ext, ".xml");
output_file_name_check (&spec_xml_file); output_file_name_check (&spec_xml_file, false);
} }
if (report_flag) if (report_flag)
{ {
if (!spec_verbose_file) if (!spec_verbose_file)
spec_verbose_file = concat2 (all_but_tab_ext, OUTPUT_EXT); spec_verbose_file = concat2 (all_but_tab_ext, OUTPUT_EXT);
output_file_name_check (&spec_verbose_file); output_file_name_check (&spec_verbose_file, false);
} }
free (all_but_tab_ext); free (all_but_tab_ext);
@@ -355,7 +364,7 @@ compute_output_file_names (void)
} }
void void
output_file_name_check (char **file_name) output_file_name_check (char **file_name, bool source)
{ {
bool conflict = false; bool conflict = false;
if (STREQ (*file_name, grammar_file)) if (STREQ (*file_name, grammar_file))
@@ -367,11 +376,11 @@ output_file_name_check (char **file_name)
else else
{ {
int i; int i;
for (i = 0; i < file_names_count; i++) for (i = 0; i < generated_files_size; i++)
if (STREQ (file_names[i], *file_name)) if (STREQ (generated_files[i].name, *file_name))
{ {
complain (NULL, Wother, _("conflicting outputs to file %s"), complain (NULL, Wother, _("conflicting outputs to file %s"),
quote (*file_name)); quote (generated_files[i].name));
conflict = true; conflict = true;
} }
} }
@@ -382,12 +391,23 @@ output_file_name_check (char **file_name)
} }
else else
{ {
file_names = xnrealloc (file_names, ++file_names_count, generated_files = xnrealloc (generated_files, ++generated_files_size,
sizeof *file_names); sizeof *generated_files);
file_names[file_names_count-1] = xstrdup (*file_name); generated_files[generated_files_size-1].name = xstrdup (*file_name);
generated_files[generated_files_size-1].is_source = source;
} }
} }
void
unlink_generated_sources (void)
{
int i;
for (i = 0; i < generated_files_size; i++)
if (generated_files[i].is_source)
/* Ignore errors. The file might not even exist. */
unlink (generated_files[i].name);
}
void void
output_file_names_free (void) output_file_names_free (void)
{ {
@@ -400,8 +420,8 @@ output_file_names_free (void)
free (dir_prefix); free (dir_prefix);
{ {
int i; int i;
for (i = 0; i < file_names_count; i++) for (i = 0; i < generated_files_size; i++)
free (file_names[i]); free (generated_files[i].name);
} }
free (file_names); free (generated_files);
} }
+9 -1
View File
@@ -63,7 +63,15 @@ extern char *all_but_ext;
void compute_output_file_names (void); void compute_output_file_names (void);
void output_file_names_free (void); void output_file_names_free (void);
void output_file_name_check (char **file_name);
/** Record that we generate file \a file_name.
* \param source whether this is a source file (*c, *.java...)
* as opposed to a report (*.output, *.dot...).
*/
void output_file_name_check (char **file_name, bool source);
/** Remove all the generated source files. */
void unlink_generated_sources (void);
FILE *xfopen (const char *name, char const *mode); FILE *xfopen (const char *name, char const *mode);
void xfclose (FILE *ptr); void xfclose (FILE *ptr);
+19 -23
View File
@@ -67,17 +67,13 @@ static goto_number **includes;
static goto_list **lookback; static goto_list **lookback;
void void
set_goto_map (void) set_goto_map (void)
{ {
state_number s; state_number s;
goto_number *temp_map; goto_number *temp_map = xnmalloc (nvars + 1, sizeof *temp_map);
goto_map = xcalloc (nvars + 1, sizeof *goto_map); goto_map = xcalloc (nvars + 1, sizeof *goto_map);
temp_map = xnmalloc (nvars + 1, sizeof *temp_map);
ngotos = 0; ngotos = 0;
for (s = 0; s < nstates; ++s) for (s = 0; s < nstates; ++s)
{ {
@@ -132,16 +128,13 @@ set_goto_map (void)
goto_number goto_number
map_goto (state_number s0, symbol_number sym) map_goto (state_number s0, symbol_number sym)
{ {
goto_number high; goto_number low = goto_map[sym - ntokens];
goto_number low; goto_number high = goto_map[sym - ntokens + 1] - 1;
goto_number middle;
state_number s;
low = goto_map[sym - ntokens];
high = goto_map[sym - ntokens + 1] - 1;
for (;;) for (;;)
{ {
goto_number middle;
state_number s;
aver (low <= high); aver (low <= high);
middle = (low + high) / 2; middle = (low + high) / 2;
s = from_state[middle]; s = from_state[middle];
@@ -412,7 +405,6 @@ static void
lookahead_tokens_print (FILE *out) lookahead_tokens_print (FILE *out)
{ {
state_number i; state_number i;
int j, k;
fprintf (out, "Lookahead tokens: BEGIN\n"); fprintf (out, "Lookahead tokens: BEGIN\n");
for (i = 0; i < nstates; ++i) for (i = 0; i < nstates; ++i)
{ {
@@ -421,21 +413,25 @@ lookahead_tokens_print (FILE *out)
int n_lookahead_tokens = 0; int n_lookahead_tokens = 0;
if (reds->lookahead_tokens) if (reds->lookahead_tokens)
for (k = 0; k < reds->num; ++k) {
if (reds->lookahead_tokens[k]) int j;
++n_lookahead_tokens; for (j = 0; j < reds->num; ++j)
if (reds->lookahead_tokens[j])
++n_lookahead_tokens;
}
fprintf (out, "State %d: %d lookahead tokens\n", fprintf (out, "State %d: %d lookahead tokens\n",
i, n_lookahead_tokens); i, n_lookahead_tokens);
if (reds->lookahead_tokens) if (reds->lookahead_tokens)
for (j = 0; j < reds->num; ++j) {
BITSET_FOR_EACH (iter, reds->lookahead_tokens[j], k, 0) int j, k;
{ for (j = 0; j < reds->num; ++j)
fprintf (out, " on %d (%s) -> rule %d\n", BITSET_FOR_EACH (iter, reds->lookahead_tokens[j], k, 0)
k, symbols[k]->tag, fprintf (out, " on %d (%s) -> rule %d\n",
reds->rules[j]->number); k, symbols[k]->tag,
}; reds->rules[j]->number);
}
} }
fprintf (out, "Lookahead tokens: END\n"); fprintf (out, "Lookahead tokens: END\n");
} }
+5
View File
@@ -704,6 +704,11 @@ output (void)
/* Process the selected skeleton file. */ /* Process the selected skeleton file. */
output_skeleton (); output_skeleton ();
/* If late errors were generated, destroy the generated source
files. */
if (complaint_status)
unlink_generated_sources ();
obstack_free (&format_obstack, NULL); obstack_free (&format_obstack, NULL);
} }
+33 -33
View File
@@ -65,40 +65,39 @@ print_core (FILE *out, int level, state *s)
sitems = itemset; sitems = itemset;
snritems = nitemset; snritems = nitemset;
if (!snritems) { if (!snritems)
xml_puts (out, level, "<itemset/>"); {
return; xml_puts (out, level, "<itemset/>");
} return;
}
xml_puts (out, level, "<itemset>"); xml_puts (out, level, "<itemset>");
for (i = 0; i < snritems; i++) for (i = 0; i < snritems; i++)
{ {
bool printed = false; bool printed = false;
item_number *sp; item_number *sp1 = ritem + sitems[i];
item_number *sp1; item_number *sp = sp1;
rule_number r; rule *r;
sp1 = sp = ritem + sitems[i]; while (0 <= *sp)
while (*sp >= 0)
sp++; sp++;
r = item_number_as_rule_number (*sp); r = &rules[item_number_as_rule_number (*sp)];
sp = rules[r].rhs; sp = r->rhs;
/* Display the lookahead tokens? */ /* Display the lookahead tokens? */
if (item_number_is_rule_number (*sp1)) if (item_number_is_rule_number (*sp1))
{ {
reductions *reds = s->reductions; reductions *reds = s->reductions;
int red = state_reduction_find (s, &rules[r]); int red = state_reduction_find (s, r);
/* Print item with lookaheads if there are. */ /* Print item with lookaheads if there are. */
if (reds->lookahead_tokens && red != -1) if (reds->lookahead_tokens && red != -1)
{ {
xml_printf (out, level + 1, xml_printf (out, level + 1,
"<item rule-number=\"%d\" point=\"%d\">", "<item rule-number=\"%d\" point=\"%d\">",
rules[r].number, sp1 - sp); r->number, sp1 - sp);
state_rule_lookahead_tokens_print_xml (s, &rules[r], state_rule_lookahead_tokens_print_xml (s, r,
out, level + 2); out, level + 2);
xml_puts (out, level + 1, "</item>"); xml_puts (out, level + 1, "</item>");
printed = true; printed = true;
@@ -106,12 +105,10 @@ print_core (FILE *out, int level, state *s)
} }
if (!printed) if (!printed)
{ xml_printf (out, level + 1,
xml_printf (out, level + 1, "<item rule-number=\"%d\" point=\"%d\"/>",
"<item rule-number=\"%d\" point=\"%d\"/>", r->number,
rules[r].number, sp1 - sp);
sp1 - sp);
}
} }
xml_puts (out, level, "</itemset>"); xml_puts (out, level, "</itemset>");
} }
@@ -136,10 +133,11 @@ print_transitions (state *s, FILE *out, int level)
} }
/* Nothing to report. */ /* Nothing to report. */
if (!n) { if (!n)
xml_puts (out, level, "<transitions/>"); {
return; xml_puts (out, level, "<transitions/>");
} return;
}
/* Report lookahead tokens and shifts. */ /* Report lookahead tokens and shifts. */
xml_puts (out, level, "<transitions>"); xml_puts (out, level, "<transitions>");
@@ -190,10 +188,11 @@ print_errs (FILE *out, int level, state *s)
count = true; count = true;
/* Nothing to report. */ /* Nothing to report. */
if (!count) { if (!count)
xml_puts (out, level, "<errors/>"); {
return; xml_puts (out, level, "<errors/>");
} return;
}
/* Report lookahead tokens and errors. */ /* Report lookahead tokens and errors. */
xml_puts (out, level, "<errors>"); xml_puts (out, level, "<errors>");
@@ -287,10 +286,11 @@ print_reductions (FILE *out, int level, state *s)
} }
/* Nothing to report. */ /* Nothing to report. */
if (!report) { if (!report)
xml_puts (out, level, "<reductions/>"); {
return; xml_puts (out, level, "<reductions/>");
} return;
}
xml_puts (out, level, "<reductions>"); xml_puts (out, level, "<reductions>");
+5 -2
View File
@@ -106,8 +106,11 @@ print_core (FILE *out, state *s)
for (sp = rules[r].rhs; sp < sp1; sp++) for (sp = rules[r].rhs; sp < sp1; sp++)
fprintf (out, " %s", symbols[*sp]->tag); fprintf (out, " %s", symbols[*sp]->tag);
fputs (" .", out); fputs (" .", out);
for (/* Nothing */; *sp >= 0; ++sp) if (0 <= *rules[r].rhs)
fprintf (out, " %s", symbols[*sp]->tag); for (/* Nothing */; 0 <= *sp; ++sp)
fprintf (out, " %s", symbols[*sp]->tag);
else
fprintf (out, " %%empty");
/* Display the lookahead tokens? */ /* Display the lookahead tokens? */
if (report_flag & report_lookahead_tokens if (report_flag & report_lookahead_tokens
+5 -2
View File
@@ -84,8 +84,11 @@ print_core (struct obstack *oout, state *s)
obstack_1grow (oout, '.'); obstack_1grow (oout, '.');
for (/* Nothing */; *sp >= 0; ++sp) if (0 <= *r->rhs)
obstack_printf (oout, " %s", escape (symbols[*sp]->tag)); for (/* Nothing */; *sp >= 0; ++sp)
obstack_printf (oout, " %s", escape (symbols[*sp]->tag));
else
obstack_printf (oout, " %%empty");
/* Experimental feature: display the lookahead tokens. */ /* Experimental feature: display the lookahead tokens. */
if (report_flag & report_lookahead_tokens if (report_flag & report_lookahead_tokens
+3 -2
View File
@@ -244,8 +244,9 @@ at_output (int argc, char *argv[], char **out_namep, int *out_linenop)
xfclose (yyout); xfclose (yyout);
} }
*out_namep = xstrdup (argv[1]); *out_namep = xstrdup (argv[1]);
output_file_name_check (out_namep); output_file_name_check (out_namep, true);
yyout = xfopen (*out_namep, "w"); /* If there were errors, do not generate the output. */
yyout = xfopen (complaint_status ? "/dev/null" : *out_namep, "w");
*out_linenop = 1; *out_linenop = 1;
} }
+52 -39
View File
@@ -243,7 +243,7 @@ typedef std::list<std::string> strings_type;
// digraph for the left square bracket. // digraph for the left square bracket.
%type <::std::list<std::string>> list result; %type <::std::list<std::string>> list result;
%printer { yyo << $][$; } %printer { yyo << $$; }
<int> <::std::string> <::std::list<std::string>>; <int> <::std::string> <::std::list<std::string>>;
%% %%
@@ -253,13 +253,13 @@ result:
list: list:
/* nothing */ { /* Generates an empty string list */ } /* nothing */ { /* Generates an empty string list */ }
| list item { std::swap ($][$,$][1); $$.push_back ($][2); } | list item { std::swap ($$,$][1); $$.push_back ($][2); }
| list error { std::swap ($][$,$][1); } | list error { std::swap ($$,$][1); }
; ;
item: item:
TEXT { std::swap ($][$,$][1); } TEXT { std::swap ($$,$][1); }
| NUMBER { if ($][1 == 3) YYERROR; else $][$ = string_cast ($][1); } | NUMBER { if ($][1 == 3) YYERROR; else $$ = string_cast ($][1); }
; ;
%% %%
]AT_TOKEN_CTOR_IF([], ]AT_TOKEN_CTOR_IF([],
@@ -649,11 +649,12 @@ AT_CLEANUP
## Exception safety. ## ## Exception safety. ##
## ------------------ ## ## ------------------ ##
# AT_TEST([BISON-DIRECTIVES]) # AT_TEST([BISON-DIRECTIVES = ''], [WITH-RECOVERY = "with"])
# --------------------------- # ----------------------------------------------------------
# Check that no object is leaked when exceptions are thrown. # Check that no object is leaked when exceptions are thrown.
# WITH-RECOVERY = "with" or "without".
m4_pushdef([AT_TEST], m4_pushdef([AT_TEST],
[AT_SETUP([[Exception safety $1]]) [AT_SETUP([[Exception safety $2 error recovery $1]])
AT_SKIP_IF_EXCEPTION_SUPPORT_IS_POOR AT_SKIP_IF_EXCEPTION_SUPPORT_IS_POOR
@@ -669,27 +670,43 @@ $1
#include <cassert> #include <cassert>
#include <cstdlib> // size_t and getenv. #include <cstdlib> // size_t and getenv.
#include <iostream> #include <iostream>
#include <list> #include <set>
bool debug = false; bool debug = false;
/// A class that counts its number of instances. /// A class that tracks its instances.
struct Object struct Object
{ {
char val; char val;
Object (char v)
: val (v)
{
Object::instances.push_back(this);
log (this, "Object::Object");
}
Object () Object ()
: val ('?') : val ('?')
{ {
Object::instances.push_back(this);
log (this, "Object::Object"); log (this, "Object::Object");
Object::instances.insert (this);
}
Object (const Object& that)
: val (that.val)
{
log (this, "Object::Object");
Object::instances.insert (this);
}
Object (char v)
: val (v)
{
log (this, "Object::Object");
Object::instances.insert (this);
}
~Object ()
{
log (this, "Object::~Object");
objects::const_iterator i = instances.find (this);
// Make sure this object is alive.
assert (i != instances.end ());
Object::instances.erase (i);
} }
Object& operator= (char v) Object& operator= (char v)
@@ -698,14 +715,8 @@ $1
return *this; return *this;
} }
~Object ()
{
Object::instances.remove (this);
log (this, "Object::~Object");
}
// Static part. // Static part.
typedef std::list<const Object*> objects; typedef std::set<const Object*> objects;
static objects instances; static objects instances;
static bool static bool
@@ -785,22 +796,23 @@ $1
start: list {]AT_VARIANT_IF([], [ delete $][1]; )[}; start: list {]AT_VARIANT_IF([], [ delete $][1]; )[};
list: list:
item { $][$ = $][1; } item { $$ = $][1; }
// Right recursion to load the stack. // Right recursion to load the stack.
| item list { $][$ = $][1; ]AT_VARIANT_IF([], [delete $][2]; )[} | item list { $$ = $][1; ]AT_VARIANT_IF([], [delete $][2]; )[}
; ;
item: item:
'a' { $$][ = $][1; } 'a' { $$ = $][1; }
| 'e' { YYUSE ($][$); YYUSE($][1); error ("syntax error"); } | 'e' { YYUSE ($$); YYUSE($][1); error ("syntax error"); }
// Not just 'E', otherwise we reduce when 'E' is the lookahead, and // Not just 'E', otherwise we reduce when 'E' is the lookahead, and
// then the stack is emptied, defeating the point of the test. // then the stack is emptied, defeating the point of the test.
| 'E' 'a' { YYUSE($][1); $][$ = $][2; } | 'E' 'a' { YYUSE($][1); $$ = $][2; }
| 'R' { ]AT_VARIANT_IF([], [$][$ = YY_NULLPTR; delete $][1]; )[YYERROR; } | 'R' { ]AT_VARIANT_IF([], [$$ = YY_NULLPTR; delete $][1]; )[YYERROR; }
| 'p' { $][$ = $][1; } | 'p' { $$ = $][1; }
| 's' { $][$ = $][1; throw std::runtime_error ("reduction"); } | 's' { $$ = $][1; throw std::runtime_error ("reduction"); }
| 'T' { ]AT_VARIANT_IF([], [$][$ = YY_NULLPTR; delete $][1]; )[YYABORT; } | 'T' { ]AT_VARIANT_IF([], [$$ = YY_NULLPTR; delete $][1]; )[YYABORT; }
| error { ]AT_VARIANT_IF([], [$][$ = YY_NULLPTR; ])[yyerrok; } ]m4_if([$2], [with],
[[| error { $$ = ]AT_VARIANT_IF([], [new ])[Object ('R'); yyerrok; }]])[
; ;
%% %%
@@ -903,16 +915,17 @@ AT_PARSER_CHECK([[./input aaaaE]], [[2]], [[]],
AT_PARSER_CHECK([[./input aaaaT]], [[1]]) AT_PARSER_CHECK([[./input aaaaT]], [[1]])
# There is error-recovery, so exit success. AT_PARSER_CHECK([[./input aaaaR]], [m4_if([$2], [with], [0], [1])])
AT_PARSER_CHECK([[./input aaaaR]], [[0]])
AT_BISON_OPTION_POPDEFS AT_BISON_OPTION_POPDEFS
AT_CLEANUP AT_CLEANUP
]) ])
AT_TEST AT_TEST([], [with])
AT_TEST([%define api.value.type variant]) AT_TEST([], [without])
AT_TEST([%define api.value.type variant], [with])
AT_TEST([%define api.value.type variant], [without])
m4_popdef([AT_TEST]) m4_popdef([AT_TEST])
+12 -12
View File
@@ -1447,7 +1447,7 @@ State 0
0 $accept: . start $end 0 $accept: . start $end
1 start: . resolved_conflict 'a' reported_conflicts 'a' 1 start: . resolved_conflict 'a' reported_conflicts 'a'
2 resolved_conflict: . 'a' unreachable1 2 resolved_conflict: . 'a' unreachable1
3 | . ['a'] 3 | . %empty ['a']
$default reduce using rule 3 (resolved_conflict) $default reduce using rule 3 (resolved_conflict)
@@ -1483,7 +1483,7 @@ State 4
1 start: resolved_conflict 'a' . reported_conflicts 'a' 1 start: resolved_conflict 'a' . reported_conflicts 'a'
8 reported_conflicts: . 'a' 8 reported_conflicts: . 'a'
9 | . 'a' 9 | . 'a'
10 | . ['a'] 10 | . %empty ['a']
'a' shift, and go to state 5 'a' shift, and go to state 5
@@ -1576,11 +1576,11 @@ AT_CHECK([[cat input.output | sed -n '/^State 0$/,/^State 1$/p']], 0,
6 | . empty_c1 'c' 6 | . empty_c1 'c'
7 | . empty_c2 'c' 7 | . empty_c2 'c'
8 | . empty_c3 'c' 8 | . empty_c3 'c'
9 empty_a: . ['a'] 9 empty_a: . %empty ['a']
10 empty_b: . [] 10 empty_b: . %empty []
11 empty_c1: . [] 11 empty_c1: . %empty []
12 empty_c2: . [] 12 empty_c2: . %empty []
13 empty_c3: . ['c'] 13 empty_c3: . %empty ['c']
'b' shift, and go to state 1 'b' shift, and go to state 1
@@ -1652,11 +1652,11 @@ AT_CHECK([[cat input.output | sed -n '/^State 0$/,/^State 1$/p']], 0,
6 | . empty_c1 'c' 6 | . empty_c1 'c'
7 | . empty_c2 'c' 7 | . empty_c2 'c'
8 | . empty_c3 'c' 8 | . empty_c3 'c'
9 empty_a: . [] 9 empty_a: . %empty []
10 empty_b: . [] 10 empty_b: . %empty []
11 empty_c1: . [] 11 empty_c1: . %empty []
12 empty_c2: . ['c'] 12 empty_c2: . %empty ['c']
13 empty_c3: . ['c'] 13 empty_c3: . %empty ['c']
'a' error (nonassociative) 'a' error (nonassociative)
'b' error (nonassociative) 'b' error (nonassociative)
+38 -19
View File
@@ -17,12 +17,23 @@
AT_BANNER([[Output file names.]]) AT_BANNER([[Output file names.]])
# AT_CHECK_FILES(EXPECTED-FILES, [IGNORED-FILES])
# -----------------------------------------------
# Check that the current directory contains FILE... (sorted).
m4_define([AT_CHECK_FILES],
[AT_CHECK([[find . -type f |
$PERL -ne '
s,\./,,; chomp;
push @file, $_ unless m{^($2|testsuite.log)$};
END { print join (" ", sort @file), "\n" }']],
[], [$1
])])
# AT_CHECK_OUTPUT(INPUT-FILE, [DIRECTIVES], [FLAGS], EXPECTED-FILES, [SHELLIO], # AT_CHECK_OUTPUT(INPUT-FILE, [DIRECTIVES], [FLAGS], EXPECTED-FILES, [STATUS],
# [ADDITIONAL-TESTS], [PRE-TESTS]) # [ADDITIONAL-TESTS], [PRE-TESTS])
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
m4_define([AT_CHECK_OUTPUT], m4_define([AT_CHECK_OUTPUT],
[AT_SETUP([[Output files: ]$2 $3 $5])[ [AT_SETUP([[Output files: ]$2 $3])[
]$7[ ]$7[
for file in ]$1 $4[; do for file in ]$1 $4[; do
case $file in case $file in
@@ -32,18 +43,12 @@ done
]AT_DATA([$1], ]AT_DATA([$1],
[$2[ [$2[
%% %%
foo: {}; foo: %empty {};
]])[ ]])[
]AT_BISON_CHECK([$3 $1 $5], 0)[ ]AT_BISON_CHECK([$3 $1], [$5], [], [ignore])[
# Ignore the files non-generated files # Ignore the files non-generated files
]AT_CHECK([[find . -type f | ]AT_CHECK_FILES([$4], [$1])[
$PERL -ne '
s,\./,,; chomp;
push @file, $_ unless m{^($1|testsuite.log)$};
END { print join (" ", sort @file), "\n" }']],
[], [$4
])[
]$6[ ]$6[
]AT_CLEANUP[ ]AT_CLEANUP[
]]) ]])
@@ -54,9 +59,9 @@ AT_CHECK_OUTPUT([foo.y], [], [-dv],
# Some versions of Valgrind (at least valgrind-3.6.0.SVN-Debian) report # Some versions of Valgrind (at least valgrind-3.6.0.SVN-Debian) report
# "fgrep: write error: Bad file descriptor" when stdout is closed, so we # "fgrep: write error: Bad file descriptor" when stdout is closed, so we
# skip this test group during maintainer-check-valgrind. # skip this test group during maintainer-check-valgrind.
AT_CHECK_OUTPUT([foo.y], [], [-dv], AT_CHECK_OUTPUT([foo.y], [], [-dv >&-],
[foo.output foo.tab.c foo.tab.h], [foo.output foo.tab.c foo.tab.h],
[>&-], [], [], [],
[AT_CHECK([[case "$PREBISON" in *valgrind*) exit 77;; esac]])]) [AT_CHECK([[case "$PREBISON" in *valgrind*) exit 77;; esac]])])
AT_CHECK_OUTPUT([foo.y], [], [-dv -o foo.c], AT_CHECK_OUTPUT([foo.y], [], [-dv -o foo.c],
@@ -114,6 +119,20 @@ AT_CHECK_OUTPUT([foo.yy], [],
[-o foo.c++ --graph=foo.gph], [-o foo.c++ --graph=foo.gph],
[foo.c++ foo.gph]) [foo.c++ foo.gph])
# Do not generate code when there are early errors (even warnings as
# errors).
AT_CHECK_OUTPUT([foo.y], [%type <foo> useless],
[--defines --graph --xml --report=all -Wall -Werror],
[foo.dot foo.output foo.xml],
[1])
# Do not generate code when there are late errors (even warnings as
# errors).
AT_CHECK_OUTPUT([foo.y], [%define useless],
[--defines --graph --xml --report=all -Wall -Werror],
[foo.dot foo.output foo.xml],
[1])
## ------------ ## ## ------------ ##
## C++ output. ## ## C++ output. ##
@@ -290,7 +309,7 @@ a: ;
b: 'b'; b: 'b';
]], ]],
[[ [[
0 [label="State 0\n\l 0 $accept: . exp $end\l 1 exp: . a '?' b\l 2 a: .\l"] 0 [label="State 0\n\l 0 $accept: . exp $end\l 1 exp: . a '?' b\l 2 a: . %empty\l"]
0 -> 1 [style=dashed label="exp"] 0 -> 1 [style=dashed label="exp"]
0 -> 2 [style=dashed label="a"] 0 -> 2 [style=dashed label="a"]
0 -> "0R2" [style=solid] 0 -> "0R2" [style=solid]
@@ -332,7 +351,7 @@ empty_b: %prec 'b';
empty_c: %prec 'c'; empty_c: %prec 'c';
]], ]],
[[ [[
0 [label="State 0\n\l 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 [label="State 0\n\l 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: . %empty ['a']\l 8 empty_b: . %empty ['b']\l 9 empty_c: . %empty ['c']\l"]
0 -> 1 [style=solid label="'a'"] 0 -> 1 [style=solid label="'a'"]
0 -> 2 [style=solid label="'b'"] 0 -> 2 [style=solid label="'b'"]
0 -> 3 [style=solid label="'c'"] 0 -> 3 [style=solid label="'c'"]
@@ -399,7 +418,7 @@ empty_b: %prec 'b';
empty_c: %prec 'c'; empty_c: %prec 'c';
]], ]],
[[ [[
0 [label="State 0\n\l 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 [label="State 0\n\l 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: . %empty ['a']\l 8 empty_b: . %empty []\l 9 empty_c: . %empty []\l"]
0 -> 1 [style=solid label="'b'"] 0 -> 1 [style=solid label="'b'"]
0 -> 2 [style=solid label="'c'"] 0 -> 2 [style=solid label="'c'"]
0 -> 3 [style=dashed label="start"] 0 -> 3 [style=dashed label="start"]
@@ -447,7 +466,7 @@ a: ;
b: ; b: ;
]], ]],
[[ [[
0 [label="State 0\n\l 0 $accept: . exp $end\l 1 exp: . a\l 2 | . b\l 3 a: . [$end]\l 4 b: . [$end]\l"] 0 [label="State 0\n\l 0 $accept: . exp $end\l 1 exp: . a\l 2 | . b\l 3 a: . %empty [$end]\l 4 b: . %empty [$end]\l"]
0 -> 1 [style=dashed label="exp"] 0 -> 1 [style=dashed label="exp"]
0 -> 2 [style=dashed label="a"] 0 -> 2 [style=dashed label="a"]
0 -> 3 [style=dashed label="b"] 0 -> 3 [style=dashed label="b"]
@@ -480,7 +499,7 @@ b: ;
c: ; c: ;
]], ]],
[[ [[
0 [label="State 0\n\l 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 [label="State 0\n\l 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: . %empty [';', '.']\l 9 b: . %empty ['?', '!']\l 10 c: . %empty [';', '?']\l"]
0 -> 1 [style=dashed label="exp"] 0 -> 1 [style=dashed label="exp"]
0 -> 2 [style=dashed label="a"] 0 -> 2 [style=dashed label="a"]
0 -> 3 [style=dashed label="b"] 0 -> 3 [style=dashed label="b"]
@@ -595,7 +614,7 @@ imm: '0';
"11R7d" [label="R7", fillcolor=5, shape=diamond, style=filled] "11R7d" [label="R7", fillcolor=5, shape=diamond, style=filled]
11 -> "11R7" [style=solid] 11 -> "11R7" [style=solid]
"11R7" [label="R7", fillcolor=3, shape=diamond, style=filled] "11R7" [label="R7", fillcolor=3, shape=diamond, style=filled]
12 [label="State 12\n\l 4 ifexp: \"if\" exp \"then\" exp . elseexp\l 5 elseexp: . \"else\" exp\l 6 | . [$end, \"then\", \"else\", '+']\l 7 opexp: exp . '+' exp\l"] 12 [label="State 12\n\l 4 ifexp: \"if\" exp \"then\" exp . elseexp\l 5 elseexp: . \"else\" exp\l 6 | . %empty [$end, \"then\", \"else\", '+']\l 7 opexp: exp . '+' exp\l"]
12 -> 13 [style=solid label="\"else\""] 12 -> 13 [style=solid label="\"else\""]
12 -> 9 [style=solid label="'+'"] 12 -> 9 [style=solid label="'+'"]
12 -> 14 [style=dashed label="elseexp"] 12 -> 14 [style=dashed label="elseexp"]
+5 -5
View File
@@ -1057,7 +1057,7 @@ State 12
4 A: 'a' 'a' . B 4 A: 'a' 'a' . B
5 B: . 'a' 5 B: . 'a'
6 | . ]AT_COND_CASE([[LALR]], [[['a', 'b']]], [[['a']]])[ 6 | . %empty ]AT_COND_CASE([[LALR]], [[['a', 'b']]], [[['a']]])[
]AT_COND_CASE([[canonical LR]], [['a']], ]AT_COND_CASE([[canonical LR]], [['a']],
[[$default]])[ reduce using rule 6 (B) [[$default]])[ reduce using rule 6 (B)
@@ -1087,7 +1087,7 @@ State 15
4 A: 'a' 'a' . B 4 A: 'a' 'a' . B
5 B: . 'a' 5 B: . 'a'
6 | . [$end] 6 | . %empty [$end]
7 c: 'a' 'a' . 'b' 7 c: 'a' 'a' . 'b'
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[20]], 'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[20]],
@@ -1150,7 +1150,7 @@ State 22]])[
4 A: 'a' 'a' . B 4 A: 'a' 'a' . B
5 B: . 'a' 5 B: . 'a'
6 | . ['b'] 6 | . %empty ['b']
'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[23]], 'a' shift, and go to state ]AT_COND_CASE([[canonical LR]], [[23]],
[[16]])[ [[16]])[
@@ -1575,8 +1575,8 @@ State 3
1 start: a . b 1 start: a . b
2 | a . b 'a' 2 | a . b 'a'
3 | a . c 'b' 3 | a . c 'b'
5 b: . [$end, 'a'] 5 b: . %empty [$end, 'a']
6 c: . ['b']]AT_COND_CASE([[most]], [[ 6 c: . %empty ['b']]AT_COND_CASE([[most]], [[
'b' reduce using rule 6 (c) 'b' reduce using rule 6 (c)
$default reduce using rule 5 (b)]], [[ $default reduce using rule 5 (b)]], [[