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  }}
0 0
原创粉丝点击