打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
转换器5:参考Python源码,实现Php代码转Ast并直接运行

转换器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_tyPyAST_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 astexpr = """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 astexpr = """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 worldhello 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

<?phpfunction hello($name='world'){    echo 'hello ' . $name;}hello();
if __name__ == '__main__':    CompilerPhp().compile_file('src/demo.php').execute()

运行上面的例子,结果与Python版本的例子完全一样。

试着用Unparse生成代码,也一切正常,唯一要说的,就是编码问题,不能使用Unicode。

以上

源码:converterV0.5.zip

 

这个项目到现在差不多有三个星期的狂热编码,做到现在也已经完全和最初的设想是两码事了。最核心及最难的部分,都已经完成。是时候休整一段时间了。最后再啰嗦几句。

很多人可能还不了解这个项目的价值所在,或者说我想输出的价值在哪里。这个项目实际上是一种廉价编译器的试验品。廉价编译器,意味着我们可以很轻易地扩充支持的语言,比如所有的主流语言。这个不难。做到了这一步,我们可以想像一下,这个工具的价值在哪里。至少有三种后续的可能:

1、还是Transpiler,就是这个项目。

2、源码阅读器。现在的主流阅读器还是15年前SourceInsight3.5,多年的停滞让需求已经在爆发的边缘。

3、源码(片段)管理、搜索、自动生成工具。Snippet管理需要编译器,一个无法理解源码的源码管理器,是不合格的。

以上,感兴趣的同学可以留言或发邮件给我:windfic@qq.com

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
走进Python: 为Python增加新语法
教你阅读CPython的源码
php
php入门(1)
译|Python幕后(2):CPython编译器原理
Python优化机制:常量折叠
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服