使用标识符时出现 ANTLR4 错误,但使用文字时不会出现 ANTLR4 错误

ANTLR4 error when using identifier but not when using literal

正在测试以下简单语法。

grammar SQL;
selectStatement: SELECT selectElements EOF;
selectElements: (star='*' | ID ) (',' ID)*;
ID: ID_LITERAL;
WS: [ \t\r\n]+ -> channel(HIDDEN);
fragment ID_LITERAL: [A-Z_[=10=]-9]*? [A-Z_$]+? [A-Z_[=10=]-9]*;
SELECT: 'SELECT';

给定输入 SELECT * 它会产生以下错误:

line 1:0 missing 'SELECT' at 'SELECT'
line 1:7 extraneous input '*' expecting <EOF>

虽然将 SELECT 标识符更改为 selectStatement 中的内联文字会产生以下语法,它可以无错误地解析相同的输入。为什么?

grammar SQL;
selectStatement: 'SELECT' selectElements EOF;
selectElements: (star='*' | ID ) (',' ID)*;
ID: ID_LITERAL;
WS: [ \t\r\n]+ -> channel(HIDDEN);
fragment ID_LITERAL: [A-Z_[=12=]-9]*? [A-Z_$]+? [A-Z_[=12=]-9]*;

模式 [A-Z_[=10=]-9]*? [A-Z_$]+? [A-Z_[=10=]-9]*'SELECT' 都匹配输入 SELECT * 并且它们都产生相同长度的匹配(即它们都匹配 SELECT 然后留下 * 作为输入的其余部分)。在这种情况下,ANTLR(像大多数词法分析器生成器一样)应用语法中最先出现的规则。在你的第一个语法中是 ID。所以 SELECT * 被词法化为 ID, WS, '*',而不是 SELECT, WS, '*'.

如果您将规则 SELECT: 'SELECT'; 移到 ID 的定义之前,它将按您希望的方式工作。