首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >复杂语法的Antlr AST树方法

复杂语法的Antlr AST树方法
EN

Stack Overflow用户
提问于 2012-11-28 23:02:02
回答 1查看 393关注 0票数 0

我写了一个复杂的语法。语法如下所示:

代码语言:javascript
复制
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完成的。以上只是一个小样本。然而,我正在开发一些大的语法,并需要关于如何处理这一点的建议。

例如,根据上述语法,可以产生以下内容:

代码语言:javascript
复制
SELECT * from table;
SELECT * from table WHERE name = i AND name = j;

这个查询可能会变得更加复杂。我已经在Java代码中实现了AST,并且可以获取树。我想把语法和逻辑分开,所以它们是有凝聚力的。所以AST是最好的方法。

用户将以字符串形式输入查询,我的代码需要以最好的方式处理查询。正如您所看到的,函数解析器当前是*,这意味着选择全部。在未来,这可能会扩大到包括其他东西。

我的代码如何处理这个问题呢?最好的方法是什么?

我可以这样做:

代码语言:javascript
复制
String input = "SELECT * from table;";
if(input.startsWith("SELECT")) {
    select();
}

正如你所看到的,这种方法更加复杂,因为我需要处理*以及可选的过滤器。也需要做AND和OR的operatorLogic。

最好的方法是什么?我已经在网上找过了,但是找不到任何关于如何处理这个问题的例子。

你能举一些例子吗?

编辑:

代码语言:javascript
复制
String input = "SELECT * FROM table;";
if(input.startsWith("SELECT")) {
   select();
}
else if(input.startsWith("SELECT *")) {
  findAll();
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-11-28 23:41:29

处理多个启动规则("SELECT ...“、"UPDATE...”等)的最简单方法是让ANTLR语法在单个顶级启动规则上为您完成工作。你几乎已经拥有了,所以只需要更新你已经拥有的东西。

目前,您的语法仅限于一种命令类型的输入("SELECT...")因为这就是你所定义的:

代码语言:javascript
复制
query       : (select)*; //query only handles "select" because that's all there is.
select      : 'SELECT'^ functions 'FROM table' filters?';';

如果您的起始规则是query,那么接受额外的顶级输入就是定义query接受比select更多的内容

代码语言:javascript
复制
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

代码语言:javascript
复制
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获得Java树之后,现在就有了query_return代码可以处理的有意义的东西,而不是字符串。该树表示解析器处理的所有输入。

您可以像这样遍历树的子节点:

代码语言:javascript
复制
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定义为接受比*更多的内容。;)

下面是一个例子:

代码语言:javascript
复制
functions: '*'      //"all"
         | STRING   //some id
         ;

请记住,Java代码没有理由检查输入字符串。每当你想这样做的时候,寻找一种方法来让你的语法进行检查。然后,您的Java代码将查看AST树输出,以获取它想要的任何内容。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13608062

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档