Query.g4:
grammar Query;
// parser
query : expr;
expr : SELECT result FROM repo (WHERE orCondition SEMI)?;
result : resultType (COMMA resultType)*;
resultType : 'class'
| 'method'
| 'package'
| 'dependenceGraph'
| 'controlFlowFraph'
| 'callGraph';
repo : app (COMMA app)*;
app : '[' ID ']';
// TODO 改为与或表达式
orCondition : andCondition (operator=OR andCondition)*
;
andCondition : conditionExpr (operator=AND conditionExpr)*
;
conditionExpr : conditionLeft op=('=' | '!=') conditionRight;
conditionLeft : app DOT type DOT attr;
conditionRight : STRING;
type: 'package'
| 'class'
| 'method';
attr : 'name'
| 'type'
| 'visibility'
| 'isAbstract';
// keyword
SELECT : 'select';
FROM : 'from';
WHERE : 'where';
AND : 'and';
OR : 'or';
NOT : 'not';
COMMA : ',';
SEMI : ';';
DOT : '.';
// lexer
ID : Letter LetterOrDigit*;
STRING
: '\'' ( ~('\''|'\\') | ('\\' .) )* '\''
| '"' ( ~('"'|'\\') | ('\\' .) )* '"'
;
fragment Letter: [a-zA-Z_];
fragment Digit : ('0' .. '9') +;
fragment LetterOrDigit: Letter | Digit;
WS : [ \t\n\r]+ -> skip ;
QueryListenerImp.java:
package modelQuery.parser;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import java.util.HashSet;
public class QueryListenerImp extends QueryBaseListener {
HashSet resultSet = new HashSet<>();
HashSet appSet = new HashSet<>();
StringBuilder condition = new StringBuilder();
boolean Sign = false;
public ParseTreeProperty values = new ParseTreeProperty<>();
@Override
public void exitExpr(QueryParser.ExprContext ctx) {
if(Sign)
return;
else {
System.out.println("resultSet: " + resultSet);
System.out.println("appSet: " + appSet);
System.out.println("condition: " + values.get(ctx.orCondition()));
// 后面调用XQuery查询xml信息库中内容
}
}
@Override
public void exitResultType(QueryParser.ResultTypeContext ctx) {
resultSet.add(ctx.getText());
System.out.println("exitResultType: " + ctx.getText());
}
@Override
public void exitRepo(QueryParser.RepoContext ctx) {
for(QueryParser.AppContext appCtx : ctx.app()) {
appSet.add(appCtx.getText());
}
}
@Override
public void exitOrCondition(QueryParser.OrConditionContext ctx) {
if(ctx.operator != null){
values.put(ctx, values.get(ctx.andCondition(0)) + " or " + values.get(ctx.andCondition(1)));
} else {
}
values.put(ctx, values.get(ctx.andCondition(0)));
}
@Override
public void exitAndCondition(QueryParser.AndConditionContext ctx) {
if(ctx.operator != null) {
values.put(ctx, values.get(ctx.conditionExpr(0)) + " and " + values.get(ctx.conditionExpr(1)));
} else {
values.put(ctx, values.get(ctx.conditionExpr(0)));
}
}
@Override
public void exitConditionExpr(QueryParser.ConditionExprContext ctx) {
String left = values.get(ctx.conditionLeft());
values.put(ctx, left + ctx.op.getText() + ctx.conditionRight().getText());
}
@Override
public void exitConditionLeft(QueryParser.ConditionLeftContext ctx) {
String app = ctx.app().getText();
if(!appSet.contains(app)) {
System.err.println(ctx.start.getLine() + ":" + ctx.start.getStartIndex() + ", variable " + ctx.app().getText() + " not defined");
Sign = true;
return;
} else {
String type = ctx.type().getText();
String attr = ctx.attr().getText();
values.put(ctx, "$x/" + type + "/@" + attr);
}
}
}
最后可以测试如下语句:
select class,method, package from [aa],[bb]
where [app].method.name = "yyf"
and [app].class.name = "www";
利用IDEA插件可以看到解析的语法树:
test.png