ANTLR 4.5-输入不匹配';x';期待';x';

ANTLR 4.5-输入不匹配';x';期待';x';,antlr,antlr4,Antlr,Antlr4,我已经开始使用ANTLR,并注意到它的lexer规则非常易变。下面是一个非常令人沮丧的例子: grammar output; test: FILEPATH NEWLINE TITLE ; FILEPATH: ('A'..'Z'|'a'..'z'|'0'..'9'|':'|'\\'|'/'|' '|'-'|'_'|'.')+ ; NEWLINE: '\r'? '\n' ; TITLE: ('A'..'Z'|'a'..'z'|' ')+ ; 此语法与以下内容不匹配: c:\test.txt x

我已经开始使用ANTLR,并注意到它的lexer规则非常易变。下面是一个非常令人沮丧的例子:

grammar output;

test: FILEPATH NEWLINE TITLE ;

FILEPATH: ('A'..'Z'|'a'..'z'|'0'..'9'|':'|'\\'|'/'|' '|'-'|'_'|'.')+ ;
NEWLINE: '\r'? '\n' ;
TITLE: ('A'..'Z'|'a'..'z'|' ')+ ;
此语法与以下内容不匹配:

c:\test.txt
x

奇怪的是,如果我把
TITLE
改为
TITLE:'x'这一次仍然失败,给出一条错误消息说“不匹配的输入'x'应为'x'”,这非常令人困惑。更奇怪的是,如果我用
FILEPATH
替换
test
中的
TITLE
的用法,整个过程都会正常工作(虽然
FILEPATH
的匹配比我期望的匹配要多,所以一般来说这对我来说不是一个有效的解决方案)


我非常困惑,为什么ANTLR会出现如此奇怪的错误,然后在处理事情时突然无缘无故地工作。

这似乎是对
ANTLR
的常见误解:

ANTLR中的语言处理:

语言处理分为两个严格分离的阶段:

  • 词法分析,即将文本划分为标记
  • 解析,即从令牌构建解析树
由于词法分析必须在解析之前进行,因此有一个结果:词法分析程序独立于解析器,解析器不能影响词法分析

词法分析

ANTLR中的弯曲工作如下:

grammar output;

test: FILEPATH NEWLINE TITLE ;

FILEPATH: ('A'..'Z'|'a'..'z'|'0'..'9'|':'|'\\'|'/'|' '|'-'|'_'|'.')+ ;
NEWLINE: '\r'? '\n' ;
TITLE: ('A'..'Z'|'a'..'z'|' ')+ ;
  • 所有以大写字母开头的规则都是lexer规则
  • lexer从开头开始,试图找到与当前输入最匹配的规则
  • 最佳匹配是具有最大长度的匹配,即,将下一个输入字符附加到最大长度匹配后得到的标记不符合任何lexer规则
  • 令牌由匹配项生成:
    • 如果一条规则最大长度匹配匹配,则将相应的令牌推送到令牌流中
    • 如果多个规则匹配最大长度匹配语法中定义的第一个标记将被推送到标记流
示例:你的语法有什么问题

您的语法有两条至关重要的规则:

FILEPATH: ('A'..'Z'|'a'..'z'|'0'..'9'|':'|'\\'|'/'|' '|'-'|'_'|'.')+ ;
TITLE: ('A'..'Z'|'a'..'z'|' ')+ ;
由标题匹配的每个匹配项也将由文件路径匹配。文件路径在TITLE之前定义:因此,您希望成为标题的每个标记都将是文件路径。

有两个提示:

  • 保持你的lexer规则不相交(没有任何标记应该匹配另一个标记的超集)
  • 如果您的令牌有意匹配相同的字符串,那么将它们放入正确的顺序(在您的情况下,这就足够了)
  • 如果您需要一个解析器驱动的词法分析器,那么您必须切换到另一个解析器生成器:PEG解析器或GLR解析器可以做到这一点(当然,这可能会产生其他问题)
      这不是OP的直接问题,但对于那些有相同错误消息的人,您可以检查以下内容



      当我引入一个新的关键字时,我有相同的
      不匹配的输入'x'期望'x'
      模糊的错误消息。对我来说,原因是我将新关键字放在我的
      VARNAME
      lexer规则之后,该规则将其指定为变量名,而不是新关键字。我通过将关键字放在
      VARNAME
      规则之前解决了这个问题。

      现在很有意义,谢谢您的回复!不过,如果有一条更有用的错误消息就好了,但我知道这可能很难或不合理。在运行时,解析器必须假设用户知道其行为。但我同意,如果两条lexer规则以这种方式重叠,则可以发出警告。来自ANTLR参考的伟大总结!我有同样的问题还有另一个原因。解析器和lexer中的令牌常量不同步,导致两者中“x”的数字不同。已正确识别标记,但解析器无法匹配。清理项目有帮助。