ANTLR不会自动进行超前匹配吗?

时间:2017-02-07 15:23:59

标签: parsing antlr antlr3

我目前正在编写一个简单的语法,需要在一个表达式中使用运算符优先级和混合关联性。示例表达式为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错误。

我测试时,termrest产品可以正常工作,所以我认为这是因为解析器被expr弄糊涂了。为了解决这个问题,我做了以下重构:

prog    :   expr EOF;
expr    :   term exprRest;
exprRest 
        :   '->' expr
        |   ;
term    :   ID rest;
rest    :   DU ID rest
        |   ;

这很好用。但是,由于这个重构,我现在需要检查输出解析树中的空exprRest个节点,这是非理想的。有没有办法让ANTLR解决expr初始声明中的含糊不清问题?我假设生成的解析器将完全匹配term,然后对"->"进行超前搜索并继续解析或返回孤独的term。我错过了什么?

1 个答案:

答案 0 :(得分:1)

如上所述,问题在于此规则:

expr    :   term '->' expr
        |   term;

有问题的部分是term,这两种选择都很常见。

  • LL(1)语法根本不允许这样做(除非term只匹配零令牌 - 但这样的规则没有意义),因为它无法决定哪个替代方案使用只能提前看到一个令牌( LL(1)中的 1 )。
  • LL(k)语法只有在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)决定。

这与你所得到的非常相似,但是解析树应该看起来非常像你想要的原始语法。