转换器5:参考Python源码,实现Php代码转Ast并直接运行
前两个周末写了《手写PHP转Python编译器》的词法,语法分析部分,上个周末卡文了。
访问器部分写了两次都不满意,没办法,只好停下来,参考一下Python的实现。我实现的部分正好和Python是一个思路,就是生成CST(Concrete syntax tree)之后,再生成AST。由于我想创(tou)新(lan),所以未没有详细实现AST,而想绕过AST去生成代码。这下有点欲速不达了。
先看看Python执行代码的过程:
1. Tokenizer进行词法分析,把源程序分解为Token
2. Parser根据Token创建CST
3. 将CST转换为AST
4. 将AST编译为字节码
5. 执行字节码
现在我们要实现第3步。参考一下Python源码:
/* Transform the CST rooted at node * to the appropriate AST*/ mod_ty PyAST_FromNode(const node *n, PyCompilerFlags *flags, const char *filename, PyArena *arena)
这是将CST转换为AST的入口,Node就是CST的节点。而下一步处理的函数为ast_for_stmt。
在ast_for_stmt里面,根据语法定义表,由各子函数生成AST的节点。例如函数调用:ast_for_call最后生成了这样的结构
Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena);
而这个C语言的函数与Python的AST库接口一模一样。
我们来看一个AST库的例子
import ast expr = """ def hello(name='world'): print("hello " + name) hello() """ expr_ast = ast.parse(expr) print(ast.dump(expr_ast)) exec compile(expr_ast, '<string>', 'exec')
运行后的结果:
Module( body=[ FunctionDef( name='hello', args=arguments(args=[Name(id='name', ctx=Param())], vararg=None, kwarg=None, defaults=[Str(s='world')]), body=[ Print(dest=None, values=[BinOp(left=Str(s='hello '), op=Add(), right=Name(id='name', ctx=Load()))], nl=True)], decorator_list=[]), Expr(value=Call(func=Name(id='hello', ctx=Load()), args=[], keywords=[], starargs=None, kwargs=None))]) hello world
注意结果中的Call(func=Name(id='hello', ctx=Load()), args=[], keywords=[], starargs=None, kwargs=None)
为了更好的说明问题,我们来为AST增加一条函数调用
import ast expr = """ def hello(name='world'): print("hello " + name) hello() """ expr_ast = ast.parse(expr) n = ast.Name('hello', ast.Load(), lineno=5, col_offset=0) p = ast.Str('windfic', lineno=5, col_offset=0) c = ast.Call(n,[p]运行后,结果为, [], None, None, lineno=5, col_offset=0) e = ast.Expr(c, lineno=5, col_offset=0) expr_ast.body.append(e) exec compile(expr_ast, '<string>', 'exec')
hello world hello windfic
就这样,我们已经可以直接生成一个AST结构,并且运行了。
以前,我一直是想先由Php生成AST,再生成Python代码。但是突然发现,我们不必生成代码了,可以直接生成兼容Python的AST结构,并且可以在Python中直接运行。
而Python的语法定义也不算很大,在Python文档中已经完整列出了
1 module Python version "$Revision$" 2 { 3 mod = Module(stmt* body) 4 | Interactive(stmt* body) 5 | Expression(expr body) 6 7 -- not really an actual node but useful in Jython's typesystem. 8 | Suite(stmt* body) 9 10 stmt = FunctionDef(identifier name, arguments args, 11 stmt* body, expr* decorator_list) 12 | ClassDef(identifier name, expr* bases, stmt* body, expr* decorator_list) 13 | Return(expr? value) 14 15 | Delete(expr* targets) 16 | Assign(expr* targets, expr value) 17 | AugAssign(expr target, operator op, expr value) 18 19 -- not sure if bool is allowed, can always use int 20 | Print(expr? dest, expr* values, bool nl) 21 22 -- use 'orelse' because else is a keyword in target languages 23 | For(expr target, expr iter, stmt* body, stmt* orelse) 24 | While(expr test, stmt* body, stmt* orelse) 25 | If(expr test, stmt* body, stmt* orelse) 26 | With(expr context_expr, expr? optional_vars, stmt* body) 27 ...
想要完整实现Php的CST转Python的AST还需要一些时间,先来一个例子吧demo.php
<?php function hello($name='world'){ echo 'hello ' . $name; } hello();
if __name__ == '__main__': CompilerPhp().compile_file('src/demo.php').execute()
运行上面的例子,结果与Python版本的例子完全一样。
试着用Unparse生成代码,也一切正常,唯一要说的,就是编码问题,不能使用Unicode。
以上
这个项目到现在差不多有三个星期的狂热编码,做到现在也已经完全和最初的设想是两码事了。最核心及最难的部分,都已经完成。是时候休整一段时间了。最后再啰嗦几句。
很多人可能还不了解这个项目的价值所在,或者说我想输出的价值在哪里。这个项目实际上是一种廉价编译器的试验品。廉价编译器,意味着我们可以很轻易地扩充支持的语言,比如所有的主流语言。这个不难。做到了这一步,我们可以想像一下,这个工具的价值在哪里。至少有三种后续的可能:
1、还是Transpiler,就是这个项目。
2、源码阅读器。
3、源码(片段)管理、搜索、自动生成工具。
转载于:https://www.cnblogs.com/windfic/p/6594791.html
- 点赞
- 收藏
- 分享
- 文章举报
- PHPstorm实现PHP代码直接运行,并动态更新服务器代码
- 在notepad++中实现直接运行python代码
- 使用PHP实现密保卡功能实现代码<打包下载直接运行>
- 利用PHP安装windows自动运行的服务,PHP程序可以实现长时间、自动运行、定时更新功能,直接可以用在项目中的类源代码
- 使用PHP实现密保卡功能实现代码<打包下载直接运行>
- PHPstorm实现PHP代码直接运行,并动态更新服务器代码
- 利用PHP安装windows自动运行的服务,PHP程序可以实现长时间、自动运行、定时更新功能,直接可以用在项目中的类源代码...
- 介绍两种方法来实现不用开浏览器就能运行php代码的方法
- 内存数据库内核开发 工作日志(内存索引实现原理)(附红黑树实现清晰完整直接可编译运行代码)(十)
- python程序运行进程、使用时间、剩余时间显示功能的实现代码
- 翻译文章“AST 模块:用 Python 修改 Python 代码”---!!注意ironpathyon未实现此功能
- php实现有序数组打印或排序的方法【附Python、C及Go语言实现代码】
- 代码在线运行工具(PHP、Python、Java等)
- asp下实现代码的“运行代码”“复制代码”“保存代码”功能源码
- PHP + PYTHON 多任务多线程,后台运行,计划任务-实现方法
- redis实战中的python代码用php实现
- 100行Python代码实现自动抢火车票(附源码)
- 用python实现多目标差分进化算法(MODE)完整代码,自己写的,简单易懂,可以直接跑
- [PHP征文] 怪咖方式实现php代码后台运行
- 无需操作系统和虚拟机,直接运行Python代码