精华帖 (2) :: 良好帖 (12) :: 新手帖 (2) :: 隐藏帖 (3)
|
|
---|---|
作者 | 正文 |
发表时间:2009-06-07
最后修改:2009-06-13
http://www.iteye.com/topic/405561 前几天做动态表单的时候老总给了我一个好东东:Antlr 为什么说Antlr是好东东呢?因为他很有意思 今天琢磨了1天,搞了个简单的小东西 目标:设计自己的脚本语言 先说说为啥要设计自己的脚本语言。 举一个例子: 在数据仓库领域,我们在做ETL的时候往往会从A地方取的一堆数据,加工后塞到B地方。 我们可以用java写个程序让后编译运行,让它来做这个事。 或者,我们更希望能简单点,比方说写个脚本 $source:url="jdbc:hsqldb:mem:Test",table="DB1" $target:url="jdbc:hsqldb:mem:Test2",table="DB2" #copy{ $target.First_Name=$source.First_Name $target.Last_Name=$source.Last_Name $target.Address=$source.Address } 这个脚本一看就能懂吧,从一个库把数据拷到另一个库,是不是很简单 ?:D 不过问题来了,脚本写出来了,但是我们怎么运行它呢?JavaCompiler貌似不认识这个东西。 好吧,那我们自己来做一个编译器和运行器。 不要惊讶,这并不是一个很复杂困难的工作 第一步:构建脚本编译器 理论上来说,这一步实际上是很复杂的,牵涉到递归下降,词法分析,语法分析等等好多事情,不过好在有Antlr这个东西作为我们实现编译器的基础,让我们这些不是很精通编译原理的人也能做出编译器来。 Antlr的资料网上还是很多的。 第二步:构建脚本的运行环境 脚本的运行是需要有一个上下文环境的,比方说 $source:url="jdbc:hsqldb:mem:Test",table="DB1" <script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/themes/advanced/langs/zh.js"></script><script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/plugins/javaeye/langs/zh.js"></script>在这里,脚本中声明了一个数据源source,当我们编译脚本的时候,也需要在上下文对象(Context)中配置一个数据源对象。 看到这里,一定感觉Context的意义很抽象,先别急。 第三部:脚本的运行方式 在Antlr的帮助下,我们可以做到对于脚本的直接解释运行的,不过这里我想用另外的一种方式 将脚本转义成Java代码,然后把Java代码拷贝到一个实现准备好的模板Java类的某个方法里,然后动态编译加载这个Java类,并运行该方法 编译前的脚本 #copy{ $target.First_Name=$source.First_Name $target.Last_Name=$source.Last_Name $target.Address=$source.Address } 这段脚本编译后变成了 String sql1 = "SELECT First_Name,Last_Name,Address FROM DB1"; String sql2 = "INSERT INTO DB2 (First_Name,Last_Name,Address) VALUES ("; ResultSet rs = sourceStm.executeQuery(sql1); while (rs.next()) { targetStm.execute(sql2 + "'" + rs.getString("First_Name") + "'" + "," + "'" + rs.getString("Last_Name") + "'" + "," + "'" + rs.getString("Address") + "'" + ")"); } 只是写个例子,所以这段sql比较笨,不过这不是重点。 之后,把上面这段代码拷贝到下面 public class RuntimeTemplate { public void execute() throws Exception { System.out.println("开始执行"); /* start */ /* end */ System.out.println("执行完毕"); } } 就像这样,把转义好的代码拷贝到/* start */和/* end */之间。 之所以这样画蛇添足,是出于两点考虑: 1.性能问题。 2.由于这些代码是被拷贝到Java类中的,所以对于很多脚本本身不能满足的功能,可以直接在脚本中写Java代码,编译时候直接复制过去,这样很方便:D 动态编译也很简单,两行代码的事 JavaCompilerTool compiler = ToolProvider.getSystemJavaCompilerTool(); compiler.run(null, null, null, "etl/Runtime.java"); 然后重写一下ClassLoader,加载编译后的class文件,最后运行 Object obj = clz.newInstance(); clz.getMethod("init", new Class[] { Context.class }).invoke(obj, ctx); clz.getMethod("execute", new Class[] {}).invoke(obj); 在这里,把之前准备好的Context对象传给了脚本运行对象。 OK,这样就搞定了基本的工作流程。 ######################################################################## 目前已经有了一定的进展,可以解释如下的脚本 $source : url = "jdbc:hsqldb:mem:Test", table = "DB1" $target : url = "jdbc:hsqldb:mem:Test", table = "DB2" $target.FIRST_NAME = $source.FIRST_NAME + "ABC" $target.LAST_NAME = $source.LAST_NAME + 123.456 $target.FULL_NAME = $source.FIRST_NAME + $source.LAST_NAME $target.ADDRESS = $source.ADDRESS if( "ss"+"aa"=="ssaa" or (1+1!=2 and 1+1>=2) ){ if( $source.FIRST_NAME == "name1" ){ #copy } } 附件是SRC LIB比较大,自行下载Antlr3.1.2 http://www.antlr.org/download.html 测试用的DB是h2sql 需求:JDK1.6(1.6可以直接调用CompilerTool,不用调外部exe了,本人比较懒 ) 注意是JDK1.6,JRE不行,而且有的JDK中的类名是JavaCompilerTool,有的是JavaCompile,根据自身情况改下。 还差一个数据库字段类型转换没做,现在所有数据库字段类型都当做String来处理 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-06-08
http://www.antlr.org/
Antlr的项目主页,有兴趣可以看看 |
|
返回顶楼 | |
发表时间:2009-06-08
不错,希望楼主说明一下这个东西,你再动态表单上的用法,我也想学习学习!!!
|
|
返回顶楼 | |
发表时间:2009-06-08
Hibernate的hql是用这个东西做的语法分析,有兴趣深入了解,可以参考一下Hibernate的源代码.
|
|
返回顶楼 | |
发表时间:2009-06-09
简单扼要的文章呀,赞一个。
虽说老大要求用这个东西,不过个人感觉还是Groovy之类的脚本语言更适合。LZ有空和我一起研究研究吧。 |
|
返回顶楼 | |
发表时间:2009-06-09
Groovy之前我也提过啊,LS的在这里发现我了可要低调啊 哈哈哈
|
|
返回顶楼 | |
发表时间:2009-06-09
晕倒,,我点收藏的,点成隐藏帖了,不好意思。
|
|
返回顶楼 | |
发表时间:2009-06-09
哈哈,楼上更搞笑哦!!!
|
|
返回顶楼 | |
发表时间:2009-06-10
最后修改:2009-06-10
==,楼主不是要做直接的运行程序,而是要做源码到源码的代码生成(这话用中文说怎么这么别扭……source-to-source code generation),这样的话ANTLR+StringTemplate虽然是Terence Parr很推荐的方式,但要这么用的话其实还有另外一种非常方便的工具:JetBrains的MPS。比起ANTLR,这个工具应更适合楼主的需求,它对编译原理之类的知识的要求更低,而且能更方便的做源码生成,外加可以很方便的生成出你的DSL对应的编辑器
MPS是免费的工具,官网上也有些视频教程,应该能很快上手……吧。 更新:刚到官网去试下新的版本,怪哉……我下载不到那安装包。jetbrains.com能连上,但是download.jetbrains.com连不上。有墙外的人能试试么? 现在下载不到MPS的安装包,不过楼主或许会有兴趣看看官网上的视频来感受一下它会不会比ANTLR更合适。我找找看以前下的版本还在不在…… |
|
返回顶楼 | |
发表时间:2009-06-10
ToolProvider.getSystemJavaCompilerTool is Java SE6 stuff.
|
|
返回顶楼 | |