代码之家  ›  专栏  ›  技术社区  ›  Maks Karashchuk

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

  •  1
  • Maks Karashchuk  · 技术社区  · 7 年前

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

    语法和;Lexer公司

    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');
    

    最重要的部分是 公告 rankAnalytic公司

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

     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}

    欢迎您的建议:)

    1 回复  |  直到 7 年前
        1
  •  1
  •   GRosenberg    7 年前

    这个 RANK 规则显然出现在 IDENT 因此,lexer永远不会将字符串“rank”作为 代币

    一个简单的解决方法是更改 colAlias

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

    OP添加:

    好的,但如果我不仅有一个lexer规则的排名,但整个列表

    如果 colAlias公司 可以是任何东西,那么就让它:

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

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

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

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