【问题标题】:ANTLR lexer can't lookahead at allANTLR 词法分析器根本无法向前看
【发布时间】:2012-08-30 05:38:54
【问题描述】:

我的语法如下:

rule: 'aaa' | 'a' 'a';

它可以成功解析字符串'aaa',但它无法解析'aa'并出现以下错误:

line 1:2 mismatched character '<EOF>' expecting 'a'

仅供参考,这是词法分析器的问题,而不是解析器的问题,因为我什至不调用解析器。主要功能如下:

@members {
  public static void main(String[] args) throws Exception {
    RecipeLexer lexer = new RecipeLexer(new ANTLRInputStream(System.in));
    for (Token t = lexer.nextToken(); t.getType() != EOF; t = lexer.nextToken())
      System.out.println(t.getType());
  }
}

结果与更明显的版本相同:

rule: AAA | A A;
AAA: 'aaa';
A: 'a';

显然,ANTLR 词法分析器尝试将输入“aa”与失败的规则 AAA 匹配。除了 ANTLR 是一个 LL(*) 解析器或其他什么之外,词法分析器应该与解析器分开工作,它应该能够解决歧义。该语法适用于旧的 lex(或 flex),但它似乎不适用于 ANTLR。那么这里的问题是什么?

感谢您的帮助!

【问题讨论】:

  • 词法分析器中的标记是如何定义的?在我看来,词法分析器更喜欢匹配 a 而不是 aaa 给定一个 a 作为输入。
  • @Dervall 令牌文件看起来像:A=4 AAA=5 它更喜欢aaa 而不是a。它可以解析aaaa 但不能解析aa
  • @AustinHenley:是的,从某种意义上说,当有多种选择时它更喜欢较长的令牌,这是贪婪的。但是对于输入“aa”,“aaa”甚至不是一个可能的选择。
  • 查看这个非常详细但易于关注的页面:wincent.com/wiki/ANTLR_lexers_in_depth。它对我理解 ANTLR Lexer 的怪癖有很大帮助。尤其是“.+ 和 .* 默认为非贪婪行为”非常令人惊讶!

标签: antlr lex antlr3 lexer


【解决方案1】:

ANTLR 生成的解析器是(或可以是)LL(*),而不是它的词法分析器。

当词法分析器看到输入"aa"时,它会尝试匹配标记AAA。当它失败时,它会尝试匹配任何其他也匹配"aa" 的标记(词法分析器不会回溯到匹配A!)。由于这是不可能的,所以会产生错误。

这通常不是问题,因为在实践中,经常有某种标识符规则"aa" 可以回退到。那么,您正在尝试解决什么实际问题,或者您只是对内部工作原理感到好奇?如果是第一个,请编辑您的问题并描述您的实际问题。

【讨论】:

  • 感谢您的澄清,巴特。我想它更接近第二个。我一直在使用 lex/yacc,我正在尝试切换到 ANTLR。 ANTLR 解析器作为 LL 解析器已经有其局限性,但正如您所指出的,这是关于词法分析器而不是解析器。老实说,如果 ANTLR 词法分析器不能处理如此复杂的复杂性,我会有点失望,而像 lex 这样的其他词法分析器可以做到。回溯成本不会很大,最坏的情况是 O(n^2),如果处理得当,可能会更好。
  • @KJ,当然有办法解决这个问题。但与其解释如何解决您的“稻草人”示例,我更愿意尝试为手头的“真正”问题提出解决方案(否则我最终会回答两次......)。
  • 恐怕我不是在寻找针对特定问题的解决方法。正如我所说,当我考虑使用 ANTLR 时,它更接近好奇心,因为它支持 JAVA,不像 yacc,但我越来越谨慎。我知道手动前瞻可以解决这个问题(我已经看到你的previous post),但是必须逐个处理类似的问题似乎不可靠.. 感谢您的回答!
猜你喜欢
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多