ANTLR是一个开源的词法分析器,包含了词法分析和语法分析,可以按照自定义规则去解析文件,得到一个树,下面主要结束使用ANTLR解析简单的HQL(此HQL只包含简单的select和from语句),大概介绍了解析的方法,提供一种大概步骤,有关hibernate对于字符串HQL的详细解析可以参照hibernate的hql.g文件
首先我们需要借助一个ANTLR的图形化编辑工具antlrworks-1.5.jar,这个jar可以使我们图形化编辑.g文件(本人理解.g文件为文法),可以实时验证语法、生成java语法解析类和此法解析类
下面是.g文法文件的主要代码:
grammar CustomHQL;
options{
output = AST;
ASTLabelType = CommonTree;
}
tokens{
SELECT = 'select';
DISTINCT='distinct';
FROM = 'from';
AS = 'as';
HQL;
FROMCLAUSE;
FROMRANGE;
TABLENAME;
TABLEALIAS;
TABLEFIELD;
SELECTCLAUSE;
SELECTRANGE;
CHILDTABLENAME;
SORTWAY;
}
@header {package mtpackage;}
@lexer::header{package mypackage;}
hql : selectClause* fromClause* ->^(HQL selectClause* fromClause*)
;
selectClause : SELECT DISTINCT? selectRange? (',' selectRange)* -> ^(SELECTCLAUSE SELECT DISTINCT? selectRange*)
;
selectRange : (tableAlias '.' (childTableName '.')?)? tableField -> ^(SELECTRANGE tableAlias? childTableName? tableField)
;
fromClause : FROM fromRange? (',' fromRange)* -> ^(FROMCLAUSE FROM fromRange*)
;
fromRange : tableName (AS? tableAlias)? -> ^(FROMRANGE tableName (AS? tableAlias)?)
;
tableName : ID -> ^(TABLENAME ID)
;
tableAlias : ID -> ^(TABLEALIAS ID)
;
tableField : ID -> ^(TABLEFIELD ID)
;
childTableName : ID -> ^(CHILDTABLENAME ID)
;
sort : SORT ->^(SORTWAY SORT)
;
SORT : ('asc' | 'desc')+;
ID : ('a'..'z' |'A'..'Z')+ ;
INT : '0'..'9' + ;
NEWLINE:'\r' ? '\n' ;
WS : (' ' |'\t' |'\n' |'\r' )+ {skip();} ;
开头的单词grammar关键字,用来定义文法的名字
option定义一些操作:输出为一个AST树,类型为CommonTree
tokens是我们自定义的一些标记,这里主要是一些关键字和占位符然后下面的是一个文法结构:这里hql节点后面只能有selectClause或fromClause 语句后面的箭头->是重写树规则,前面的文法结构式不会出现在树里面的,树的结构需要重新定义,关于树结构有两种写法,一种是直接在文法结构里面嵌套写,另外一种是在语句后面重写规则,这里采用第二种,这样有利于维护以上文法写好之后可以进行语法验证,看有没有错误:Gramat->Check Gramar 还可以在antlrworks-1.5.jar工作界面的interpreter界面写一些语句进行验证,如果执行可以生成树接表示文件正确,然后直接生成语法解析文件、文法解析文件和一个标记文件,生成这三个文件之后就可以在java里面使用了
使用主要代码如下
String hql = "select u.name, b.name.child from ConfigTable as eedc, InventTable as i, BatchTable";
CharStream charStream = new ANTLRStringStream(hql);
CustomHQL Lexer lexer = new CustomHQLLexer(charStream);
TokenStream tokenStream = new CommonTokenStream(lexer);CustomHQLParser parser = new CustomHQLParser(tokenStream);
CustomHQLParser.hql_return ret = parser.hql();CommonTree tree = ret.getTree();
到这里我们就已经得到一棵HQL树了
最后推荐一遍有关ANTLR入门文章http://www.oschina.net/question/12_16797