Lexer 规则在不需要的地方被识别

Lexer rule is recognized where it wasn't needed

尝试使用 ANTLR 4 为 Oracle DB 中的某些 Select 语句创建简单语法。并面临一个小问题。我有以下语法:

语法和词法分析器

column
: (tableAlias '.')? IDENT ((AS)? colAlias)?
| expression ((AS)? colAlias)?
| caseWhenClause ((AS)? colAlias)?
| rankAggregate ((AS)? colAlias)?
| rankAnalytic colAlias
;

colAlias
: '"' IDENT '"'
| IDENT
;

rankAnalytic
: RANK '(' ')' OVER '(' queryPartitionClause orderByClause ')'
;

RANK: R A N K;
fragment A:('a'|'A');
fragment N:('n'|'N');
fragment R:('r'|'R');
fragment K:('k'|'K');

最重要的部分在 COLUMN 声明 rankAnalytic 部分。我声明在 Rank 语句之后应该是 colAlias,但是如果这个 colAlias 被称为 "rank"(不带引号),它会被识别为 RANK 词法分析器规则,而不是 colAlias。

例如,如果我有以下文本:

 SELECT fulfillment_bundle_id, SKU, SKU_ACTIVE, PARENT_SKU, SKU_NAME, LAST_MODIFIED_DATE,
 RANK() over (PARTITION BY fulfillment_bundle_id, SKU, PARENT_SKU 
 order by ACTIVE DESC NULLS LAST,SKU_NAME) rank

"rank" 别名将带有下划线并标记为错误,并出现以下错误:
输入不匹配 'rank' 需要 {'"', IDENT}
但关键是我不希望它被识别为RANK词法分析器词,而只是作为Column的别名进行排名。
欢迎您提出建议:)

RANK 规则显然出现在 IDENT 规则之上,因此词法分析器永远不会将字符串 "rank" 作为 IDENT 标记发出。

一个简单的解决方法是更改​​ colAlias 规则:

colAlias
    : '"' ( IDENT | RANK ) '"'
    | ( IDENT | RANK ) 
    ;

OP 添加:

Ok but in case I have not only RANK as a lexer rule but the whole list (>100) of such key words... What am I supposed to do?

如果 colAlias 可以是任何字面意思,那就让它:

colAlias
    : '"' .+? '"'    // must quote if multiple
    | .              // one token
    ;

如果该定义会引起歧义,则需要一个谓词来限定匹配:

colAlias
    : '"' m+=.+? '"' { check($m) }?  // multiple
    | o=.            { check($o) }?  // one 
    ;

从功能上讲,谓词只是子规则中的另一个元素。