我写了一个复杂的语法。语法如下:
grammar i;
options {
output=AST;
}
@header {
package com.data;
}
operatorLogic : 'AND' | 'OR';
value : STRING;
query : (select)*;
select : 'SELECT'^ functions 'FROM table' filters?';';
operator : '=' | '!=' | '<' | '>' | '<=' | '>=';
filters : 'WHERE'^ conditions;
conditions : (members (operatorLogic members)*);
members : STRING operator value;
functions : '*';
STRING : ('a'..'z'|'A'..'Z')+;
WS : (' '|'\t'|'\f'|'\n'|'\r')+ {skip();}; // handle white space between keywords
使用AST完成输出。以上只是一个小样本。但是,我正在开发一些大语法,需要有关如何处理这个问题的建议。
例如,根据上述语法,可以产生以下内容:
SELECT * from table;
SELECT * from table WHERE name = i AND name = j;
此查询可能会变得更复杂。我已经在Java代码中实现了AST,并且可以将Tree恢复。我想分离语法和逻辑,所以它们是有凝聚力的。所以AST是最好的方法。
用户将以字符串形式输入查询,我的代码需要以尽可能最好的方式处理查询。正如您所看到的,函数解析器当前是*,这意味着选择all。在未来,这可以扩展到包括其他东西。
我的代码如何处理这个问题?什么是最好的方法?
我可以这样做:
String input = "SELECT * from table;";
if(input.startsWith("SELECT")) {
select();
}
正如您所看到的,这种方法更复杂,因为我需要处理*也是可选的过滤器。还需要完成AND和OR的operatorLogic。
最好的方法是什么?我已经在线查看,但找不到任何关于如何处理这个问题的例子。
你能提供任何例子吗?
编辑:
String input = "SELECT * FROM table;";
if(input.startsWith("SELECT")) {
select();
}
else if(input.startsWith("SELECT *")) {
findAll();
}
答案 0 :(得分:0)
处理多个启动规则(“SELECT ...”,“UPDATE ...”等)的最简单方法是让ANTLR语法在单个顶级启动规则中为您完成工作。你已经拥有了它,所以只需要更新你拥有的东西。
目前你的语法仅限于一个命令类型的输入(“SELECT ...”),因为这是你所定义的:
query : (select)*; //query only handles "select" because that's all there is.
select : 'SELECT'^ functions 'FROM table' filters?';';
如果query
是您的起始规则,那么接受额外的顶级输入就是将query
定义为接受select
以上的内容:
query : (select | update)*; //query now handles any number of "select" or "update" rules, in any order.
select : 'SELECT'^ functions 'FROM table' filters?';';
update : 'UPDATE'^ ';'; //simple example of an update rule
现在query
规则可以处理SELECT * FROM table;
,UPDATE;
或SELECT * FROM table; UPDATE;
等输入。添加新的顶级规则后,只需更新query
即可测试该新规则。这样您的Java代码就不需要测试输入,它只调用query
规则并让解析器处理其余的。
如果您只想从输入处理一种类型的输入,请像这样定义query
:
query : select* //read any number of selects, but no updates
| update* //read any number of updates, but no selects
;
规则query
仍会处理SELECT * FROM table;
和UPDATE;
,但不会混合使用SELECT * FROM table; UPDATE;
等命令。
从调用query_return
获得query
AST树后,您现在可以使用Java代码可以处理的有意义的内容,而不是字符串。该树表示解析器处理的所有输入。
你可以像这样走过树的孩子:
iParser.query_return r = parser.query();
CommonTree t = (CommonTree) r.getTree();
for (int i = 0, count = t.getChildCount(); i < count; ++i) {
CommonTree child = (CommonTree) t.getChild(i);
System.out.println("child type: " + child.getType());
System.out.println("child text: " + child.getText());
System.out.println("------");
}
遍历整个AST树是在所有父节点上递归调用getChild(...)
的问题(上面的示例仅查看顶级子节点)。
处理*
的替代方案与您定义的任何其他方案没有什么不同:只需在要扩展的规则中定义备选方案即可。如果您希望functions
接受*
以上的内容,请定义functions
以接受*
以上的内容。 ;)
以下是一个例子:
functions: '*' //"all"
| STRING //some id
;
现在,解析器可以接受SELECT * FROM table;
和SELECT foobar FROM table;
。
请记住,您的Java代码无理由来检查输入字符串。每当你想要这样做时,寻找一种方法让你的语法做检查。然后,您的Java代码将根据需要查看AST树输出。