本文共 2622 字,大约阅读时间需要 8 分钟。
在tinypy中,函数分三类
1. 内置函数(或者说C函数,builtin-function) 2. python函数,包括python的方法 3. 对象的实例化方法typedef struct tp_fnc_ { int type; struct _tp_fnc *info; int ftype; void *val;} tp_fnc_;typedef struct _tp_fnc { int gci; tp_obj self; tp_obj globals;} _tp_fnc;
从结构体可以看出来一个函数包括如下成员变量
/* TP是一个宏,具体内容如下,实际上就是一个虚拟机的结构体,函数并没有用到。 */#define TP tp_vm *tpvoid _tp_call(TP,tp_obj *dest, tp_obj fnc, tp_obj params) { /* 对象的实例化 */ if (fnc.type == TP_DICT) { _tp_call(tp,dest,tp_get(tp,fnc,tp_string("__call__")),params); return; } /* 调用C函数 */ if (fnc.type == TP_FNC && !(fnc.fnc.ftype&1)) { *dest = _tp_tcall(tp,fnc); tp_grey(tp,*dest); return; } /* 调用Python函数 */ if (fnc.type == TP_FNC) { tp_frame(tp,fnc.fnc.info->globals,(tp_code*)fnc.fnc.val,dest); /* 方法调用的参数处理,在python中调用对象方法时self参数是不写的,实际上还是需要传给函数 */ if ((fnc.fnc.ftype&2)) { tp->frames[tp->cur].regs[0] = params; _tp_list_insert(tp,params.list.val,0,fnc.fnc.info->self); } else { tp->frames[tp->cur].regs[0] = params; } return; } tp_params_v(tp,1,fnc); tp_print(tp); tp_raise(,"tp_call: %s is not callable",TP_CSTR(fnc));}.
C函数的处理比较简单,直接调用C的函数指针。
/* 执行C函数 */tp_obj _tp_dcall(TP,tp_obj fnc(TP)) { return fnc(tp);}/* 调用C函数 */tp_obj _tp_tcall(TP,tp_obj fnc) { /* 方法调用的参数处理,在python中调用对象方法时self参数是不写的,实际上还是需要传给函数 */ if (fnc.fnc.ftype&2) { _tp_list_insert(tp,tp->params.list.val,0,fnc.fnc.info->self); } return _tp_dcall(tp,(tp_obj (*)(tp_vm *))fnc.fnc.val);}
这里需要给出函数栈的结构体
typedef struct tp_frame_ { tp_code *codes; tp_code *cur; tp_code *jmp; tp_obj *regs; /* 局部变量 */ tp_obj *ret_dest; /* 返回值指针 */ tp_obj fname; tp_obj name; tp_obj line; tp_obj globals; /* 模块的全局变量 */ int lineno; int cregs;} tp_frame_;
从代码中可以看出,python函数是新构建了一个调用栈,然后会返回到解释器循环进行执行。这里有一个问题,函数执行完了怎么返回呢?tinypy有一个返回机制。
void tp_return(TP, tp_obj v) { tp_obj *dest = tp->frames[tp->cur].ret_dest; if (dest) { *dest = v; tp_grey(tp,v); } memset(tp->frames[tp->cur].regs,0,tp->frames[tp->cur].cregs*sizeof(tp_obj)); tp->cur -= 1;}
可以看出,虚拟机在执行return的时候给该函数栈的ret_dest
指针的指向值赋值了,而在调用的时候就指定了ret_dest
的值,这样返回的时候就已经赋值好了。
对象的实例化实际上直接把字典当成函数来调用(在tinypy里类的本质就是字典,其实python也是这样),实例化的时候先从字典中取出__call__
方法,然后调用它。这里有点类似于python的函数调用,在python中,func(args)
等价于func.__call__(args)
>>> chr>>> chr.__call__ >>> chr(0x30)'0'>>> chr.__call__(0x30)'0'
转载地址:http://vtuws.baihongyu.com/