Parsing 为什么ANTLR4语法不明确?
我正在努力理解ANTLR4算法以及它如何处理左递归。希望有人能教育我一点 以左下角的递归语法为例:Parsing 为什么ANTLR4语法不明确?,parsing,antlr,antlr4,ambiguity,Parsing,Antlr,Antlr4,Ambiguity,我正在努力理解ANTLR4算法以及它如何处理左递归。希望有人能教育我一点 以左下角的递归语法为例: grammar Dummy; TOK1 : 'foo'; TOKE_OPT : 'bar'; TOK2 : 'baz'; TOKDERP : 'derp'; SPACES : [ \u000B\t\r\n] -> channel(HIDDEN) ; rr : rr TOK1 rr TOKE_OPT? | '(' TOK2 ')' | TOKDERP
grammar Dummy;
TOK1 : 'foo';
TOKE_OPT : 'bar';
TOK2 : 'baz';
TOKDERP : 'derp';
SPACES
: [ \u000B\t\r\n] -> channel(HIDDEN)
;
rr
: rr TOK1 rr TOKE_OPT?
| '(' TOK2 ')'
| TOKDERP
;
和以下输入字符串:
derp foo derp foo derp
当运行TestRig-diagnostics
ANTLR时,得出语法不明确的结论,我不明白为什么:
line 1:5 reportAttemptingFullContext d=2 (rr), input='foo'
line 1:9 reportContextSensitivity d=2 (rr), input='foo derp'
line 1:14 reportAttemptingFullContext d=2 (rr), input='foo'
line 2:0 reportAmbiguity d=2 (rr): ambigAlts={1, 2}, input='foo derp
'
如果有人能解释为什么这个语法是歧义的,以及如何消除歧义,我们将不胜感激。也有可能我不明白为什么歧义的意思是:)
如果我删除TOKE_OPT?
子句,警告就会消失
我使用的是ANTLR版本
4.7.2
,该语法实际上是不明确的,因为该语法允许对derp foo derp foo derp
进行两种解释:
(rr (rr (rr derp) foo (rr derp)) foo (rr derp))
(rr (rr derp) foo (rr (rr derp) foo (rr derp)))
(就我个人而言,我认为,如果您只使用看似合理的运算符和操作数标记,而不是从表达式中抽象出来,那么整个问题将更容易理解。但我离题了。)
Antlr4是一种LL解析器,它不能真正处理左递归。它通过将左递归规则转换为简单的等价形式,有效地改变了:
rule: base
| rule more
;
进入
但这并不足以处理左递归规则的典型情况,即代数表达式。这里,典型的语法可能是:
expr: expr '*' expr
| expr '+' expr
| atom
;
其意图是:
expr: atom ('*' atom)* ('+' ('*' atom)*)*
但这是一个复杂的转换,不能很好地推广,所以Antlr真正做的是在每个规则中引入谓词,以强制运算符优先顺序。使用这些谓词,语法变得明确,并且(通常)符合关于表达式语法应该如何解析的预期
但是,只有在没有“隐藏”的左递归或右递归的情况下,Antlr才能正确地获取优先谓词。(“Hidden right recursion”并不意味着递归是隐藏的。隐藏的是递归发生在规则末尾的事实。)特别是,在规则末尾放置一个可选标记隐藏了一个事实,即可选标记前面的非终端可能是右递归的,因此,Antlr4不会试图用优先谓词消除规则的歧义。这使得语法模棱两可
您可以通过避免隐藏右侧递归来解决此问题:
rr
: rr TOK1 rr TOKE_OPT
| rr TOK1 rr
| '(' TOK2 ')'
| TOKDERP
;
现在,正确的递归规则是明确的,而另一个规则(以TOKE_OPT
结尾)并不含糊。(或者至少不会以同样的方式模棱两可。)
有关Antlr4用于重写规则的算法的更精确描述,请参见附录末尾。我也不太明白。当我从您的示例中删除“TOKE_OPT”时,它将不再能够解析您的输入字符串,除非我将其设置为
rr(TOK1-rr)
@Daniel:您是指在输入“”时没有可行的替代方法
错误吗?这是一个长期存在的问题的结果,可以通过添加开始符号来解决。感谢您详尽的回复。对抽象标记表示抱歉,尽管看起来像,但该语法并非来自泛型表达式/运算符用例。@dkfso:当然,还有其他用例。我得到了抽象的论点;只是所有的德普在黑暗中看起来都一样。
rr
: rr TOK1 rr TOKE_OPT
| rr TOK1 rr
| '(' TOK2 ')'
| TOKDERP
;