ANTLR 4.5 - 预期'x'输入不匹配'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代替testTITLE的用法,整个事情都会起作用(尽管FILEPATH的匹配程度会比我想要的要高,所以一般来说,这对我来说不是一个有效的解决方案)。

我非常困惑,为什么ANTLR会出现如此奇怪的错误,然后在混乱的时候突然莫名其妙地工作。

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

ANTLR中的语言处理:

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

  • Lexing,即将文本划分为令牌
  • 解析,即根据令牌构建解析树

由于词法分析必须优先于语法分析,因此有一个后果:词法分析器独立于语法分析器,语法分析器不能影响词法分析。

乐星

ANTLR中的乐星工作如下:

  • 所有第一个字符大写的规则都是lexer规则
  • lexer从一开始就试图找到一个与当前输入最匹配的规则
  • 最佳匹配是具有最大长度的匹配,也就是说,将下一个输入字符附加到最大长度匹配后得到的令牌不符合任何lexer规则
  • 令牌是根据匹配生成的:
    • 如果一个规则匹配最大长度匹配,则将相应的令牌推入令牌流
    • 如果多个规则匹配最大长度匹配,则语法中第一个定义的令牌将被推送到令牌流

示例:您的语法有什么问题

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

FILEPATH: ('A'..'Z'|'a'..'z'|'0'..'9'|':'|'\'|'/'|' '|'-'|'_'|'.')+ ;
TITLE: ('A'..'Z'|'a'..'z'|' ')+ ;

每个由TITLE匹配的匹配也将由FILEPATH匹配。FILEPATH是在TITLE:之前定义的,所以你期望成为标题的每个令牌都是FILEPATH

有两个提示:

  • 保持lexer规则的析取(任何令牌都不应该与另一个令牌的超集匹配)
  • 如果您的令牌有意匹配相同的字符串,那么将它们按正确的顺序排列(在您的情况下,这就足够了)
  • 如果你需要一个解析器驱动的lexer,你必须换成另一个解析器生成器:PEG解析器或GLR解析器会这样做(但这当然会产生其他问题)

这不是OP的直接问题,但对于那些有相同错误消息的人,您可以检查以下内容。


当我引入一个新关键字时,我收到了相同的Mismatched Input 'x' expecting 'x'模糊错误消息。对我来说,原因是我将新关键字放在了VARNAMElexer规则之后,该规则将其指定为变量名,而不是新关键字。我通过将关键字放在VARNAME规则之前来修复它。

TITLE的任何输入都与FILEPATH令牌匹配。lang处理器停止对处理输入的FILEPATH的选择,并且没有机会到达TITLE令牌。这就引出了这个问题。

解决方法是将TITLE置于FILEPATH令牌之前(或将FILEPATH置于TITLE令牌之后)。例如:

grammar output;
test: FILEPATH NEWLINE TITLE ;
NEWLINE: 'r'? 'n' ;
TITLE: ('A'..'Z'|'a'..'z'|' ')+ ;
FILEPATH: ('A'..'Z'|'a'..'z'|'0'..'9'|':'|'\'|'/'|' '|'-'|'_'|'.')+ ;

p.S。此解决方案适用于等输入

c:test.txt
x

如果你的输入是简单的文件名,没有文件夹名的扩展名,你会遇到同样的问题。

test
x

所以我会考虑对FILEPATH使用一些限制,使其与TITLE不同。例如,将下一个正则表达式[A-Za-z][:][\/][A-Za-z0-9]+'.'[A-Za-z0-9]+用于FILEPATH(不确定,因为我不清楚您的所有情况)。因此,最终的解决方案可能是:

grammar output;
test: FILEPATH NEWLINE TITLE ;
fragment FILENAME: TITLE DOT EXTENSION;
fragment LETTER: [a-zA-Z] ;
fragment DIGIT: [0-9] ;
fragment UNDERSCORE: '_' ;
fragment SPACE: ' ' ;
fragment ESCAPE: '\' ;
fragment SLASH: '/' ;
fragment QUOTE: '"' ;
fragment PLUS: '+';
fragment MINUS: '-';
fragment COLON: ':' ;
fragment DOT: '.';
EXTENSION: DOT (LETTER | DIGIT)+;
SEPARATOR: ESCAPE | SLASH;
DISC: LETTER COLON;
TITLE: (LETTER | DIGIT | UNDERSCORE | MINUS)+ ;
FILEPATH: DISC?(SEPARATOR TITLE)+ EXTENSION ;
NEWLINE: 'r'? 'n' ;

相关内容

  • 没有找到相关文章

最新更新