Antlr4 ANTLR 4优先级不符合预期

Antlr4 ANTLR 4优先级不符合预期,antlr4,Antlr4,我定义了一种我们在公司中使用的SQL风格,如下所示: /** Grammars always start with a grammar header. This grammar is called * GigyaSQL and must match the filename: GigyaSQL.g4 */ grammar GigyaSQL; parse : selectClause fromClause ( whereClause )? ( filterClause

我定义了一种我们在公司中使用的SQL风格,如下所示:

/** Grammars always start with a grammar header. This grammar is called
 *  GigyaSQL and must match the filename: GigyaSQL.g4
 */
grammar GigyaSQL;

parse
 : selectClause
   fromClause
   ( whereClause )?
   ( filterClause )?
   ( groupByClause )?
   ( limitClause )?
 ;

selectClause
 : K_SELECT result_column ( ',' result_column )*
 ;

result_column
 : '*' # selectAll
 | table_name '.' '*' # selectAllFromTable
 | select_expr ( K_AS? column_alias )? # selectExpr
 | with_table # selectWithTable
 ;

fromClause
 : K_FROM table_name
 ;

table_name 
 : any_name # simpleTable
 | any_name K_WITH with_table # tableWithTable
 ;

any_name
 : IDENTIFIER
 | STRING_LITERAL
 | '(' any_name ')'
 ;

with_table
 : COUNTERS
 ;

select_expr
 : literal_value
 | range_function_in_select
 | interval_function_in_select
 | ( table_name '.' )? column_name
 | function_name '(' argument_list ')'
 ;

whereClause
 : K_WHERE condition_expr
 ;

condition_expr
 : literal_value # literal
 | ( table_name '.' )? column_name # column_name_expr
 | unary_operator condition_expr # unary_expr
 | condition_expr binary_operator condition_expr # binary_expr
 | K_IFELEMENT '(' with_table ',' condition_expr ')' # if_element
 | function_name '(' argument_list ')' # function_expr
 | '(' condition_expr ')' # brackets_expr
 | condition_expr K_NOT? K_LIKE condition_expr # like_expr
 | condition_expr K_NOT? K_CONTAINS condition_expr # contains_expr
 | condition_expr K_IS K_NOT? condition_expr # is_expr
 //| condition_expr K_NOT? K_BETWEEN condition_expr K_AND condition_expr
 | condition_expr K_NOT? K_IN '(' ( literal_value ( ',' literal_value )*) ')' # in_expr
 ;

filterClause
 : K_FILTER with_table K_BY condition_expr
 ;

groupByClause
 : K_GROUP K_BY group_expr ( ',' group_expr )*
 ;  

group_expr
 : literal_value
 | ( table_name '.' )? column_name
 | function_name '(' argument_list ')'
 | range_function_in_group
 | interval_function_in_group
 ;

limitClause
 : K_LIMIT NUMERIC_LITERAL
 ;

argument_list
 : ( select_expr ( ',' select_expr )* | '*' )
 ;

unary_operator
 : MINUS
 | PLUS
 | '~'
 | K_NOT
 ;

binary_operator
 : ( '*' | DIVIDE | MODULAR )
 | ( PLUS | MINUS )
 //| ( '<<' | '>>' | '&' | '|' )
 | ( LTH | LEQ | GTH | GEQ )
 | ( EQUAL | NOT_EQUAL | K_IN | K_LIKE )
 //| ( '=' | '==' | '!=' | '<>' | K_IS | K_IS K_NOT | K_IN | K_LIKE | K_GLOB | K_MATCH | K_REGEXP )
 | K_AND
 | K_OR
 ;

range_function_in_select
 : K_RANGE '(' select_expr ')'
 ;

range_function_in_group
 : K_RANGE '(' select_expr ',' range_pair (',' range_pair)* ')'
 ;

range_pair // Tried to use INT instead (for decimal numbers) but that didn't work fine (didn't parse a = 1 correctly)
 : '"' NUMERIC_LITERAL ',' NUMERIC_LITERAL '"'
 | '"' ',' NUMERIC_LITERAL '"'
 | '"' NUMERIC_LITERAL ',' '"'
 ;

interval_function_in_select
 : K_INTERVAL '(' select_expr ')'
 ;

interval_function_in_group
 : K_INTERVAL '(' select_expr ',' NUMERIC_LITERAL ')'
 ;


function_name
 : any_name
 ;

literal_value
 : NUMERIC_LITERAL
 | STRING_LITERAL
// | BLOB_LITERAL
 | K_NULL
// | K_CURRENT_TIME
// | K_CURRENT_DATE
// | K_CURRENT_TIMESTAMP
 ;

column_name 
 : any_name
 ;

column_alias
 : IDENTIFIER
 | STRING_LITERAL
 ;

SPACES
 : [ \u000B\t\r\n] -> skip
 ;

COUNTERS : 'counters' | 'COUNTERS';

//INT : '0' | DIGIT+ ; 

EQUAL  : '=';
NOT_EQUAL  : '<>' | '!=';
LTH : '<' ;
LEQ : '<=';
GTH   : '>';
GEQ   : '>=';
//MULTIPLY: '*';
DIVIDE  : '/';
MODULAR : '%';
PLUS  : '+';
MINUS : '-';

K_AND : A N D;
K_AS : A S;
K_BY : B Y;
K_CONTAINS: C O N T A I N S;
K_DISTINCT : D I S T I N C T;
K_FILTER : F I L T E R;
K_FROM : F R O M;
K_GROUP : G R O U P;
K_IFELEMENT : I F E L E M E N T;
K_IN : I N;
K_INTERVAL : I N T E R V A L;
K_IS : I S;
K_LIKE : L I K E;
K_LIMIT : L I M I T;
K_NOT : N O T;
K_NULL : N U L L;
K_OR : O R;
K_RANGE : R A N G E;
K_REGEXP : R E G E X P;
K_SELECT : S E L E C T;
K_WHERE : W H E R E;
K_WITH : W I T H;

IDENTIFIER
 : '"' (~'"' | '""')* '"'
 | '`' (~'`' | '``')* '`'
 | '[' ~']'* ']'
 | [a-zA-Z_] [.a-zA-Z_0-9]* // TODO - need to check if the period is correcly handled
 | [a-zA-Z_] [a-zA-Z_0-9]* // TODO check: needs more chars in set
 ;

STRING_LITERAL
 : '\'' ( ~'\'' | '\'\'' )* '\''
 ;

NUMERIC_LITERAL
 :// INT
 DIGIT+  ('.' DIGIT*)? ( E [-+]? DIGIT+ )?
 | '.' DIGIT+ ( E [-+]? DIGIT+ )?
 ;

fragment DIGIT : [0-9];

fragment A : [aA];
fragment B : [bB];
fragment C : [cC];
fragment D : [dD];
fragment E : [eE];
fragment F : [fF];
fragment G : [gG];
fragment H : [hH];
fragment I : [iI];
fragment J : [jJ];
fragment K : [kK];
fragment L : [lL];
fragment M : [mM];
fragment N : [nN];
fragment O : [oO];
fragment P : [pP];
fragment Q : [qQ];
fragment R : [rR];
fragment S : [sS];
fragment T : [tT];
fragment U : [uU];
fragment V : [vV];
fragment W : [wW];
fragment X : [xX];
fragment Y : [yY];
fragment Z : [zZ];
/**语法始终以语法头开头。这种语法叫做
*GigyaSQL和必须匹配文件名:GigyaSQL.g4
*/
语法;
作语法分析
:selectClause
从句
(条款)?
(过滤槽)?
(分组条款)?
(限制条款)?
;
选择子句
:K_选择结果_列(“,”结果_列)*
;
结果列
:“*”#选择全部
|表_名称''.'*.#从表中选择AllFromTable
|选择_expr(K_AS?column_alias)?#选择表达式
|使用表格#选择WithTable
;
从句
:K_来自表_名称
;
表名称
:任意_名称#可简化
|任何_名称K_WITH_table#tableWithTable
;
有名字吗
:标识符
|字符串文字
|“(“任何名称”)”
;
带桌子
:计数器
;
选择_expr
:文字值
|范围\u功能\u在\u选择中
|间隔\u功能\u在\u选择中
|(表_名称')?列名
|函数名“(“参数列表”)”
;
where子句
:K_WHERE condition_expr
;
条件表达式
:literal_值#literal
|(表_名称')?列名称列名称表达式
|一元运算符条件表达式一元表达式
|条件表达式二进制运算符条件表达式二进制表达式
|K#IFELEMENT'('with_table','condition_expr'))#if_元素
|函数名“(“参数列表”)”函数表达式
|“(“条件表达式”)”括号
|条件是什么?类K条件
|条件是什么?K#u包含条件#u表达式#包含条件#u表达式
|条件expr K不是吗?条件“expr”是“expr”
//|条件是什么?条件表达式K与条件表达式K之间的K
|条件是什么?在“(”(文字值(“,”文字值)*)“)中的K#u
;
过滤槽
:K_过滤器,带有表K_按条件导出
;
分组子句
:K_组K_按组表达式(','GROUP_expr)*
;  
组expr
:文字值
|(表_名称')?列名
|函数名“(“参数列表”)”
|组中的范围函数
|组中的区间函数
;
限制条款
:K\u限制数字\u文字
;
参数列表
:(选择表达式(“,”选择表达式)*|“*”)
;
一元算子
:减
|加上
| '~'
|库诺
;
二元算子
:(“*”|除|模)
|(加|减)
//| ( '' | '&' | '|' )
|(长| LEQ | GTH | GEQ)
|(相等|不相等| K|u IN | K|u LIKE)
//|(“=”|“=”|“!=”|“| K|u是| K|u不是| K|u在| K|u类似| K|u全球| K|u匹配| K|u REGEXP)
|K_和
|库奥
;
范围\u功能\u在\u选择中
:K_RANGE'('select_expr')'
;
组中的范围函数
:K_RANGE'('select_expr','RANGE_pair(','RANGE_pair)*')
;
range\u pair//尝试改用INT(对于十进制数),但效果不好(没有正确解析a=1)
:“‘数值文字’、‘数值文字’”
|“‘,‘数字’文字’”
|“‘数字文字’,”“”
;
间隔\u功能\u在\u选择中
:K_INTERVAL'('select_expr')'
;
组中的区间函数
:K_INTERVAL'('select_expr','NUMERIC_LITERAL')'
;
函数名
:有名字吗
;
字面值
:数字文字
|字符串文字
//| BLOB|U文字
|K_NULL
//| K_当前_时间
//| K_当前日期
//| K_当前_时间戳
;
列名
:有名字吗
;
列别名
:标识符
|字符串文字
;
空间
:[\u000B\t\r\n]->跳过
;
计数器:“计数器”|“计数器”;
//INT:'0'|位+;
相等:'=';
不等于:“|”!=”;
LTH:'=';
//乘:'*';
除法:“/”;
模块化:“”;
加:“+”;
减:'-';
K_和:A和D;
K_AS:A S;
K_BY:B Y;
K_包含:C O N T A I N S;
K_DISTINCT:D I S T I N C T;
K_滤波器:F I L T E R;
K_FROM:F R O M;
K_组:G R O U P;
K_if元素:I F E L M N T;
库因:我在;
K_间隔:I N T R V A L;
K_是:I S;
你喜欢:我喜欢;
K_极限:L I M I T;
K_NOT:N没有;
K_NULL:N U L L;
K_或:O R;
K_范围:R A N G E;
K_REGEXP:R E G E X P;
K_选择:S E L E C T;
K_其中:W H R E;
K_与:W I T H;
标识符
: '"' (~'"' | '""')* '"'
| '`' (~'`' | '``')* '`'
| '[' ~']'* ']'
|[a-zA-Z_][.a-zA-Z_0-9]*//TODO-需要检查周期是否正确处理
|[a-zA-Z_][a-zA-Z_0-9]*//TODO检查:集合中需要更多字符
;
字符串文字
: '\'' ( ~'\'' | '\'\'' )* '\''
;
数字文字
://INT
数字+('.'数字*)?(E[-+]?数字+?
|“.”数字+(E[-+]?数字+?
;
碎片数字:[0-9];
片段A:[aA];
片段B:[bB];
片段C:[cC];
片段D:[dD];
片段E:[eE];
片段F:[fF];
片段G:[gG];
片段H:[hH];
片段一:[二];
片段J:[jJ];
片段K:[kK];
片段L:[lL];
碎片M:[mM];
片段N:[nN];
片段O:[oO];
片段P:[pP];
片段Q:[qQ];
片段R:[rR];
片段S:[sS];
片段T:[tT];
片段U:[uU];
片段V:[vV];
片段W:[wW];
片段X:[xX];
片段Y:[yY];
片段Z:[zZ];
我尝试解析以下查询: 从非data.zzz>124的帐户中选择*

我得到以下树:

但我想得到与使用括号时类似的树: 从不存在的帐户中选择*(data.zzz>124)

我不明白为什么会这样,因为一元规则比其他规则更重要


有什么建议吗?

这是给定语法的正确结果。正如您已经提到的,
一元运算符
位于
二元运算符
之前,这意味着NOT关键字的任何操作数都是在其他运算符之前绑定到它的。由于它是一元运算符,因此它将
data.zzz
作为其操作数,并在t之后使整个NOT表达式成为
二进制\u运算符的操作数

要得到您想要的,只需根据一元_运算符的优先级向下移动它(我记得,在SQL中,NOT的优先级低于二元运算符的优先级,并且NOT运算符的优先级不应与减号加号和~的优先级相同,就像您的语法一样)

这就是你想要的:

condition_expr
: literal_value # literal
| ( table_name '.' )? column_name # column_name_expr
| condition_expr binary_operator condition_expr # binary_expr
| unary_operator condition_expr # unary_expr
| K_IFELEMENT '(' with_table ',' condition_expr ')' # if_element
| function_name '(' argument_list ')' # function_expr
| '(' condition_expr ')' # brackets_expr
| condition_expr K_NOT? K_LIKE condition_expr # like_expr
| condition_expr K_NOT? K_CONTAINS condition_expr # contains_expr
| condition_expr K_IS K_NOT? condition_expr # is_expr
//| condition_expr K_NOT? K_BETWEEN condition_expr K_AND condition_expr
| condition_expr K_NOT? K_IN '(' ( literal_value ( ',' literal_value )*) ')' # in_expr
;