ANTLR4 中奇怪的语义谓词行为,可能是一个错误

Weird Semantic Predicate Behaviour in ANTLR4, could be a Bug

这是我的 C 解析语法的一个工作子集。它只能解析如下所示的输入,但足以说明我的完整语法遇到的问题。请注意,它遵循传统方法来定义运算符优先级:

grammar CPPProcessor;
translation_unit:    expression;
primary_expression:
  '1'
  //|  {false}? '(' expression ')'
  | 'a'
  | 'b'

;
postfix_expression:
      primary_expression
    | postfix_expression '(' expression ')'

;

unary_expression:
      postfix_expression
    | '-' cast_expression
;
cast_expression:
      unary_expression
    | '(' 'a' ')' cast_expression
;
additive_expression:
      cast_expression
    | additive_expression '-' cast_expression
;
expression :  additive_expression;
WS: [ \t\f]+    -> channel(1);
CRLF: '\r'? '\n' -> channel(1);

调用规则是 translation_unit 并且输入是包含以下内容的单行:

(a)-b

注意 primary_expression 中的语义谓词已被注释掉。 (解释语法的方式是,当 primary_expression 的第二条规则启用时,输入被解析为减法。当子规则不存在时,它成为 -b 的 C 风格类型转换输入 a).

问题: 真正的问题是,我想有一个{false}?相当于什么都没有,因此删除注释应该没有区别。但是,当我删除评论时解析失败,即

primary_expression:
  '1'
  |  {false}? '(' expression ')'
  | 'a'
  | 'b'

;

并得到这个错误:

line 1:0 no viable alternative at input '('

为什么 {false}? 语义谓词会导致解析失败?这可能是 ANLTR4 中的错误吗?看起来 postfix_expression 中的第二个子规则导致了左递归问题。移除左递归后,问题消失

我想通了。

语义谓词不能导致上层规则回溯并尝试另一个子规则。因此,当 primary_expression 的第二个子规则未被注释时,它会公开另一个 '(' 匹配规则并允许选择 cast_expression 的第一个子规则作为输入。但是一旦做出此选择,它即使进一步子规则 return 中的某些语义谓词为 false,也无法撤消。语义谓词只能导致 primary_expression 的某些其他子规则被选中。但是由于 [= 中没有任何其他子规则10=] 可以匹配 '('。解析失败。