以下语法(其中INTEGER是数字序列)引起减少/减少冲突,因为例如-4可以通过expr减少 - > -expr或expr - > num - > -整数。在我的语法中,num和expr返回不同的类型,因此我必须区分-num和-expr。我的目标是-5减少数量,例如 - (...)是一个expr。我怎么能做到这一点?
%token INTEGER
%left '+' '-'
%%
start: expr
;
expr: expr '+' expr
| expr '-' expr
| '-' expr
| '(' expr ')'
| num
;
num: INTEGER
| '-' INTEGER
;
%%
答案 0 :(得分:2)
对于这种特定情况,您可以将否定表达式的规则更改为
expr: '-' '(' expr ')'
并且只识别带括号的表达式的否定。然而,这不会识别双重否定(例如- - x
),更重要的是,如果您尝试添加其他一元运算符,它将无法缩放。
现在您可以简单地在num
规则之前放置expr
规则,并允许默认的reduce / reduce冲突解决方案来处理它(如果两者都是,则将使用文件中出现的第一个规则可能),但这有点难看,因为你每次跑野牛都会得到这些冲突警告,当你不确切知道发生了什么事情时忽略它们是一个坏主意。
解决这种歧义的一般方法是将语法分解为将违规规则分成两个规则,并在每个上下文中使用适当的版本,这样就不会产生冲突。在这种情况下,对于以expr
开头的表达式和其他表达式的num_expr
,您将num
拆分为non_num_expr
:
expr: num_expr | non_num_expr ;
num_expr: num_expr '+' expr
| num_expr '-' expr
| num
;
non_num_expr: non_num_expr '+' expr
| non_num_expr '-' expr
| '-' non_num_expr
| '(' expr ')'
;
基本上,expr
的每个以RHS上的expr
开头的规则都需要重复,expr
的其他用法可能需要更改为其中一个变体,因此为了避免冲突。
不幸的是,在这种情况下,它不能干净利落,因为您使用优先级来解决表达式语法的固有歧义,并且因素规则妨碍了这一点 - 额外的一步规则导致问题。因此,您需要将这些规则排除在外(在RHS上使用expr
复制每个规则 - 一个使用num_expr
版本,另一个使用non_num_version
或者您需要重构具有优先级/关联性的额外规则的语法
expr: expr '+' term
| expr '-' term
| term
;
term: non_num_term | num_term ;
non_num_term: '-' non_num_term
| '(' expr ')'
;
num_term: num ;
请注意,在这种情况下,num / non_num分解已在term
而不是expr
上完成
答案 1 :(得分:0)
您不清楚为什么num
需要代表负数。我不知道你是否在语法的其他地方使用num
。您也没有说明为什么您希望num
和expr
不同。
通常,负数在lexer级别处理。在您的情况下,规则将类似于-?[0-9]+
。这样就完全不需要num
,并产生以下结果:
expr: expr '+' expr
| expr '-' expr
| '-' expr
| '(' expr ')'
| INTEGER
;
编辑: Chris Dodd有一点意见。因此,您需要将完全移动到解析器中。你仍然摆脱num
,只是不测试INTEGER
词法模式中的否定(即模式类似于[0-9]+
,这就是你现在正在做的事情,对?)。我上面给出的expr
规则不会改变。
-5
)解析为:'-' INTEGER
,变为'-' expr
(选择5),然后expr
(选择3)。3-2
)解析为INTEGER '-' INTEGER
,变为expr - expr
(选择5两次),然后expr
(选择2)。5--1
)之间的差异解析为INTEGER '-' '-' INTEGER
,变为expr '-' '-' expr
(选择5两次),然后expr '-' expr
(选择3) ,然后expr
(选择2)。等等。根本问题是你在两个不同的地方有否定,并且没有办法不会模棱两可。