Python源码分析6 – 从CST到AST的转化

Introduction

上篇文章解释了Python是如何使用PyParser生成CST的。回顾一下,Python执行代码要经过如下过程:

1.     Tokenizer进行词法分析,把源程序分解为Token

2.     Parser根据Token创建CST

3.     CST被转换为AST

4.     AST被编译为字节码

5.     执行字节码

当执行Python代码的时候,以代码存放在文件中的情况为例,Python会调用PyParser_ASTFromFile函数将文件的代码内容转换为AST

mod_ty

PyParser_ASTFromFile(FILE *fp, const char *filename, int start, char *ps1,

                   char *ps2, PyCompilerFlags *flags, int *errcode,

                   PyArena *arena)

{

       mod_ty mod;

       perrdetail err;

       node *n = PyParser_ParseFileFlags(fp, filename, &_PyParser_Grammar,

                           start, ps1, ps2, &err, PARSER_FLAGS(flags));

       if (n) {

              mod = PyAST_FromNode(n, flags, filename, arena);

              PyNode_Free(n);

              return mod;

       }

       else {

              err_input(&err);

              if (errcode)

                     *errcode = err.error;

              return NULL;

       }

}

PyParser_ParseFileFlags把文件转换成CST之后,PyAST_FromNode函数会把CST转换成AST。此函数定义在include/ast.h:

PyAPI_FUNC(mod_ty) PyAST_FromNode(const node *, PyCompilerFlags *flags,

                             const char *, PyArena *);

在分析此函数之前,我们先来看一下有关AST的一些基本的类型定义。

AST Types

AST所用到的类型均定义在Python_ast.h中,以stmt_ty类型为例:

enum _stmt_kind {FunctionDef_kind=1, ClassDef_kind=2, Return_kind=3,

                  Delete_kind=4, Assign_kind=5, AugAssign_kind=6, Print_kind=7,

                  For_kind=8, While_kind=9, If_kind=10, With_kind=11,

                  Raise_kind=12, TryExcept_kind=13, TryFinally_kind=14,

                  Assert_kind=15, Import_kind=16, ImportFrom_kind=17,

                  Exec_kind=18, Global_kind=19, Expr_kind=20, Pass_kind=21,

                  Break_kind=22, Continue_kind=23};

struct _stmt {

        enum _stmt_kind kind;

        union {

                struct {

                        identifier name;

                        arguments_ty args;

                        asdl_seq *body;

                        asdl_seq *decorators;

                } FunctionDef;

               

                struct {

                        identifier name;

                        asdl_seq *bases;

                        asdl_seq *body;

                } ClassDef;

               

                struct {

                        expr_ty value;

                } Return;

 

                // ... 过长,中间从略              

               

                struct {

                        expr_ty value;

                } Expr;

               

        } v;

        int lineno;

        int col_offset;

};

 

typedef struct _stmt *stmt_ty;

stmt_ty是语句结点类型,实际上是_stmt结构的指针。_stmt结构比较长,但有着很清晰的Pattern

1.  第一个Fieldkind,代表语句的类型。_stmt_kind定义了_stmt的所有可能的语句类型,从函数定义语句,类定义语句直到Continue语句共有23种类型。

2.  接下来是一个union v,每个成员均为一个struct,分别对应_stmt_kind中的一种类型,如_stmt.v.FunctionDef对应了_stmt_kind枚举中的FunctionDef_Kind,也就是说,当_stmt.kind == FunctionDef_Kind时,_stmt.v.FunctionDef中保存的就是对应的函数定义语句的具体内容。

3. 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值