(更新src)构建编译器,设计自己的脚本语言

相关贴
[url]http://www.iteye.com/topic/405561[/url]

前几天做动态表单的时候老总给了我一个好东东: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貌似不认识这个东西。 :x
好吧,那我们自己来做一个编译器和运行器。 :idea:

不要惊讶,这并不是一个很复杂困难的工作

第一步:构建脚本编译器

理论上来说,这一步实际上是很复杂的,牵涉到递归下降,词法分析,语法分析等等好多事情,不过好在有Antlr这个东西作为我们实现编译器的基础,让我们这些不是很精通编译原理的人也能做出编译器来。 :D
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来处理
MsCode脚本编译器教程 程序编:汪京苑/教程编:汪京苑/论坛昵称:幕夜流星/联系QQ:420452913 MsCode脚本编译器脚本录制步骤(以迅雷为例): 1.录制新脚本 点击录制新脚本。 2.软件配置 这里的软件名称没有任何讲究,随便输入。 点击选择指定安装程序的路径,然后点击下一步。 3.脚本录制 比如我想点击下一步这个按钮,那就先把鼠标移到下一步这个按钮前,记住只是移到按钮前,并不是点击这个按钮,然后按Home键获取该控件的信息。 当提示已经获取控件句柄,请选择执行命令的时候就表示编译器已经获取了该控件的信息,接下来选择你要进行的操作,比如你想点击该控件就点击单击控件,编译器就会自动执行你的命令。 看,你只是点击了单击控件,编译器就自动点击了程序上你想要点击的那个按钮,如果你想要点击我同意此协议那个选择框,只要重复上述的步骤,先把鼠标移到我同意此协议选择框前按Home键获取该控件的信息,然后点击单击控件,编译器就会自动记录该步骤并执行你的命令。 如果你想要更改安装路径,那么就先把鼠标移到安装路径所在的那个编辑框前按Home键获取该控件的信息。 然后点击更改控件内容,在弹出的输入框里输入新的安装路径,点击确认输入,编译器就会自动记录该步骤并执行你的命令,其他程序比如WinRAR在安装完成后会弹出一个名为WinRAR的文件夹,这时你可以把鼠标移到文件夹的标题前按Home键获取该控件的信息,然后点击关闭窗口,编译器就会自动记录该步骤并执行你的命令,最后如果安装结束点击下一步封装脚本,封装成功后就可以回到编译器主窗口去点击执行脚本来看看效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值