在Bison中,如何为非终端保留specity左结合性?

在Bison中,如何为非终端保留specity左结合性?,bison,glr,Bison,Glr,我有以下Bison语法片段: binary_op: BINARY_OP { ... } | '|' %prec BINARY_OP { ... } ; non_keyword_expr:

我有以下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 { ... } ; 我可以成功地解析它(或者被lexer识别为二进制_OP标记)

但是,如果我的输入是:

4 | 5 | 6
我犯了一个模棱两可的语法错误。(未将
|
识别为左关联)

如何使二进制运算在非关键字表达式中保持关联?二进制运算的第二条规则上的
%prec
语句似乎没有效果


编辑:这是针对GLR解析器的

简单回答:您不能。优先级(和关联性)仅适用于产品(左侧)和端子(右侧)。它们不适用于非端子

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

优先级和关联性规则用于解决移位/减少冲突。产品可能具有隐式或显式优先级:显式优先级由
%prec
声明提供;否则,将使用生产中最后一个终端的优先级。在发生移位/减少冲突的情况下,可减少的生产优先级与可移位的先行终端的优先级进行比较,以优先级较高的为准。就这样。优先级不会被保留或继承。事实上,比较先例是不准确的,因为在解析过程中不会发生这种情况;解析器有一个action或transition表,它定义了在特定堆栈配置(“state”)和lookahead令牌的情况下要做什么,并且在解析器生成时使用优先级信息来填充action表中的条目,否则这些条目将是不明确的

就你的产品而言

binary_op: '|' %prec BINARY_OP
%prec
声明是无用的,因为必须立即减少
二进制运算
;它不能参与转换/减少冲突。shift/reduce冲突与
非\u关键字\u表达式
生产一起出现,该表达式用(不同的)
%prec
声明标记,该声明将用于该生产

非_关键字_表达式
的结果没有终端,因此也没有隐式优先级。这通常不是您想要的,而产品的使用类似于:

binary_op: '|' | "OR" ;
与使用优先级解决解析冲突并不真正兼容



注1:如果您要求使用GLR解析器,则这并非完全正确。GLR解析器可以同时执行移位和缩减,因为它(有效地)同时维护多个解析器状态。最终,除一个国家外,所有这些国家都必须被消灭;否则,解析是不明确的。GLR解析器使用优先级(和
%prec
声明)的方式与非GLR解析器完全相同;由优先级消除的解析器操作实际上被消除,并且不会导致并行状态。然而,GLR解析器也可以处理reduce/reduce冲突,其中有两种可能的reduce(可能到同一个非终端)。可以使用
%dprec
(“动态优先级”)声明来解决这些冲突。

解决s/r冲突时,Bison规则的优先级通过将规则的优先级与要移位的所有冲突标记的优先级进行比较来工作。因此,它将二进制_SEND_PREC与“|”和“OR”的优先级进行比较。对于“或”,它选择了reduce。要获得“|”的reduce以及标记“|”本身,需要
%left'|'
。要让它们一起工作,“|”和“或”需要相同的优先级

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

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

... 

add:      '+' | PLUS;
exp:      NUM                           { $$ = $1;         }
        | exp add exp        %prec '+'  { $$ = $1 + $3;    }
2加-3乘以4^2+3

-43

主要变化如下所示:

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

... 

add:      '+' | PLUS;
exp:      NUM                           { $$ = $1;         }
        | exp add exp        %prec '+'  { $$ = $1 + $3;    }
非终端的优先级将是bison IMHO的有用扩展。它将允许用户在非终端的a前缀可以移动时(并且只有当它可以为具有优先权的非终端移动时,才可能有其他有效的移动原因),通过支持减少来修复s/r冲突。事实上,我在尝试实现haskell风格的函数应用程序语法ie之后发现了这个问题

 x y z -> ((x y) z)
但是,由于单个端子在这里也是有效的,因此将x/y/z减少为非端子是有效的。因此,野牛会到达
非长期×非长期| z
|
是堆栈/前瞻边界)并且不知道是减少到
非长期(ux|y
还是移动z。(幸运的是,类似的技巧在这里也能奏效)

我在bison源代码中搜索了一些,但是我找不到一个简单的方法来允许在非终端上使用%prec。当s/r冲突得到解决时,只有还原规则已知,冲突的令牌将被转移,并对其先例进行比较。您需要知道这里所有有效的移位原因,并且有一些方法可以访问冲突移位规则,所以。。您需要将可移位标记划分为与它们最终将减少的规则相对应的组,然后比较规则的先例。我要找个地方看看