我目前正在编写一个简单的语法,需要在一个表达式中使用运算符优先级和混合关联性。示例表达式为a -> b ?> C ?> D -> e
,应解析为(a -> (((b ?> C) ?> D) -> e)
。也就是说,?>
运算符是一个高优先级的左关联运算符,而->
运算符是一个优先级较低的右关联运算符。
我正在使用ANTLR 3.5.1(通过ANTLRWorks 1.5.2)对语法进行原型设计,并发现它无法处理以下语法:
prog : expr EOF;
expr : term '->' expr
| term;
term : ID rest;
rest : '?>' ID rest
| ;
它产生rule expr has non-LL(*) decision due to recursive rule invocations reachable from alts 1,2
错误。
我测试时,term
和rest
产品可以正常工作,所以我认为这是因为解析器被expr
弄糊涂了。为了解决这个问题,我做了以下重构:
prog : expr EOF;
expr : term exprRest;
exprRest
: '->' expr
| ;
term : ID rest;
rest : DU ID rest
| ;
这很好用。但是,由于这个重构,我现在需要检查输出解析树中的空exprRest
个节点,这是非理想的。有没有办法让ANTLR解决expr
初始声明中的含糊不清问题?我假设生成的解析器将完全匹配term
,然后对"->"
进行超前搜索并继续解析或返回孤独的term
。我错过了什么?
答案 0 :(得分:1)
如上所述,问题在于此规则:
expr : term '->' expr
| term;
有问题的部分是term
,这两种选择都很常见。
term
只匹配零令牌 - 但这样的规则没有意义),因为它无法决定哪个替代方案使用只能提前看到一个令牌( LL(1)中的 1 )。term
规则最多匹配k - 1
令牌时才允许这样做。LL(*)语法,ANTLR 3.5使用它做了一些技巧,允许它处理匹配任意数量令牌的规则(ANTLR作者称之为"变量预见& #34;。)
然而,这些技巧无法处理的一件事是规则是递归的,即它是否以任何方式(直接或间接)引用自身引用本身 - 这正是你的{{1规则确实:
term
- 从term : ID rest;
rest : '?>' ID rest
| ;
引用的规则rest
以递归方式引用自身。因此,错误消息
由于递归规则调用,规则expr具有非LL(*)决策...
解决LL语法限制的方法称为左因子分析:
term
我在这里所做的是"匹配术语第一" (因为你想在两种选择中匹配它,在决定哪一个匹配它没有意义),然后决定是否匹配expr : term
( '->' expr )?
;
(这可以通过查看下一个来决定令牌 - 如果它是'->' expr
,请使用它 - 所以这甚至是 LL(1)决定。
这与你所得到的非常相似,但是解析树应该看起来非常像你想要的原始语法。