在Bison中,如何为非终端指定左关联性?

时间:2014-05-16 06:40:35

标签: bison glr

我有以下Bison语法片段:

binary_op:         BINARY_OP
                    {
                        ...
                    }
                    | '|' %prec BINARY_OP
                    {
                        ...
                    }
;

non_keyword_expr:   non_keyword_expr binary_op non_keyword_expr %prec BINARY_SEND_PREC %dprec 2
                    {
                        ...
                    }
;

|在我的语法中有重载意义,因此我无法从我的词法分析器中将其作为标记BINARY_OP返回。根据具体情况,它可能是一个不同的标记。

如果我用它作为我的输入:

4 OR 5 OR 6

我可以成功解析它(词法分析器将OR识别为BINARY_OP标记)。

但是,如果我输入的是:

4 | 5 | 6

我得到了一个含糊不清的语法错误。 (|未被识别为左关联)

如何让 binary_op non_keyword_expr 中保持左关联? binary_op 的第二条规则上的%prec语句似乎没有效果。

编辑:这适用于GLR解析器

2 个答案:

答案 0 :(得分:1)

简单回答:你做不到。优先级(和关联性)仅适用于制作(左侧)和终端(右侧)。它们不适用于非终端。

这不是一个武断的决定;这是野牛处理转变/减少冲突的方式所固有的。在每个解析步骤中,先行令牌(终端)必须最终被移位,但是可能存在可以在终端移位之前减少的产生。如果不立即执行减少,则永远不会执行减少。 LR(1)语法允许解析器基于当前的解析堆栈和先行令牌来决定是否应该执行缩减或者是否应该立即移动先行令牌。如果两种行为都是可能的,那么语法就会产生转移/减少冲突,严格来说不是LR(1)。

优先级和关联性规则用于解决转移/减少冲突。生成可能具有隐式或显式优先级:显式优先级由%prec声明提供;否则使用生产中最后一个终端的优先顺序。在发生转移/减少冲突的情况下,可以减少的生产优先级与可以转移的先行终端的优先级相比较,并且具有更高优先级的胜利。而已。优先级不会保留或继承。事实上,比较优先级是不准确的,因为在解析期间不会发生这种情况;解析器有一个操作或转换表,它定义了在特定堆栈配置(“状态”)和先行标记的情况下要执行的操作,并且在解析器生成时使用优先级信息来填充操作表中的条目否则会含糊不清。

如果是你的作品

binary_op: '|' %prec BINARY_OP

%prec声明无用,因为binary_op必须立即减少;它无法参与转变/减少冲突。转移/减少冲突伴随着non_keyword_expression生产,其标记有(不同的)%prec声明,这是将用于该生产的声明。

non_keyword_expression的生产没有终端,因此它也没有隐含优先权。这通常不是你想要的,以及如下作品的使用:

binary_op: '|' | "OR" ;

与使用优先级解决解析冲突并不真正兼容。


注1:如果要求GLR解析器,则不完全正确。 GLR解析器可以执行shift和reduce,因为它(有效地)同时维护了许多解析器状态。最终,必须消除除这些状态之外的所有状态;否则,解析是模棱两可的。 GLR解析器使用优先级(和%prec声明)与非GLR解析器完全相同;通过优先级消除的解析器操作确实被消除,并且不会导致并行状态。但是,GLR解析器还可以处理减少/减少冲突,其中有两种可能的减少(可能是相同的非终端)。可以使用%dprec(“动态优先级”)声明来解决这些冲突。

答案 1 :(得分:1)

Bison的规则优先级通过在解决s / r冲突时将规则的优先级与所有冲突令牌的优先级进行比较来实现。因此,它将BINARY_SEND_PREC与' |'的优先级进行比较。和'或者'。对于' OR'它选择减少。为了减少' |'以及令牌' |'本身需要%left '|'。让他们一起工作' |'和'或者'需要相同的优先权。

如果您可以指定终端的关联性,则可以解决此类问题。或者'和' |'等,并将它们的优先级设置为相同。通过几次更改,中缀计算器示例可以解析输入,如下所示:

  

2加-3次4 ^ 2 + 3

     

-43

主要变化如下:

%token PLUS
%token TAKE
%left '-' '+' PLUS TAKE

... 

add:      '+' | PLUS;
exp:      NUM                           { $$ = $1;         }
        | exp add exp        %prec '+'  { $$ = $1 + $3;    }

非终端的优先权将是野牛恕我直言的有用扩展。当非终端的前缀可以被移位时,它将允许用户通过支持减少来修复s / r冲突(并且当可以为具有优先权的非终端移动时, - 可能有其他有效理由转移)。实际上我在尝试实现haskell样式函数应用程序语法后发现了这个问题,即

 x y z -> ((x y) z)

但由于单个终端本身也有效,因此将x / y / z减少到非终端是有效的。 Therfore bison将达到non-term_x non-term_y | z|是堆叠/超前边界)并且不知道是减少到non-term_x_y还是移动z。 (幸运的是,类似的技巧在这里起作用)

我在野牛源中稍微挖了一下,但是我无法看到一种在非终端上允许%prec的简单方法。当解决s / r conficts时,只知道缩减规则并且要移位冲突的令牌,其优先级将被比较。你需要知道所有有效的移动原因,并且有方法可以访问冲突的移位规则,所以可能......你需要将可移动的令牌分成与他们最终会减少的规则相对应的组,然后比较规则和#39;优先级。有一天我会看到......