Bison 野牛:奇怪的转变减少冲突

Bison 野牛:奇怪的转变减少冲突,bison,operator-precedence,Bison,Operator Precedence,我尝试用自定义语法(加上类似的数组访问操作符)实现函数调用: 以下是我所有的操作员案例: %right ASSIGN ASSIGN_MOD ASSIGN_XOR ASSIGN_AND ASSIGN_STAR ASSIGN_MINUS ASSIGN_PLUS ASSIGN_OR ASSIGN_DIV ASSIGN_LSHIFT ASSIGN_RSHIFT %right QUESTION COLON %left OR %left AND %left BIN_OR %left XOR %left BI

我尝试用自定义语法(加上类似的数组访问操作符)实现函数调用:

以下是我所有的操作员案例:

%right ASSIGN ASSIGN_MOD ASSIGN_XOR ASSIGN_AND ASSIGN_STAR ASSIGN_MINUS ASSIGN_PLUS ASSIGN_OR ASSIGN_DIV ASSIGN_LSHIFT ASSIGN_RSHIFT
%right QUESTION COLON
%left OR
%left AND
%left BIN_OR
%left XOR
%left BIN_AND
%left NOT_EQUALS NOT_SAME EQUALS SAME
%left LESS LESS_EQUALS MORE MORE_EQUALS
%left LSHIFT RSHIFT
%left PLUS MINUS
%left PERCENT STAR SLASH
%right TILDE NOT DECREASE INCREASE
%left DOT
请注意,圆点的优先级最高。所以,我试着把它赋予我的函数调用规则。尽管如此,我还是收到了74条shift/reduce警告,它们都遵循以下模式:

State 25
15 expression: expression . PLUS expression
16           | expression . MINUS expression
17           | expression . NOT_EQUALS expression
18           | expression . NOT_SAME expression
19           | expression . PERCENT expression
20           | expression . ASSIGN_MOD expression
21           | expression . XOR expression
22           | expression . ASSIGN_XOR expression
23           | expression . BIN_AND expression
24           | expression . AND expression
25           | expression . ASSIGN_AND expression
26           | expression . STAR expression
27           | expression . ASSIGN_STAR expression
28           | expression . ASSIGN_MINUS expression
29           | expression . ASSIGN expression
30           | expression . EQUALS expression
31           | expression . SAME expression
32           | expression . ASSIGN_PLUS expression
33           | expression . BIN_OR expression
34           | expression . OR expression
35           | expression . ASSIGN_OR expression
36           | expression . SLASH expression
37           | expression . ASSIGN_DIV expression
38           | expression . DOT expression
39           | expression . LESS expression
40           | expression . LESS_EQUALS expression
41           | expression . LSHIFT expression
42           | expression . ASSIGN_LSHIFT expression
43           | expression . MORE expression
44           | expression . MORE_EQUALS expression
45           | expression . RSHIFT expression
46           | expression . ASSIGN_RSHIFT expression
48           | expression . PARENTHESIS_OPEN expressions PARENTHESIS_CLOSE
49           | expression . SQUARE_OPEN expressions SQUARE_CLOSE
53           | DECREASE expression .
55           | expression . DECREASE
56           | expression . INCREASE

PARENTHESIS_OPEN  shift, and go to state 46
DECREASE          shift, and go to state 47
INCREASE          shift, and go to state 52
SQUARE_OPEN       shift, and go to state 54
DOT               shift, and go to state 61

PARENTHESIS_OPEN  [reduce using rule 53 (expression)]
SQUARE_OPEN       [reduce using rule 53 (expression)]
$default          reduce using rule 53 (expression)
46号州,冲突转移表明,如下所示:

State 46

48 expression: expression PARENTHESIS_OPEN . expressions PARENTHESIS_CLOSE

MINUS             shift, and go to state 5
TILDE             shift, and go to state 6
NOT               shift, and go to state 7
PARENTHESIS_OPEN  shift, and go to state 8
DECREASE          shift, and go to state 9
INCREASE          shift, and go to state 10
INT               shift, and go to state 11
FLOAT             shift, and go to state 12
STRING            shift, and go to state 13
CHAR              shift, and go to state 14
ID                shift, and go to state 15

$default  reduce using rule 59 (expressions)

expression   go to state 87
expressions  go to state 88
我真的不明白为什么野牛选择减少。因为我给了函数调用规则最高的优先级,所以bison应该尝试移位,直到它与该规则匹配为止。尽管如此,前缀DECREASE操作符看起来像是bison的选择,即使它的优先级较低


为什么野牛会这样?我怎样才能清楚地告诉bison函数调用规则应该具有更高的优先级,从而避免冲突?

以下引用自:

回想一下,生产和终端之间定义了优先关系。它不涉及两个终端或两个产品(因此不能用于解决冲突)。可以减少的生产优先级与前瞻终端之间的比较确定是减少还是转移

%prec
声明(re-)定义了它所属的缩减的优先级。就你而言

| expression PARENTHESIS_OPEN expressions PARENTHESIS_CLOSE   {  }     %prec DOT
| expression SQUARE_OPEN expressions SQUARE_CLOSE      {  }          %prec DOT
声明这两种缩减的优先级均为
,而不是
括号
正方形
[注1]。由于后两个标记没有出现在
%left/%right
声明中,因此这实际上是一个优先级定义,但由于两个原因它是不必要的:

  • 您可以将括号和正方形添加到适当的优先级,但更重要的是

  • 这两种减少不参与任何转移/减少冲突

  • 您应该尝试理解(并希望同意)我在第(2)项中的主张。作为一个开始的地方,考虑你在你的问题中包含的状态25。在状态25中,唯一可能的减少是根据规则53(
    表达式:减少表达式
    )。您可以看到这一点,因为这是状态中唯一在右侧边缘有
    的项。只有右边缘有点的项目才能减少(因为右边缘的点表示该项目对应的生产在此状态下可能已完成)。实际上,您可以看到针对该状态报告的移位/减少冲突:

    PARENTHESIS_OPEN  shift, and go to state 46
    PARENTHESIS_OPEN  [reduce using rule 53 (expression)]
    
    SQUARE_OPEN       shift, and go to state 54
    SQUARE_OPEN       [reduce using rule 53 (expression)]
    
    这两种冲突都涉及使用规则53进行可能的减少

    因此,在状态25中,如果a(是先行字符,语法将允许

    • ()的移位,导致项的状态为
      表达式:表达式括号\u打开。表达式括号\u关闭
      (请注意点是如何移动到
      括号\u打开
      标记上的)

    • 或者规则的缩减
      表达式:缩减表达式

    Bison通过比较缩减的优先级(
    reduce
    )和前瞻标记的优先级(
    圆括号_OPEN
    )来解决此冲突。
    圆括号_OPEN
    没有出现在任何优先级中,因此Bison返回其默认值,即更喜欢移位

    显然,更改缩减
    表达式:表达式括号\u开放表达式括号\u关闭
    的优先级不会影响此冲突的解决,因为该缩减与此冲突无关

    现在,我的主张是,这种减少与语法中的任何冲突无关。这可能看起来有点奇怪,因为我看不到语法的大部分内容,事实上我可能是错的。理论上,表中可能还有其他一些状态,包括该项:

    expression: expression PARENTHESIS_OPEN expressions PARENTHESIS_CLOSE .
    
    还包括一些可能发生转移的项目,例如

    some_non_terminal: expression PARENTHESIS_OPEN expressions PARENTHESIS_CLOSE . something
    
    我觉得这不太可能

    通常,后缀运算符减少(函数调用和数组索引在概念上是后缀运算符)永远不要参与移位减少冲突,因为后缀运算符之后几乎没有可能的移位。如果有这样的移位,运算符将是中缀,而不是后缀。你可以想象这样一种语法,其中运算符符号可以是中缀运算符和后缀运算符,类似于-which could可以是中缀或前缀。但事实证明,由于超出本答案范围的原因,情况并不对称。[注2]

    回到原来的问题:我们已经看到移位/减少冲突发生在reduce
    表达式:reduce expression
    之间(在本例中)以及端子
    圆括号(OPEN)
    方括号(OPEN)
    方括号(OPEN)
    未列在您的优先级中,因此解决方案是列出它们:

    /* ... */
    %left PERCENT STAR SLASH
    %precedence TILDE NOT DECREASE INCREASE
    %precedence PARENTHESIS_OPEN SQUARE_OPEN
    
    请注意,我将最后一个
    %left
    %right
    更改为
    %preference
    ,这是一个bison扩展,允许您为关联性没有意义的运算符定义优先级。我这样做是因为我认为它更清晰。[注3]

    笔记
  • 使用括号(OPEN)()比使用更简单、更易读的()好得多。Yacc和bison允许单字符标记像那样单引号引用,以确保代码的可读性

    expression:  expression '(' expressions ')'
    expression:  expression '[' expressions ']'
    
    这也简化了(f)lex扫描器,因为单个回退规则可以处理所有四个标记和所有其他单字符标记,包括尚未添加到语法中的标记:

          /* Put this rule at the end of your ruleset */ 
    .    { return *yytext;}
    
  • 例如,假设可以是后缀或中缀,并考虑

          /* Put this rule at the end of your ruleset */ 
    .    { return *yytext;}