AST解释执行
来源:互联网 发布:淘宝售后的服务流程 编辑:程序博客网 时间:2024/05/01 07:11
语法和语义分析的结果是抽象语法树AST,再往后编译原理还有代码生成及优化的很大一部分,但如果只是做一个执行器,到AST为止就可以解释执行了,当然就算不生成AST,解析执行也可以,只是基于之前说过的原因,极少采用解析执行的方式
目前的大多数解释执行的语言,都是在虚拟机解释字节码执行,这个后面再说,它只是把AST的解释串行化了而已,事实上ruby在1.9版本之前是解释AST执行的,到1.9整合了YARV才改成了解释字节码
抽象地看,一个高级语言的AST就是一个stmt_list,语法分析过程只是把人能看懂的语言转成方便解释器看懂的罢了,具体的执行过程和人阅读代码没什么差别,就是一个个stmt执行过去,前面讲过stmt的接口类的样子:
这个RetType后面再细说,形式上可以认为一个解释器的架构就是:
因此,核心部分在于实现各个stmt的execute部分,为简单起见,我们讨论动态类型语言,所有变量类型都是用Object,这里还需要一个expr的接口:
静态类型的情况虽然会复杂点,但也不难想到
于是很容易写出前面StmtPrint的execute方法(方便起见代码主要用类似java形式,不过不一定和java语法契合):
然后考虑StmtWhile的execute方法:
在这里,出现了嵌套语句列表,相应地递归调用execute_stmt_list解释执行,这里需要解释下RetType的含义,根据具体的语法,一个语句块返回一般有以下几种情况:运行结束,break,continue,return,异常。而RetType则对应这几种,那么显然上面//...的内容差不多是这样:
return和异常直接往上面一层返回,因为while本身是在一个函数或try中,让上层来处理即可,另外,return的返回值和异常的内容应该已经存在某个地方了,不过这个在上面的伪代码里面没有体现,它属于运行时环境的范畴,后面再说
expr的compute方法的实现,差不多都是类似的,先计算各个操作数,然后最后做当前对象的运算,比如加法:
递归调用元素的compute,当然这个递归不会无限下去,最后都会停止于一个load操作:
其中env是运行时环境的一个抽象,简单说就是根据a的内容返回对应的对象即可,这个load操作一般会根据名字空间细化为几种,比如LoadLocal,LoadGlobal,LoadConst,表示从局部变量区,全局区,常量区
特殊点的,函数调用expr:
这个实现稍微丑陋了点,其实可以改成f.execute(...)更直观些,另外这里的execute_stmt_list_with_frm以及ret_value存在栈帧里面只是表个意思,实际不一定这么实现
目前的大多数解释执行的语言,都是在虚拟机解释字节码执行,这个后面再说,它只是把AST的解释串行化了而已,事实上ruby在1.9版本之前是解释AST执行的,到1.9整合了YARV才改成了解释字节码
抽象地看,一个高级语言的AST就是一个stmt_list,语法分析过程只是把人能看懂的语言转成方便解释器看懂的罢了,具体的执行过程和人阅读代码没什么差别,就是一个个stmt执行过去,前面讲过stmt的接口类的样子:
class Stmt { RetType execute(); }
这个RetType后面再细说,形式上可以认为一个解释器的架构就是:
RetType execute_stmt_list(StmtList stmt_list) { for stmt in stmt_list //就是遍历,这里用伪代码 { RetType ret = stmt.execute(); //处理RetType,后面讲 } }
因此,核心部分在于实现各个stmt的execute部分,为简单起见,我们讨论动态类型语言,所有变量类型都是用Object,这里还需要一个expr的接口:
class Expr { Object compute(); }
静态类型的情况虽然会复杂点,但也不难想到
于是很容易写出前面StmtPrint的execute方法(方便起见代码主要用类似java形式,不过不一定和java语法契合):
Object a = this.e.compute(); System.out.println(a); return RET_TYPE_NORMAL;
然后考虑StmtWhile的execute方法:
while (this.condition.compute().as_bool()) //因为是动态类型,as_bool将Object转为布尔型,和宿主语言契合 { RetType ret = execute_stmt_list(this.stmt_list); //... }
在这里,出现了嵌套语句列表,相应地递归调用execute_stmt_list解释执行,这里需要解释下RetType的含义,根据具体的语法,一个语句块返回一般有以下几种情况:运行结束,break,continue,return,异常。而RetType则对应这几种,那么显然上面//...的内容差不多是这样:
switch (ret) { case RET_TYPE_NORMAL: case RET_TYPE_CONTINUE: continue; case RET_TYPE_BREAK: break; //这里的意思是跳出while循环,不是switch case RET_TYPE_RETURN: return RET_TYPE_RETURN; case RET_TYPE_EXCEPTION: return RET_TYPE_EXCEPTION; }
return和异常直接往上面一层返回,因为while本身是在一个函数或try中,让上层来处理即可,另外,return的返回值和异常的内容应该已经存在某个地方了,不过这个在上面的伪代码里面没有体现,它属于运行时环境的范畴,后面再说
expr的compute方法的实现,差不多都是类似的,先计算各个操作数,然后最后做当前对象的运算,比如加法:
class ExprAdd { Expr a; Expr b; Object compute() { return a.compute().add(b.compute()); } }
递归调用元素的compute,当然这个递归不会无限下去,最后都会停止于一个load操作:
class ExprLoad { LoadArg a; Object compute() { return env.get(a); } }
其中env是运行时环境的一个抽象,简单说就是根据a的内容返回对应的对象即可,这个load操作一般会根据名字空间细化为几种,比如LoadLocal,LoadGlobal,LoadConst,表示从局部变量区,全局区,常量区
特殊点的,函数调用expr:
class ExprCallFunc { Func f; ExprList arg_list; Object compute() { frm = f.init_frame(compute_expr_list(arg_list)); //初始化函数调用栈 RetType ret = execute_stmt_list_with_frm(f.stmt_list, frm); assert ret == RET_TYPE_RETURN; return frm.ret_value; } }
这个实现稍微丑陋了点,其实可以改成f.execute(...)更直观些,另外这里的execute_stmt_list_with_frm以及ret_value存在栈帧里面只是表个意思,实际不一定这么实现
0 0
- AST解释执行
- AST
- ast
- AST
- Atitit.软件开发的最终的设计 dsl化,ast化(建立ast, 解析执行ast)
- 解释执行与编译执行
- 解释执行与编译执行
- 编译执行与解释执行
- 解释执行和编译执行
- 编译执行和解释执行
- 解释执行和编译执行
- .Net应用程序执行解释
- Oracle执行计划解释
- Python解释执行原理
- sql解释执行顺序
- oracle执行计划解释
- SQL解释执行顺序
- Oracle 解释执行计划
- No.2 -->包装类的简单介绍及包装类的应用
- 粗浅谈论makefile
- MySQLWorkbench报Error Code 1175
- C语言第三天
- 噶发的萨芬撒分撒
- AST解释执行
- 低版本手机浏览器不支持position: fixed的解决方法
- Linux常用命令(2):vi
- 栈虚拟机字节码
- java学习篇(四)---浅谈JUnit 3.8
- ios AES128加密解密算法
- ProtelDXP高级功能
- githubgrep
- linux下检测网卡与网线连通状态