Resolve conflict in bison grammar with space separated expression lists + if/then/else

狂风中的少年 提交于 2019-11-29 18:07:10

As you can see from the bison report, the conflicts are with the terminals true and false, which are not listed in the precedence relations. Consequently, the precedence rules do not apply to these conflicts.

Recall that a precedence relation is defined between a production and a terminal. It does not relate two terminals nor two productions (and so cannot be used to resolve reduce-reduce conflicts). The comparison between precedence of the production which could be reduced and the lookahead terminal determines whether a reduce or a shift will occur. For notational convenience, productions are represented by the name of a terminal, usually the only terminal in the production; this corresponds to a common use case but it is sometimes confusing. In particular, the %prec declaration only serves to give a rule a name for use in precedence declarations, and it is probably better to think about it in that way rather than as an "explicit" declaration.

In short, the conflict in the simplified grammar in your question can be resolved by explicitly adding the appropriate terminals into the precedence relations:

%precedence "if"
%precedence "true" "false"

%%

Hungry
  : NoHungry
  | Hungry NoHungry
  | "if" Hungry "then" Hungry "else" Hungry %prec "if"

NoHungry
  : "true"
  | "false"

Excerpt from -v output:

State 12

    2 Hungry: Hungry . NoHungry
    3       | "if" Hungry "then" Hungry "else" Hungry .

    "true"   shift, and go to state 2
    "false"  shift, and go to state 3

    $default  reduce using rule 3 (Hungry)

    NoHungry  go to state 8

By using -r solved instead of -v, you can see the resolution more explicitly:

    Conflict between rule 3 and token "true" resolved as shift ("if" < "true").
    Conflict between rule 3 and token "false" resolved as shift ("if" < "false").

I could have used "else" as the name for the if production, which would have been the default without the %prec declaration, but "if" seems more intuitive.

The %precedence declaration (available in recent bison versions) does not imply either left or right associativity; in this case, associativity does not apply because there is no case in which a conflict involves a production and terminal of equal precedence. If Happy does not implement it, either %left or %right could be used for the same reason (associativity is irrelevant) but I think %precedence better documents the situation.

Since this is undoubtedly a reduced example, it's worth noting that a more complete grammar would require some grammar analysis. In particular, the list of terminals with precedence greater than "if" would have to include all terminals in FIRST(NoHungry), and bison does not provide an automatic tool to perform that computation, although you can usually extract the list from the shift-reduce conflict reports. (It could even be that "if" is part of the set, in which case associativity would matter.)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!