Skip to content

Commit

Permalink
cex: display shifts before reductions
Browse files Browse the repository at this point in the history
When reporting counterexamples for s/r conflicts, put the shift first.
This is more natural, and displays the default resolution first, which
is also what happens for r/r conflicts where the smallest rule number
is displayed first, and "wins".

* src/counterexample.c (counterexample): Add a shift_reduce member.
(new_counterexample): Adjust.
Swap the derivations when this is a s/r conflict.
(print_counterexample): For s/r conflicts, prefer "Shift derivation"
and "Reduce derivation" rather than "First/Second derivation".

* tests/conflicts.at, tests/counterexample.at, tests/report.at: Adjust.
* NEWS, doc/bison.texi: Ditto.
  • Loading branch information
akimd committed Jul 12, 2020
1 parent 577f594 commit ba596de
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 108 deletions.
14 changes: 8 additions & 6 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ GNU Bison NEWS

* Noteworthy changes in release ?.? (????-??-??) [?]

Changes in the display of counterexamples.

** Documentation

*** Examples
Expand Down Expand Up @@ -45,8 +47,8 @@ GNU Bison NEWS
conflict. For example:

Example exp '+' exp • '/' exp
First derivation exp → [ exp → [ exp '+' exp • ] '/' exp ]
Second derivation exp → [ exp '+' exp → [ exp '/' exp ] ]
Shift derivation exp → [ exp '+' exp → [ exp • '/' exp ] ]
Reduce derivation exp → [ exp → [ exp '+' exp • ] '/' exp ]

When Bison is installed with text styling enabled, the example is actually
shown twice, with colors highlighting the ambiguity.
Expand All @@ -56,10 +58,10 @@ GNU Bison NEWS
bison cannot find an example that can be derived in two ways, it instead
generates two examples that are the same up until the dot:

First example expr • ID $end
First derivation $accept → [ s → [ a → [ expr ] ID ] $end ]
Second example expr • ID ',' ID $end
Second derivation $accept → [ s → [ a → [ expr → [ expr • ID ',' ] ] ID ] $end ]
First example expr • ID ',' ID $end
Shift derivation $accept → [ s → [ a → [ expr → [ expr • ID ',' ] ] ID ] $end ]
Second example expr • ID $end
Reduce derivation $accept → [ s → [ a → [ expr ] ID ] $end ]

In these cases, the parser usually doesn't have enough lookahead to
differentiate the two given examples.
Expand Down
42 changes: 21 additions & 21 deletions doc/bison.texi
Original file line number Diff line number Diff line change
Expand Up @@ -9936,25 +9936,25 @@ output is actually in color)}:
@example
Shift/reduce conflict on token "else":
@group
Example @yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @yellow{"else" stmt}
First derivation @yellow{if_stmt @arrow{} [ "if" expr "then"} @green{stmt @arrow{} [} @blue{if_stmt @arrow{} [ "if" expr "then" stmt} @red{•} @blue{]} @green{]} @yellow{"else" stmt ]}
Example @yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @blue{"else" stmt}
Second derivation @yellow{if_stmt @arrow{} [ "if" expr "then"} @green{stmt @arrow{} [} @blue{if_stmt @arrow{} [ "if" expr "then" stmt} @red{•} @blue{"else" stmt ]} @green{]} @yellow{]}
Shift derivation @yellow{if_stmt @arrow{} [ "if" expr "then"} @green{stmt @arrow{} [} @blue{if_stmt @arrow{} [ "if" expr "then" stmt} @red{•} @blue{"else" stmt ]} @green{]} @yellow{]}
Example @yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @yellow{"else" stmt}
Reduce derivation @yellow{if_stmt @arrow{} [ "if" expr "then"} @green{stmt @arrow{} [} @blue{if_stmt @arrow{} [ "if" expr "then" stmt} @red{•} @blue{]} @green{]} @yellow{"else" stmt ]}
@end group
@end example
@end ifhtml
@ifnothtml
@smallexample
Shift/reduce conflict on token "else":
@group
Example
@yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @yellow{"else" stmt}
First derivation
@yellow{if_stmt @arrow{} [ "if" expr "then"} @green{stmt @arrow{} [} @blue{if_stmt @arrow{} [ "if" expr "then" stmt} @red{•} @blue{]} @green{]} @yellow{"else" stmt ]}
Example
@yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @blue{"else" stmt}
Second derivation
Shift derivation
@yellow{if_stmt @arrow{} [ "if" expr "then"} @green{stmt @arrow{} [} @blue{if_stmt @arrow{} [ "if" expr "then" stmt} @red{•} @blue{"else" stmt ]} @green{]} @yellow{]}
Example
@yellow{"if" expr "then"} @blue{"if" expr "then" stmt} @red{•} @yellow{"else" stmt}
Reduce derivation
@yellow{if_stmt @arrow{} [ "if" expr "then"} @green{stmt @arrow{} [} @blue{if_stmt @arrow{} [ "if" expr "then" stmt} @red{•} @blue{]} @green{]} @yellow{"else" stmt ]}
@end group
@end smallexample
@end ifnothtml
Expand Down Expand Up @@ -9987,10 +9987,10 @@ $ @kbd{bison -Wcex sequence.y}
sequence.y: @dwarning{warning}: 1 shift/reduce conflict [@dwarning{-Wconflicts-sr}]
sequence.y: @dwarning{warning}: 2 reduce/reduce conflicts [@dwarning{-Wconflicts-rr}]
Shift/reduce conflict on token "word":
Example @red{•} @yellow{"word"}
First derivation @yellow{sequence @arrow{} [} @green{sequence @arrow{} [} @red{•} @green{]} @yellow{"word" ]}
Example @red{•} @green{"word"}
Second derivation @yellow{sequence @arrow{} [} @green{maybeword @arrow{} [} @red{•} @green{"word" ]} @yellow{]}
Shift derivation @yellow{sequence @arrow{} [} @green{maybeword @arrow{} [} @red{•} @green{"word" ]} @yellow{]}
Example @red{•} @yellow{"word"}
Reduce derivation @yellow{sequence @arrow{} [} @green{sequence @arrow{} [} @red{•} @green{]} @yellow{"word" ]}

Reduce/reduce conflict on tokens $end, "word":
Example @red{•}
Expand All @@ -9999,10 +9999,10 @@ Reduce/reduce conflict on tokens $end, "word":
Second derivation @yellow{sequence @arrow{} [} @green{maybeword @arrow{} [} @red{•} @green{]} @yellow{]}

Shift/reduce conflict on token "word":
Example @red{•} @yellow{"word"}
First derivation @yellow{sequence @arrow{} [} @green{sequence @arrow{} [} @blue{maybeword @arrow{} [} @red{•} @blue{]} @green{]} @yellow{"word" ]}
Example @red{•} @green{"word"}
Second derivation @yellow{sequence @arrow{} [} @green{maybeword @arrow{} [} @red{•} @green{"word" ]} @yellow{]}
Shift derivation @yellow{sequence @arrow{} [} @green{maybeword @arrow{} [} @red{•} @green{"word" ]} @yellow{]}
Example @red{•} @yellow{"word"}
Reduce derivation @yellow{sequence @arrow{} [} @green{sequence @arrow{} [} @blue{maybeword @arrow{} [} @red{•} @blue{]} @green{]} @yellow{"word" ]}

sequence.y:8.3-45: @dwarning{warning}: rule useless in parser due to conflicts [@dwarning{-Wother}]
8 | @dwarning{%empty @{ printf ("empty maybeword\n"); @}}
Expand Down Expand Up @@ -10033,10 +10033,10 @@ expr: %empty | expr ID ','

@smallexample
Shift/reduce conflict on token ID:
First example @blue{expr} @red{•} @green{ID} @yellow{$end}
First derivation @yellow{$accept @arrow{} [} @green{s @arrow{} [} @blue{a @arrow{} [ expr} @red{•} @blue{]} @green{ID ]} @yellow{$end ]}
Second example @purple{expr} @red{•} @purple{ID ','} @green{ID} @yellow{$end}
Second derivation @yellow{$accept @arrow{} [} @green{s @arrow{} [} @blue{a @arrow{} [} @purple{expr @arrow{} [ expr} @red{•} @purple{ID ',' ]} @blue{]} @green{ID ]} @yellow{$end ]}
First example @purple{expr} @red{•} @purple{ID ','} @green{ID} @yellow{$end}
Shift derivation @yellow{$accept @arrow{} [} @green{s @arrow{} [} @blue{a @arrow{} [} @purple{expr @arrow{} [ expr} @red{•} @purple{ID ',' ]} @blue{]} @green{ID ]} @yellow{$end ]}
Second example @blue{expr} @red{•} @green{ID} @yellow{$end}
Reduce derivation @yellow{$accept @arrow{} [} @green{s @arrow{} [} @blue{a @arrow{} [ expr} @red{•} @blue{]} @green{ID ]} @yellow{$end ]}
@end smallexample

This conflict is caused by the parser not having enough information to know
Expand Down Expand Up @@ -10432,10 +10432,10 @@ counterexamples within the report, augmented with the corresponding items
Shift/reduce conflict on token '/':
1 exp: exp '+' exp •
4 exp: exp • '/' exp
Example @green{exp '+' exp} @red{•} @yellow{'/' exp}
First derivation @yellow{exp @arrow{} [} @green{exp @arrow{} [ exp '+' exp} @red{•} @green{]} @yellow{'/' exp ]}
Example @yellow{exp '+'} @green{exp} @red{•} @green{'/' exp}
Second derivation @yellow{exp @arrow{} [ exp '+'} @green{exp @arrow{} [ exp} @red{•} @green{'/' exp ]} @yellow{]}
Shift derivation @yellow{exp @arrow{} [ exp '+'} @green{exp @arrow{} [ exp} @red{•} @green{'/' exp ]} @yellow{]}
Example @green{exp '+' exp} @red{•} @yellow{'/' exp}
Reduce derivation @yellow{exp @arrow{} [} @green{exp @arrow{} [ exp '+' exp} @red{•} @green{]} @yellow{'/' exp ]}
@end example

This shows two separate derivations in the grammar for the same @code{exp}:
Expand Down
34 changes: 25 additions & 9 deletions src/counterexample.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,29 @@ typedef struct
{
derivation *d1;
derivation *d2;
bool shift_reduce;
bool unifying;
bool timeout;
} counterexample;

static counterexample *
new_counterexample (derivation *d1, derivation *d2,
bool shift_reduce,
bool u, bool t)
{
counterexample *res = xmalloc (sizeof *res);
res->d1 = d1;
res->d2 = d2;
res->shift_reduce = shift_reduce;
if (shift_reduce)
{
// Display the shift first.
res->d1 = d2;
res->d2 = d1;
}
else
{
res->d1 = d1;
res->d2 = d2;
}
res->unifying = u;
res->timeout = t;
return res;
Expand All @@ -107,7 +119,7 @@ print_counterexample (counterexample *cex, FILE *out, const char *prefix)
prefix, cex->unifying ? _("Example") : _("First example"));
derivation_print_leaves (cex->d1, out, prefix);
fprintf (out, " %s%-20s ",
prefix, _("First derivation"));
prefix, cex->shift_reduce ? _("Shift derivation") : _("First derivation"));
derivation_print (cex->d1, out, prefix);

// If we output to the terminal (via stderr) and we have color
Expand All @@ -120,7 +132,7 @@ print_counterexample (counterexample *cex, FILE *out, const char *prefix)
derivation_print_leaves (cex->d2, out, prefix);
}
fprintf (out, " %s%-20s ",
prefix, _("Second derivation"));
prefix, cex->shift_reduce ? _("Reduce derivation") : _("Second derivation"));
derivation_print (cex->d2, out, prefix);

fputc ('\n', out);
Expand Down Expand Up @@ -506,7 +518,7 @@ example_from_path (bool shift_reduce,
: shortest_path_from_start (itm2, next_sym);
derivation *deriv2 = complete_diverging_example (next_sym, path_2, NULL);
gl_list_free (path_2);
return new_counterexample (deriv1, deriv2, false, true);
return new_counterexample (deriv1, deriv2, shift_reduce, false, true);
}

/*
Expand Down Expand Up @@ -619,7 +631,8 @@ ss_set_parse_state (search_state *ss, int idx, parse_state *ps)
*/
static counterexample *
complete_diverging_examples (search_state *ss,
symbol_number next_sym)
symbol_number next_sym,
bool shift_reduce)
{
derivation *new_derivs[2];
for (int i = 0; i < 2; ++i)
Expand All @@ -630,7 +643,8 @@ complete_diverging_examples (search_state *ss,
new_derivs[i] = complete_diverging_example (next_sym, sitems, derivs);
gl_list_free (sitems);
}
return new_counterexample (new_derivs[0], new_derivs[1], false, true);
return new_counterexample (new_derivs[0], new_derivs[1],
shift_reduce, false, true);
}

/*
Expand Down Expand Up @@ -1111,7 +1125,7 @@ unifying_example (state_item_number itm1,
{
// Once we have two derivations for the same symbol,
// we've found a unifying counterexample.
cex = new_counterexample (d1, d2, true, false);
cex = new_counterexample (d1, d2, shift_reduce, true, false);
derivation_retain (d1);
derivation_retain (d2);
goto cex_search_end;
Expand Down Expand Up @@ -1149,7 +1163,7 @@ cex_search_end:;
// If a search state from Stage 3 is available, use it
// to construct a more compact nonunifying counterexample.
if (stage3result)
cex = complete_diverging_examples (stage3result, next_sym);
cex = complete_diverging_examples (stage3result, next_sym, shift_reduce);
// Otherwise, construct a nonunifying counterexample that
// begins from the start state using the shortest
// lookahead-sensitive path to the reduce item.
Expand Down Expand Up @@ -1226,6 +1240,8 @@ counterexample_report (state_item_number itm1, state_item_number itm2,
free_counterexample (cex);
}


// ITM1 denotes a shift, ITM2 a reduce.
static void
counterexample_report_shift_reduce (state_item_number itm1, state_item_number itm2,
symbol_number next_sym,
Expand Down
4 changes: 2 additions & 2 deletions tests/conflicts.at
Original file line number Diff line number Diff line change
Expand Up @@ -865,8 +865,8 @@ State 5
1 exp: exp OP exp .
1 exp: exp . OP exp
Example exp OP exp . OP exp
First derivation exp -> [ exp -> [ exp OP exp . ] OP exp ]
Second derivation exp -> [ exp OP exp -> [ exp . OP exp ] ]
Shift derivation exp -> [ exp OP exp -> [ exp . OP exp ] ]
Reduce derivation exp -> [ exp -> [ exp OP exp . ] OP exp ]

]])

Expand Down
Loading

0 comments on commit ba596de

Please sign in to comment.