Search code examples
bison

Bison resolving shift/reduce conflict when across rules


If one of my rules expand the same as part of the other rule, how would I mark precedence? For instance, I have expression IS type rule that should expand type as type DOT identifier recursively. But the in the same rule expression I have expression DOT identifier which bison reports as conflict. I would obviously want all DOTs within as expression's type part to reduce together into type and not as expression. Ie: a is b.c.d should parse as (a is b.c.d) where b.c.d is type and not (a is b).c.d. Here is minimal grammar that shows the conflict:

%require "3.0"
%defines

%define api.pure full
%define parse.trace

%token DOT '.'
%token IS "is"

%left DOT
%left IS

%%

example
    : expression
    ;
    
expression
    : expression DOT identifier
    | expression IS type
    | identifier
    ;
    
type
    : fqtypename
    ;

fqtypename
    : identifier
    | fqtypename DOT identifier
    ;

identifier: 
    "blah"
    ;

%%

and error:

State 10

5 type: fqtypename •
7 fqtypename: fqtypename • DOT identifier

DOT  shift, and go to state 12

DOT       [reduce using rule 5 (type)]
$default  reduce using rule 5 (type)

Solution

  • As you can see from the conflicted state, the conflict actually has nothing to do with the IS token. Rather, the conflict is between shifting DOT and reducing the production type: fqtypename, and you want that to resolve to shifting DOT.

    In fact, that's the default resolution without any precedence declarations. Bison, like Yacc, automatically resolves shift-reduce conflicts in favour of shifting, and reduce-reduce conflicts in favour of whichever production appears earlier in the grammar file. You can see that resolution in the state table you pasted (DOT is shifted in that state). Of course, that does leave you looking at a bison warning every time you generate your parser, which is not ideal. You can avoid the warning by using an %expect declaration, which basically tells Bison the number of shift-reduce conflicts that are expected to be resolved automatically. With recent Bison versions, you can attach the declaration to the production itself, which makes the expectation more precise. See the link to the Bison manual, which shows an example grammar somewhat similar to yours.

    With a bit more work, you can use precedence declarations to achieve the same effect, which has the advantage of being slightly more precise, at the cost of making the grammar a bit more mysterious. Here's an example based on the grammar in your question. Note that a %prec declaration is attached to the production which is actually involved in the conflict. Because that production has no terminal symbols at all, it was necessary to use a pseudo-token to represent the precedence level.

    /* I removed the token names for '.' and "is" to make the grammar shorter. */
    %left TYPE_UNIT
    %left '.'
    
    %%
    
    example
        : expression
        
    expression
        : expression '.' identifier
        | expression "is" type
        | identifier
        
    type
        : fqtypename             %prec TYPE_UNIT
    
    fqtypename
        : identifier
        | fqtypename '.' identifier
    
    identifier: 
        "blah"