版本整理日期:/3/27
对lmathlib.c文件中的函数进行跟调。函数是那个不重要,这里选取math_abs
/*lmathlib.c取出一个TValue,转成整型,然后fabs处理。TValue可能是字符串,也可能就是数字。luaL_checknumber的行为是必返回一个number值lua_pushnumber的行为是把结果进行压栈处理,具体怎么处理还不知道return 1;表示参数个数。有做过lua和c交互的就很熟悉了,表示结果的个数可以得到的信息是,lua通过push参数+个数来表示结果的传递*/static int math_abs (lua_State *L) {//luaL_checknumber 见1.1//lua_pushnumber见1.2lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));return 1;}
/*1.1lauxlib.c调用lua_tonumber,并且对参数进行一个检测,可以看成是一个辅助性的函数*/LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {//lua_tonumber见1.1.1lua_Number d = lua_tonumber(L, narg);if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */tag_error(L, narg, LUA_TNUMBER);return d;}
/*1.1.1lapi.c观察是怎么取出一个值的.其中index2adr,tonumber等都是很常见的函数,不做单独的段落分析,统一放在末尾一起分析*/lua_tonumber(){//从栈上取出一个TValue变量const TValue *o = index2adr(L, idx);//一个宏转换,是否是number类型if (tonumber(o, &n))//从TValue里取出值return nvalue(o);else//失败返回0return 0;}
/*1.1.1宏整理都用到了以下这些宏*///lobject.h#define nvalue(o)check_exp(ttisnumber(o), (o)->value.n)#define ttisnumber(o)(ttype(o) == LUA_TNUMBER)//lvm.h#define tonumber(o,n)(ttype(o) == LUA_TNUMBER || \(((o) = luaV_tonumber(o,n)) != NULL))
这些宏都是对TValue进行操作,来看TValue结构,可以得到的信息是
1)TValue是lua通用的描述数据元的结构体
2)里面是通过tt来区分类型
3)typedef union Value里面,根据不同类型需要存放的对应变量
/*** Union of all Lua values*/typedef union {//gc先不管它GCObject *gc;//存放字符型空间void *p;//值double型lua_Number n;int b;} Value;//tt:值类型#define TValuefieldsValue value; int tt typedef struct lua_TValue {TValuefields;} TValue;
再回头看上面的宏,要注意的是tonumber,会先判断是否是LUA_TNUMBER,然后再进行转换。
我们跟踪下luaV_tonumber
/*lvm.c*/const TValue *luaV_tonumber (const TValue *obj, TValue *n) {lua_Number num;//判断是否数字型//如果是字符型进行转换if (ttisnumber(obj)) return obj; //一个V值的转换,svalue表示取出字符串的char*空间if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {setnvalue(n, num);return n;}elsereturn NULL;}
//先整理下用到的宏//lobject.h//根据里面的tt类型来判断,还有诸如很多的判断字符串,表格等#define ttisnumber(o)(ttype(o) == LUA_TNUMBER)//返回字符串空间,其中的层次组织很值得学习。raw->get->svalue#define svalue(o) getstr(rawtsvalue(o))#define getstr(ts)cast(const char *, (ts) + 1)#define rawtsvalue(o)check_exp(ttisstring(o), &(o)->value.gc->ts)//也是经常遇到的宏之一,包括一些对象的互相赋值等#define setnvalue(obj,x) \{ TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
//lobject.h//该函数主要就是调用了C标准函数库int luaO_str2d (const char *s, lua_Number *result) {char *endptr;//luaconf.h, #define lua_str2number(s,p)strtod((s), (p)), strtod,C函数库*result = lua_str2number(s, &endptr);if (endptr == s) return 0; /* conversion failed */if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */*result = cast_num(strtoul(s, &endptr, 16));if (*endptr == '\0') return 1; /* most common case */while (isspace(cast(unsigned char, *endptr))) endptr++;if (*endptr != '\0') return 0; /* invalid trailing characters? */return 1;}
//limits.h//cast转换函数,也是经常用到的#ifndef cast#define cast(t, exp)((t)(exp))#endif#define cast_byte(i)cast(lu_byte, (i))#define cast_num(i)cast(lua_Number, (i))#define cast_int(i)cast(int, (i))
/*1.2lapi.clua_pushnumber*/LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {lua_lock(L);setnvalue(L->top, n);api_incr_top(L);lua_unlock(L);}//lobject.h#define setnvalue(obj,x) \{ TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
这里对L->top很感兴趣,结合index2adr一起分析下
//lapi.cstatic TValue *index2adr (lua_State *L, int idx) {if (idx > 0) {TValue *o = L->base + (idx - 1);api_check(L, idx <= L->ci->top - L->base);if (o >= L->top) return cast(TValue *, luaO_nilobject);else return o;}else if (idx > LUA_REGISTRYINDEX) {api_check(L, idx != 0 && -idx <= L->top - L->base);return L->top + idx;}else switch (idx) { /* pseudo-indices */case LUA_REGISTRYINDEX: return registry(L);case LUA_ENVIRONINDEX: {Closure *func = curr_func(L);sethvalue(L, &L->env, func->c.env);return &L->env;}case LUA_GLOBALSINDEX: return gt(L);default: {Closure *func = curr_func(L);idx = LUA_GLOBALSINDEX - idx;return (idx <= func->c.nupvalues)? &func->c.upvalue[idx-1]: cast(TValue *, luaO_nilobject);}}}
先不具体去追究里面意思,可以知道这么几个信息
1)根据idx不同,可以取到不同的目标,而且idx可以是全局的
2)top其实是个连续的栈信息
3)L->ci似乎是个监测边界的东西
4)Closure的东西,有其他的存储方式
OK,到这,起码可以了解lua库的调用流程和思考方式习惯,再把各个调用函数对应的文件流程
整理下:
lmathlib.c(math_abs)
lauxlib.c(luaL_checknumber)
lapi.c(lua_tonumber,lua_isnumber)
lapi.c(index2adr)
lvm.h(tonumber)
lvm.h(luaV_tonumber)
lobject.h(luaO_str2d)
luaconf.h(lua_str2number)
可以得到如下信息:
1)luaX_,X可以表示lvm,lobject等
2)api.c表示lua内部的函数,lib库是对外开放的
3)lobject.h,luaconf.h是最基础的结构文件