尝试使用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 lexer规则,但不是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
"秩"别名将带下划线并标记为错误,并出现以下错误:
输入不匹配'排名'期待{'"',IDENT}
但关键是我不希望它被识别为RANK词法分析词,但只是列为Column的别名。
打开您的建议:)
答案 0 :(得分:1)
RANK
规则显然出现在IDENT
规则之上,因此字符串"排名"词法分析器永远不会将其作为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
;
从功能上讲,谓词只是子规则中的另一个元素。