消除与点表达式和数组的移位/减少冲突

时间:2018-09-27 17:51:56

标签: bison yacc

对不起,我是野牛新手。我不了解问题以及如何解决。如果您能在指出问题和解决方案的同时“教我如何钓鱼”,我将不胜感激。

%left '.' '+'
%right '(' '['

%%
 OptionalExpressions
  : { $$ = nullptr; }
  | Expressions
  ;

Expressions
  : Expression
  | Expressions ',' Expression
  ;

Expression
  : Expression '+' Expression
  | ExpressionDot
  | TOKEN_ADDROF Expression
  | ExpressionIndexable
  | ExpressionFunctionCall
  | TOKEN_INTEGER
  | TOKEN_IDENTIFIER
  | '(' Expression ')'
  ;

ExpressionDot
  : Expression '.' Expression
  ;

ExpressionIndexable
  : Expression '[' Expression ']'
  ;

ExpressionFunctionCall
  : Expression '(' OptionalExpressions ')'
  ;
%%

谢谢。

1 个答案:

答案 0 :(得分:2)

在进行下一次钓鱼探险之前,您应该仔细阅读using precedence declarations上的《野牛手册》中的部分,以及其中的一些related SO answers。 Bison手册还提供了一些very useful information,用于了解冲突以及Bison提供的可帮助您的工具。在这里,我基本上遵循上一个链接中描述的过程。

第一步是要求Bison生成解析器状态的报告,只需要给它提供-v选项(或者如果需要更多信息就可以使用--report=all,这有时是有用的)。生成的.output文件中的第一行告诉您哪些状态具有平移/减少冲突:

State 12 conflicts: 4 shift/reduce

因此,下一步是查看状态12。冲突由括号中的解析器操作指示;请参见表12。我加粗了它们以使其更明显。 (括号内的动作是使用默认解析算法消除野牛的行为,该手册中也有介绍。)


    State 12

        5 Expression: Expression . '+' Expression
        7           | TOKEN_ADDROF Expression .
       13 ExpressionDot: Expression . '.' Expression
       14 ExpressionIndexable: Expression . '[' Expression ']'
       15 ExpressionFunctionCall: Expression . '(' OptionalExpressions ')'

        '.'  shift, and go to state 15
        '+'  shift, and go to state 16
        '('  shift, and go to state 17
        '['  shift, and go to state 18

        '.'       [reduce using rule 7 (Expression)]
        '+'       [reduce using rule 7 (Expression)]
        '('       [reduce using rule 7 (Expression)]
        '['       [reduce using rule 7 (Expression)]
        $default  reduce using rule 7 (Expression)

因此,在这种状态下,野牛无法应用任何优先级规则来决定在规则7的减少适用的情况下该怎么做。报告中方便地复制了规则7:

    7           | TOKEN_ADDROF Expression .

该规则的优先级将是TOKEN_ADDROF终端的优先级。但是没有定义该优先级,因为TOKEN_ADDROF没有出现在任何优先级中。

我们可以尝试添加它:

%left '.' '+'
%precedence TOKEN_ADDROF
%precedence '(' '['

然后,嘿!

问一下为什么将它放在我放置的位置,以及为什么对它和其他一元运算符使用%precedence而不是%left%right会很公平

从第二个问题开始,%precedence的意思是“该优先级涉及无法通过关联性解决冲突的运算符,因此我将不声明任何特定的关联性。”

在这种情况下是正确的:一元运算符没有关联性。 3-4-7中的-可以与左侧((3-4)-7))或右侧(3-(4-7))关联。将基于优先级为Expression-)的Expression: Expression '-' Expression产生和优先级为--)的超前标记来进行解析。那显然会发生。相比之下,考虑一下TOKEN_ADDROF运算符(顺便说一下,它不是吗?如果是的话,只需将其写为字符标记即可。)已经看到的是

Expression: TOKEN_ADDROF Expression

现在,如果超前标记是TOKEN_ADDROF,该怎么办?答案:这是语法错误,因为TOKEN_ADDROF不是二进制运算符,因此它不能跟随表达式。 (可能是您有一个具有相同拼写的二进制运算符。但是在那种情况下,您应该在上面的代码中放%prec UNOP,然后就不可能将超前标记设为{{1 }},因为该词法不会由词法扫描程序产生。)因此,没有产生允许移位的产生,因此也没有冲突。

类似的推理也适用于后缀运算符,例如函数应用程序和下标。 (以及后递增和后递减(如果适用)。)在那些情况下,可以使用以下后缀运算符,但是在减少UNOP产量之前,不能对其进行移位。再次,没有可能的冲突。

因此,对于后缀运算符,唯一的优先级比较将是之间级别,而不是级别,并且不适用关联性。如果您不小心以允许关联的方式错误输入了语法(例如,未能在必要的地方插入Expression POSTFIX声明),而不是默默地忽略了错误,则未指定关联性将导致野牛生成冲突警告。

在此特定语法中,不需要将%prec UNOP'['放在优先级中,因为这些标记不会在任何'('生成中直接使用。这意味着语法为这些运算符提供了显式优先级。在同一语法中同时使用优先级声明和显式优先级通常表示该语法的各个部分已从不同来源进行复制和粘贴。 (只是说说吧。)尽管有时它是合理的,但通常不被认为是好的风格。在这种情况下,建议使用显式或显式声明的优先级。

因此,让我们假设需要声明优先级。在那种情况下,为什么我将后缀运算符放在最后?答案:因为后缀操作比前缀操作更紧密地绑定是一般准则(尽管不是绝对规则)。例如,Expression不是 意思是-arr[i]。显然,大多数人都没有考虑到这一点,尽管有时他们无法将规则应用于具有完全相同的优先级关系的(-arr)[i]*arr[i]

希望有帮助。