allow %expect and %expect-rr modifiers on individual rules

This change allows one to document (and check) which rules participate
in shift/reduce and reduce/reduce conflicts.  This is particularly
important GLR parsers, where conflicts are a normal occurrence.  For
example,

    %glr-parser
    %expect 1
    %%

    ...

    argument_list:
      arguments %expect 1
    | arguments ','
    | %empty
    ;

    arguments:
      expression
    | argument_list ',' expression
    ;

    ...

Looking at the output from -v, one can see that the shift-reduce
conflict here is due to the fact that the parser does not know whether
to reduce arguments to argument_list until it sees the token AFTER the
following ','.  By marking the rule with %expect 1 (because there is a
conflict in one state), we document the source of the 1 overall shift-
reduce conflict.

In GLR parsers, we can use %expect-rr in a rule for reduce/reduce
conflicts.  In this case, we mark each of the conflicting rules.  For
example,

    %glr-parser
    %expect-rr 1

    %%

    stmt:
      target_list '=' expr ';'
    | expr_list ';'
    ;

    target_list:
      target
    | target ',' target_list
    ;

    target:
      ID %expect-rr 1
    ;

    expr_list:
      expr
    | expr ',' expr_list
    ;

    expr:
      ID %expect-rr 1
    | ...
    ;

In a statement such as

    x, y = 3, 4;

the parser must reduce x to a target or an expr, but does not know
which until it sees the '='.  So we notate the two possible reductions
to indicate that each conflicts in one rule.

See https://lists.gnu.org/archive/html/bison-patches/2013-02/msg00105.html.

* doc/bison.texi (Suppressing Conflict Warnings): Document %expect,
%expect-rr in grammar rules.
* src/conflicts.c (count_state_rr_conflicts): Adjust comment.
(rule_has_state_sr_conflicts): New static function.
(count_rule_sr_conflicts): New static function.
(rule_nast_state_rr_conflicts): New static function.
(count_rule_rr_conflicts): New static function.
(rule_conflicts_print): New static function.
(conflicts_print): Also use rule_conflicts_print to report on individual
rules.
* src/gram.h (struct rule): Add new fields expected_sr_conflicts,
expected_rr_conflicts.
* src/reader.c (grammar_midrule_action): Transfer expected_sr_conflicts,
expected_rr_conflicts to new rule, and turn off in current_rule.
(grammar_current_rule_expect_sr): New function.
(grammar_current_rule_expect_rr): New function.
(packgram): Transfer expected_sr_conflicts, expected_rr_conflicts
to new rule.
* src/reader.h (grammar_current_rule_expect_sr): New function.
(grammar_current_rule_expect_rr): New function.
* src/symlist.c (symbol_list_sym_new): Initialize expected_sr_conflicts,
expected_rr_conflicts.
* src/symlist.h (struct symbol_list): Add new fields expected_sr_conflicts,
expected_rr_conflicts.
* tests/conflicts.at: Add tests "%expect in grammar rule not enough",
"%expect in grammar rule right.", "%expect in grammar rule too much."
This commit is contained in:
Paul Hilfinger
2013-02-26 16:28:36 -08:00
committed by Akim Demaille
parent 487a2a9eca
commit b34b12c4f9
9 changed files with 282 additions and 8 deletions

View File

@@ -5254,6 +5254,53 @@ in GLR parsers, using the declaration:
%expect-rr @var{n}
@end example
You may wish to be more specific in your
specification of expected conflicts. To this end, you can also attach
@code{%expect} and @code{%expect-rr} modifiers to individual rules.
The interpretation of these modifiers differs from their use as
declarations. When attached to rules, they indicate the number of states
in which the rule is involved in a conflict. You will need to consult the
output resulting from @samp{-v} to determine appropriate numbers to use.
For example, for the following grammar fragment, the first rule for
@code{empty_dims} appears in two states in which the @samp{[} token is a
lookahead. Having determined that, you can document this fact with an
@code{%expect} modifier as follows:
@example
dims:
empty_dims
| '[' expr ']' dims
;
empty_dims:
%empty %expect 2
| empty_dims '[' ']'
;
@end example
Mid-rule actions generate implicit rules that are also subject to conflicts
(@pxref{Midrule Conflicts,, Conflicts due to Midrule Actions}). To attach
an @code{%expect} or @code{%expect-rr} annotation to an implicit
mid-rule action's rule, put it before the action. For example,
@example
%glr-parser
%expect-rr 1
%%
clause:
"condition" %expect-rr 1 @{ value_mode(); @} '(' exprs ')'
| "condition" %expect-rr 1 @{ class_mode(); @} '(' types ')'
;
@end example
@noindent
Here, the appropriate mid-rule action will not be determined until after
the @samp{(} token is shifted. Thus,
the two actions will clash with each other, and we should expect one
reduce/reduce conflict for each.
In general, using @code{%expect} involves these steps:
@itemize @bullet
@@ -5269,8 +5316,17 @@ go back to the beginning.
@item
Add an @code{%expect} declaration, copying the number @var{n} from the
number which Bison printed. With GLR parsers, add an
number that Bison printed. With GLR parsers, add an
@code{%expect-rr} declaration as well.
@item
Optionally, count up the number of states in which one or more
conflicted reductions for particular rules appear and add these numbers
to the affected rules as @code{%expect-rr} or @code{%expect} modifiers
as appropriate. Rules that are in conflict appear in the output listing
surrounded by square brackets or, in the case of reduce/reduce conflicts,
as reductions having the same lookahead symbol as a square-bracketed
reduction in the same state.
@end itemize
Now Bison will report an error if you introduce an unexpected conflict,
@@ -5491,7 +5547,14 @@ Start-Symbol}).
@end deffn
@deffn {Directive} %expect
Declare the expected number of shift-reduce conflicts
Declare the expected number of shift-reduce conflicts, either overall or
for a given rule
(@pxref{Expect Decl, ,Suppressing Conflict Warnings}).
@end deffn
@deffn {Directive} %expect-rr
Declare the expected number of reduce-reduce conflicts, either overall or
for a given rule
(@pxref{Expect Decl, ,Suppressing Conflict Warnings}).
@end deffn