现在的位置: 首页 > 综合 > 正文

Hibernate中的Antlr

2013年06月21日 ⁄ 综合 ⁄ 共 3389字 ⁄ 字号 评论关闭
ANTLR(ANother Tool for Language Recognition)风头正盛,经常可以看到用它做语法解释器的项目,比如Hibernate就在3.0的时候换上它来解释HQL,使HQL的语法获得了加强。
     因为Antlr是EBNF-AST语法解释系的代表,而自己总是心思思想搞一下DSL(领域语言),所以从Hibernate来学习一下Antlr的应用。

     Antlr最好的介绍文章是那篇A Gentle Introduction to ANTLR Syntax,在《程序员》2004年3月有中文的版本。
     不过,那个计算器的例子太简单了,了解完基本原理后,还是要看看Hibernate的实战。
     另外,SlickEdit 支持Antrl的语法,是一定要用的编辑器,在 ttdown.com上有破解。

  一,Antlr引擎的工作过程大概是这样的:
  1.定义Lexer类,在类中定义各种Token如 From , Where,=,<>.......
         Lexer负责把读入的普通文本识别成Token串。

  2.定义Parser类,在类中使用BNF语法,递归定义各种句子,如whereStatement、FromStatement、Select Statement。
     Pattern负责把读入的Token串匹配成句子,翻译出AST(抽象语法树)
     有些简单的应用,也可以在本层现炒现卖,完成所有动作,属于Single Pass Builder。

  3.定义TreeParser类,根据Parser类分析出来的AST(抽象语法树)进行动作。
            用Parser把AST抽取出来,再用TreeParser进行动作的Double Pass Builder模式,解耦了Parser和Generation,再配合Template,是Antlr推荐的最佳模式。

  二,开发人员的实际步骤

  1.按照Antlr的简单语法定义前面讲的3个类,文件的后缀名为g

  2.使用java antlr.Tool xxx.g 命令 ,把grammar文件编译成java文件

  3.编写应用程序,如:

import antlr.*;
import antlr.collections.*;

public class Main {
public static void main(String[] args) throws Exception {
ExprLexer lexer = new ExprLexer(System.in);
ExprParser parser = new ExprParser(lexer);
parser.expr();
AST ast = parser.getAST();
ExprTreeParser treeParser = new ExprTreeParser();
int x = treeParser.expr(ast);
}
}

    三,Hibernate对Antlr的应用
     看Antlr对HQL的解释,觉得EBNF系的方法要解释Java这样的编程语言还好些,如果要解释类自然语言的DSL就比较痛苦,所以情绪不是很高涨,挑一条最容易的"Delete from goods where ....." 匆匆走过场。
    Joel的一句话对我的影响比较大:"如果为了证明一个微不足道的问题需要花三个小时写下几黑板的证明步骤,那么这种机制不可能用来证明任何有趣的东西" 。对于我这个层次的程序员,antlr在我手中造不出有趣的DSL来。

   Hibernate的HQL Grammar文件一共有三个,在/grammar目录下:
   1.hql.g   定义Token类和Parser类,将HQL解释成hql的抽象语法树(AST)
   2.hql-sql.g  定义Tree Walker ,将HQL AST转化为SQL AST,将生成模块与Hibernate解耦。
   3.sql-gen.g 定义Tree Walker,从SQL AST生成sql

   下面看 DELETE FROM GOODS的翻译过程

   1.HqlBaseLexer extends Lexer
     
定义EQ: "=";  LT: "<";  GT: ">";PLUS: "+";等符号
      及IDENT: ( "a" .. "z" | "_" ) ( "a" .. "z" | "0" .. "9" | "_" | "$" )*

   2.HqlBaseParser extends Parser
      先定义DELETE="delete"; FROM="from"; MIN="min"; 等字符串
      再定义:


      statement
          : ( updateStatement | deleteStatement | selectStatement )
          ; 三种Statement之一

      deleteStatement
         : DELETE^
           (optionalFromTokenFromClause)
           (whereClause)?
         ;DELETE为叶子,(whereClause)可选

      optionalFromTokenFromClause!
        : (FROM!)? f:path {
           AST #range = #([RANGE, "RANGE"], #f);
           #optionalFromTokenFromClause = #([FROM, "FROM"], #range);
          }
         ;不是很好懂对吧,我也这样觉得,whereClause就更加不要看了。

     3. HqlSqlBaseWalker extends TreeParser  
         hql与sql的delete语句基本上是一样的,没什么转换。

     4.SqlGeneratorBase extends TreeParser
          
         根据SQL AST, 生成SQL语句

          private StringBuffer buf = new StringBuffer();
          protected void out(String s) 
          {
                buf.append(s);
          }

          statement
          : selectStatement | updateStatement | deleteStatement
          ;
         deleteStatement
         : #(DELETE { out("delete"); }
               from
              (whereClause)?
             )
         ;输出"delete"
          from
          : #(f:FROM { out(" from "); }
           (fromTable)* )
           ;
         fromTable
         : #( a:FROM_FRAGMENT  { out(a); } (tableJoin [ a ])* { fromFragmentSeparator(a); } )
         | #( b:JOIN_FRAGMENT  { out(b); } (tableJoin [ b ])* { fromFragmentSeparator(b); } )
         ;
         tableJoin [ AST parent ]
          : #( c:JOIN_FRAGMENT { out(" "); out(c); } (tableJoin [ c ] )* )
          | #( d:FROM_FRAGMENT { nestedFromFragment(d,parent); } (tableJoin [ d ] )* )
         ;

         ................晕了吧 ~~~~~
         whereClause
          : #(WHERE { out(" where "); } ( conditionList | booleanExpr[ false ] ) )
          ;

 

抱歉!评论已关闭.