parsing - ANTLR 不会自动进行前向匹配?

标签 parsing antlr antlr3

我目前正在编写一种简单的语法,需要在一个表达式中使用运算符优先级和混合关联性。示例表达式为 a -> b ?> C ?> D -> e,应将其解析为 (a -> (((b ?> C) ?> D) -> e)。也就是说,?> 运算符是高优先级左结合运算符,而 -> 运算符是低优先级右结合运算符-结合运算符。

我正在 ANTLR 3.5.1 中对语法进行原型(prototype)设计(通过 ANTLRWorks 1.5.2),发现它无法处理以下语法:

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

由于可从 alts 1,2 到达的递归规则调用,它会产生rule expr has non-LL(*) Decision 错误。

当我测试时,termrest 产生式单独工作得很好,所以我认为发生这种情况是因为解析器被 expr 搞糊涂了>。为了解决这个问题,我进行了以下重构:

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

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

最佳答案

如上所述,问题出在这条规则中:

expr    :   term '->' expr
        |   term;

有问题的部分是两个替代方案所共有的术语

  • LL(1) 语法根本不允许这样做(除非 term 只匹配零个标记 - 但这样的规则毫无意义),因为它无法决定哪个另一种只能看到前面一个标记的情况(即 LL(1) 中的 1)。
  • LL(k) 语法仅在 term 规则最多匹配 k - 1 个标记时才允许这样做。
  • ANTLR 3.5 使用的
  • LL(*) 语法做了一些技巧,使其能够处理与任意数量的标记匹配的规则(ANTLR 作者将此称为“变量前瞻”)。

    • 但是,这些技巧无法处理的一件事是规则是否是递归的,即如果它或任何规则以任何方式(直接或间接)调用引用本身 - 而这正是您的 term 规则的作用是:

      term    :   ID rest;
      rest    :   '?>' ID rest
              |   ;
      

      - 从 term 引用的规则 rest 递归地引用自身。因此,错误消息

      rule expr has non-LL(*) decision due to recursive rule invocations ...


解决 LL 语法这一限制的方法称为左分解:

expr    :   term 
            ( '->' expr )?
        ;

我在这里所做的是“首先匹配术语”(因为你想在两种选择中匹配它,所以没有必要决定匹配哪一个),然后决定是否匹配 '->' expr (这可以通过查看下一个标记来决定 - 如果它是 ->,则使用它 - 所以这甚至是 LL(1) 决策)。

这也与您所得到的非常相似,但是解析树应该看起来非常像您对原始语法的预期。

关于parsing - ANTLR 不会自动进行前向匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42093553/

相关文章:

antlr - 替换 ANTLR 中的 token

linux - 用于 Linux 和 Windows 的 Antlr3 中的解析问题

java - 使用 PDFBox 解析 PDF 文件(尤其是表格)

java - 如何获取antlr解析的错误信息?

error-handling - 强制antlr3在规则失败时立即退出

java - 在 ANTLR 文法中定义关键字

java - 使用流/对象方法将 JSON 解析为 Jackson

regex - 无法在 perl6 中编写语法来解析带有特殊字符的行

parsing - 帮助解析日志文件 (ANTLR3)

antlr - 如何使用 ANTLR 重写具有复合根的子树?