lua5.3源码基础阅读(luaL_openlibs)
来源:互联网 发布:淘宝女士小包包 编辑:程序博客网 时间:2024/05/16 14:55
###C库结构和导入到lua
导入全局性的库到lua中,这些库由C实现:
/*** these libs are loaded by lua.c and are readily available to any Lua** program*/static const luaL_Reg loadedlibs[] = { {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_COLIBNAME, luaopen_coroutine}, //.... {NULL,NULL}};LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; /* "require" functions from 'loadedlibs' and set results to global table */ for (lib = loadedlibs; lib->func; lib++) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ }}
每一个库封装了很多函数, 且每个库都由库名和open函数导入,如以协程人库为例:
{LUA_COLIBNAME, luaopen_coroutine},
通过看协程的库的创建过程可以知道如何将C函数写的库导入lua:
// 每个库必须有的open函数:luaopen_name(..)// newlib的实现就是一个tableLUAMOD_API int luaopen_coroutine (lua_State *L) { luaL_newlib(L, co_funcs); return 1;}//下面是协程库的lua函数名和对应的C函数:static const luaL_Reg co_funcs[] = { {"create", luaB_cocreate}, {"resume", luaB_coresume}, {"running", luaB_corunning}, {"status", luaB_costatus}, {"wrap", luaB_cowrap}, {"yield", luaB_yield}, {"isyieldable", luaB_yieldable}, {NULL, NULL}};
lua_newlib(L,l)
单个C函数组成的库的open函数里, 调用的是下面的newlib函数luaL_newlib(L, co_funcs);
, 实现如下:
// 根据库函数数组 luaL_Reg的大小创建的table, 这里的createtable的实现就是在栈中创建一个哈希表, 表元素个数为sizeof(l)/sizeof((l)[0]) - 1 #define luaL_newlibtable(L,l) \ lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) // // 库的实现就是以l的大小创建了一个table #define luaL_newlib(L,l) \ (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
下面是上面调用的luaL_setfuncs函数的实现代码, 由于当前的栈顶是刚才newlibtable出来的table, 所以现在是将库函数名set到table中;
下面的实现可以看出, 每个函数创建的闭包前都先复制了一份闭包, 这样所有的库函数的闭包是一样的;
checkstack函数是检查当前的栈空间是否足够放得下nup个闭包元素;
lua_pushvalue()就是将索引处的值复制到栈顶
/*** set functions from list 'l' into table at top - 'nup'; each** function gets the 'nup' elements at the top as upvalues.** Returns with only the table at the stack.*/LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { // nup是闭包元素的个数 luaL_checkstack(L, nup, "too many upvalues"); // 如果空间不够会自动扩展栈空间 for (; l->name != NULL; l++) { /* fill the table with given functions */ int i; for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(L, -nup); // 压入所有的闭包, 当前栈顶(新的table)下的元素是nup个的闭包 lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ lua_setfield(L, -(nup + 2), l->name); } lua_pop(L, nup); /* remove upvalues */}
下面看下luaL_checkstack调用的check函数, ci为当前栈中的调用的函数帧, 可以看成函数的局部空间, ci->func为底, ci->top为空间顶, 两者之间就是当前函数的局部空间:
// const int extra = LUA_MINSTACK; 5个额外的空间// 调用的是该: lua_checkstack(L, space + extra)) ..LUA_API int lua_checkstack (lua_State *L, int n) { int res; CallInfo *ci = L->ci; // 当前的函数调用帧, ci->func为函数调用点 lua_lock(L); api_check(L, n >= 0, "negative 'n'"); if (L->stack_last - L->top > n) /* stack large enough? */ res = 1; /* yes; check is OK */ //空间足够 else { /* no; need to grow stack */ // 空间不够,需要增加栈空间 int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ res = 0; /* no */ else /* try to grow stack */ res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); } if (res && ci->top < L->top + n) ci->top = L->top + n; /* adjust frame top */ // 调用帧顶为栈顶+所需空间 lua_unlock(L); return res;}
luaL_requiref
前面的库导入过程中,luaL_requiref是真正的导入函数,实现如下, 说明符中将该函数表示为简化版的require, 完成了三件事:
1. 在全局表的_LOADED中查找有没有modulename对应的值;
2. 没有则压入库open函数和库名, 并调用open函数在栈中创建table, 将该table以key为modulename存入_LOADED全局表中;
3. 如果glb为真,即要求放入全局表中, 则放如全局, _G[modulename] = module该函数的功能和require的功能类似, 都会检查_loaded表, 没有则导入到表中取, 一共使用;
/*** Stripped-down 'require': After checking "loaded" table, calls 'openf'** to open a module, registers the result in 'package.loaded' table and,** if 'glb' is true, also registers the result in the global table.** Leaves resulting module on the top.*/LUALIB_API void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb){ // 全局注册表找到_loaded表 luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, -1, modname); /* _LOADED[modname] */ if (!lua_toboolean(L, -1)) { /* package not already loaded? */ lua_pop(L, 1); /* remove field */ lua_pushcfunction(L, openf); lua_pushstring(L, modname); /* argument to open function */ //调用库的open函数,在栈中创建了一个table lua_call(L, 1, 1); /* call 'openf' to open module */ // 复制一份以保存到_loaded里面取 lua_pushvalue(L, -1); /* make copy of module (call result) */ lua_setfield(L, -3, modname); /* _LOADED[modname] = module */ } lua_remove(L, -2); /* remove _LOADED table */ if (glb) {// 复制一份保存到_G里面去 lua_pushvalue(L, -1); /* copy of module */ lua_setglobal(L, modname); /* _G[modname] = module */ 是_G }}
- lua5.3源码基础阅读(luaL_openlibs)
- lua5.3.1 源码阅读记录(基础)
- lua5.2.3源码阅读笔记
- Lua5.2.3源码阅读(3)-Table(ipairs,pairs)
- Lua5.2.3源码阅读(1)-TValue,TString
- Lua5.2.3源码阅读(1)-TValue,TString
- Lua5.2.3源码阅读(2)-Table
- Lua5.2.3源码阅读(2)-Table
- Lua5.2.3源码阅读--Table(ipairs,pairs)
- JUnit源码阅读 -- 阅读基础
- Linux源码阅读基础入门
- Lua基础语法学习(二)+Lua5.3参考手册
- Lua5.3 released 变化
- lua5.3模块学习
- Lua5.3 数学函数
- lua5.3异常机制
- lua5.3数据结构
- Lua5.3云风译
- 子类父类构造方法执行顺序举例
- HDU1800 Flying to the Mars
- POJ 2251 Dungeon Master(BFS)
- PDO中事物处理
- Scala连接mongodb数据库
- lua5.3源码基础阅读(luaL_openlibs)
- 【PHP内核】运算符:instanceof的内核实现
- 关于python的标准库
- MVC,MVP 和 MVVM 的图示
- 数据结构实验之排序一:一趟快排
- “开会” 引发的思考
- 第5周项目2(1) 游戏中的角色类
- MyBatis中配置Spring的事物
- C++第二次实验上机-BOOK类