对Hplsql.g4或Hive.g4的阵列支持
大家好,, 我正在使用antlr4为配置单元SQL(Hplsql.g4)创建解析器和词法分析器。对Hplsql.g4或Hive.g4的阵列支持,hive,antlr4,Hive,Antlr4,大家好,, 我正在使用antlr4为配置单元SQL(Hplsql.g4)创建解析器和词法分析器。 我相信这是最新的语法文件。 但是,我发现至少需要添加两个索引:IF和数组索引。 例如,在select语句中,我可能有: a) 从x中选择(a>8,12,20) b) 从x中选择列名称[2] 这两者在配置单元中都是有效的,但是当我从上面的Hplsql.g4创建java解析器和lexer时,它们都不会解析。我为IF添加了一个表达式,它似乎可以工作 我补充说 expr : ...
我相信这是最新的语法文件。
但是,我发现至少需要添加两个索引:IF和数组索引。 例如,在select语句中,我可能有: a) 从x中选择(a>8,12,20)
b) 从x中选择列名称[2] 这两者在配置单元中都是有效的,但是当我从上面的Hplsql.g4创建java解析器和lexer时,它们都不会解析。我为IF添加了一个表达式,它似乎可以工作 我补充说
expr :
...
| expr_if //I added
还有一条新规则:
expr_if :
T_IF T_OPEN_P bool_expr T_COMMA expr T_COMMA expr T_CLOSE_P //I added
;
但是,找出如何允许数组索引并不容易,因为语法允许别名:
select a from x
select a alias_of_a from x
select a[1] from x
select a[1] alias_of_a from x
都应该是有效的。
我尝试为此添加一个新表达式,如下所示:
expr :
...
| expr_array //I added
expr_array :
T_OPEN_SB L_INT T_OPEN_CB //I added
;
这对我不起作用。(T_OPEN_SB L_INT T_OPEN_CB分别为[整数])。我也尝试了很多不同的方法。我的问题是:
根据Bart的建议: 我更新了标识。
我更新了expr\u atom。
我添加了数组索引。
我之前已经注释掉了“[”*?“]” 测试Sql:从t中选择[0]
结果: 第1行:8输入“selecta[0]”时没有可行的替代方案
第1行:8不匹配的输入“[0]” 树 (程序(块stmt(stmt选择)(stmt(expr_stmt)(expr(expr_原子(标识a 1077;ее))))[0]自t) 我觉得这个问题与下面选择的别名有关。 当包含ident和T_的select_list_别名为可选时,ident与数组索引匹配。 我无法解释为什么会发生这种情况,特别是因为ident已经更新 摘自Hplsql.sql:
select_list :
select_list_set? select_list_limit? select_list_item (T_COMMA select_list_item)*
;
select_list_item :
(ident T_EQUAL)? expr select_list_alias?
| select_list_asterisk
;
select_list_alias :
{!_input.LT(1).getText().equalsIgnoreCase("INTO") && !_input.LT(1).getText().equalsIgnoreCase("FROM")}? T_AS? ident
| T_OPEN_P T_TITLE L_S_STRING T_CLOSE_P
;
如果我将一个简单的SQL stmt传递给grun,例如
select a[1] from t
解析树的外观应类似于以下内容:
我希望看到的不是expr_atom,而是expr_数组,它将拆分为a的expr_atom和[1]的array_索引
请注意,这里有一条SQL语句。在我现有的g4中,数组索引[1](以及stmt的其余部分)被解析为一个单独的SQL语句
Bart,我从你的解析树中看到,解析导致了“从t中选择a[0]”中的两条SQL语句——我得到了相同的情况
我将继续探索不同的方法-我仍然怀疑select_list_别名,它有
T_AS?结尾处的标识
。为了确认,我已经注释掉了ident_part中的一行,如下所示://|“[”.*?]”如注释中所述:[…]
将标记为L_ID
标记。如果你没有;如果您不想这样做,请删除|'['.*.']'
部分:
fragment
L_ID_PART :
[a-zA-Z] ([a-zA-Z] | L_DIGIT | '_')* // Identifier part
| ('_' | '@' | ':' | '#' | '$') ([a-zA-Z] | L_DIGIT | '_' | '@' | ':' | '#' | '$')+ // (at least one char must follow special char)
| '"' .*? '"' // Quoted identifiers
// | '[' .*? ']' <-- removed
| '`' .*? '`'
;
它将正确地解析从[identifier]
中选择一个[1]别名\u of a,但对整个语法(或对HPL/SQL的深入了解)没有很好的了解,无法确定这是否会搞乱其他事情:)
编辑
根据我提议的修改,语法如下:(由于字符限制,我无法在此发布)
解析从t
中选择[0],这将导致解析树:
并且解析从[t]
中选择[0],这将导致此解析树:
您还可以通过运行以下Java代码对其进行测试:
String source=“从[t]中选择[0]”;
HplsqlLexer lexer=新的HplsqlLexer(CharStreams.fromString(source));
HplsqlParser parser=newhplsqlparser(newcommontokenstream(lexer));
ParseTree root=parser.program();
JFrame=新JFrame(“Antlr AST”);
JPanel面板=新的JPanel();
TreeViewer=newTreeViewer(Arrays.asList(parser.getRuleNames()),root);
查看器设置刻度(1.5);
面板。添加(查看器);
框架。添加(面板);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
嗨,巴特,谢谢你的评论。是的,我在语法里看到了。看起来像是选择列表别名:{!\u input.LT(1).getText().equalsIgnoreCase(“INTO”)和&!\u input.LT(1).getText().equalsIgnoreCase(“FROM”)}?图亚斯?ident导致了与ident的匹配,但是,我认为解析器首先匹配最长的规则(最长的令牌集)。巴特,谢谢你-我将阅读。我正在考虑删除单独的标记“[”和“]”,以便将它们专用于数组索引大小写(作为解析器规则)。我担心这是一个糟糕的方法。如果我明白你的意思,就没有办法添加数组索引处理了?回答得很好。事实上,我并没有说我已经注释掉了://|'['.*.']'巴特,我在原始帖子的末尾添加了我的测试结果-我的评论中没有足够的空间。请检查我的编辑@MikeLapenna。不确定我的观点是否被理解:'['.*?']'
需要删除,否则它将无法工作,因为lexer是如何工作的(此处解释:)签出my EDIT@Bart(再次感谢您对此的研究)。注意,解析结果是一个SQL smt。啊,两个stmt,是的,我刚才看到了。嗯,我想我没有一个快速的解决办法。如果我能花更多的时间在上面,我可能会看看语法,否则我会删除这个答案。
expr_atom :
date_literal
| timestamp_literal
| bool_literal
| expr_array // <-- added
| ident
| string
| dec_number
| int_number
| null_const
;
// new rule
expr_array
: ident array_index+
;
// new rule
array_index
: T_OPEN_SB expr T_CLOSE_SB
;
ident :
L_ID
| T_OPEN_SB ~T_CLOSE_SB+ T_CLOSE_SB // <-- added
| non_reserved_words
;