测试以下简单语法。
grammar SQL;
selectStatement: SELECT selectElements EOF;
selectElements: (star='*' | ID ) (',' ID)*;
ID: ID_LITERAL;
WS: [ trn]+ -> channel(HIDDEN);
fragment ID_LITERAL: [A-Z_$0-9]*? [A-Z_$]+? [A-Z_$0-9]*;
SELECT: 'SELECT';
给定输入SELECT *
它会产生以下错误:
line 1:0 missing 'SELECT' at 'SELECT'
line 1:7 extraneous input '*' expecting <EOF>
虽然在selectStatement
中SELECT
标识符更改为内联文本会导致以下语法,这将分析相同的输入而不会出错。为什么?
grammar SQL;
selectStatement: 'SELECT' selectElements EOF;
selectElements: (star='*' | ID ) (',' ID)*;
ID: ID_LITERAL;
WS: [ trn]+ -> channel(HIDDEN);
fragment ID_LITERAL: [A-Z_$0-9]*? [A-Z_$]+? [A-Z_$0-9]*;
模式[A-Z_$0-9]*? [A-Z_$]+? [A-Z_$0-9]*
和'SELECT'
都匹配在输入SELECT *
上,并且它们都产生相同长度的匹配(即它们都匹配SELECT
然后*
作为输入的其余部分(。在这种情况下,ANTLR(像大多数词法生成器一样(应用语法中首先出现的规则。在你的第一个语法中,这是ID
.所以SELECT *
被表述为ID, WS, '*'
,而不是SELECT, WS, '*'
。
如果将规则移动到ID
定义之前SELECT: 'SELECT';
,它将按预期工作。