Lexer规则在不需要的地方得到认可

时间:2017-10-18 20:38:52

标签: oracle parsing antlr4 antlrworks

尝试使用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的别名。
打开您的建议:)

1 个答案:

答案 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 
    ;

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