我编写了一些antlr4规则来解析sql,只是想区分字段和表。但是它们做了一些意想不到的事情。我的规则:
grammar Col;
stat : SELECT select_list FROM table_ref_list;
select_list : select_ele (',' select_ele)* ;
select_ele : Subquery_in_field_nor //subquery select column
| ID '(' .*? ')' //function calls
| NoDotId '(' .*? ')' NoDotId '(' .*? ')' //window function call
| ID //like column of tab
| DIGIT //number
| STRING //like this 'dad'
;
table_ref_list
: table_ref (',' table_ref)*
;
table_ref:table_block (NoDotId)?;
table_block : ID //So much like select_ele
| Subquery_in_field_nor
;
Subquery_in_field_nor : '(' (Subquery_in_field | ~[()])* ')'; //Resolving function nesting
Subquery_in_field : '(' .*? ')' ;
SELECT : [Ss][Ee][Ll][Ee][Cc][Tt];
FROM :[Ff][Rr][Oo][Mm];
NL : [ \r\n]+ ->skip;
ID : [A-Za-z] [A-Za-z0-9.]*;
NoDotId : [A-Za-z] [A-Za-z0-9]*;
DIGIT : ('-')? [0-9]+('.' [0-9]+)?;
STRING : '\'' .*? '\'';
我的sql文件是这样的
SELECT substr(A.EMPNO,1,2),
A.ENAME,
'1',
'wwet',
18,
A.DEPTNO FROM EMP A
显示消息
line 1:13 missing FROM at '(A.EMPNO,1,2)'
line 3:7 mismatched input ''1'' expecting {Subquery_in_field_nor, ID}
line 4:7 mismatched input ''wwet'' expecting {Subquery_in_field_nor, ID}
line 5:7 mismatched input '18' expecting {Subquery_in_field_nor, ID}
(stat SELECT (select_list (select_ele substr)) <missing FROM> (table_ref_list (table_ref (table_block (A.EMPNO,1,2))) , (table_ref (table_block A.ENAME)) , (table_ref (table_block '1')) , (table_ref (table_block 'wwet')) , (table_ref (table_block 18)) , (table_ref (table_block A.DEPTNO))))
我不知道为什么?为什么 select_list : select_ele (',' select_ele)*
,但仍然匹配表\u ref?
1条答案
按热度按时间zphenhs41#
substr(A.EMPNO,1,2)
不匹配为select_ele
因为它产生代币:ID
:substr
Subquery_in_field_nor
:(A.EMPNO,1,2)
而不是两种选择中的任何一种:| ID '(' .? ')' //function calls
| NoDotId '(' .*? ')' NoDotId '(' .*? ')' //window function call
零件“('.?')”解释为:匹配(
标记,不情愿地后跟零个或多个其他标记,以)
代币。但是由于antlr的lexer在标记输入时试图获取尽可能多的字符,(A.EMPNO,1,2)
总会有一个Subquery_in_field_nor
代币。除了lexer中贪婪的标记化之外,您还必须注意,当2个或更多lexer规则可以匹配相同的字符时,首先定义的规则“获胜”。所以输入
select
可以匹配SELECT
,ID
以及NoDotId
. 但是自从SELECT
首先定义,输入将始终成为SELECT
代币。然而,输入foo
可以匹配ID
以及NoDotId
从那以后呢ID
先定义,它就会赢。你会注意到永远不会有NoDotId
因为它匹配的任何东西也会被匹配ID
.下面是一个稍加修改的语法,适用于您的输入:
或者更好,从antlr4 github repo获取现有的sql语法:https://github.com/antlr/grammars-v4 请注意,所有这些语法都是来自社区的开源贡献:正确地测试它们,因为它们中的许多都有局限性(准确性和性能)。