尝试使用 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');
最重要的部分是列声明秩分析部分。我声明在 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补充说:
好的,但以防万一我不仅将 RANK 作为词法分析器规则,而且整个列表 (>100)这样的关键词...我应该怎么做?
如果colAlias
可以是字面上的任何东西,那么让它:
colAlias
: '"' .+? '"' // must quote if multiple
| . // one token
;
如果该定义会产生歧义,则需要一个谓词来限定匹配:
colAlias
: '"' m+=.+? '"' { check($m) }? // multiple
| o=. { check($o) }? // one
;
从功能上讲,谓词只是子规则中的另一个元素。