`

LUA源码分析七:require的函数调用堆栈

    博客分类:
  • LUA
阅读更多

require的调用其实很简单,熟悉完env的设置后,其实本质上都是走luaL_dofile函数对全局表的设置。do_file完,然后设置环境变量。借助此,把LUA里的函数堆栈方式依次跟调一次。


如果是熟悉汇编堆栈的形式,对LUA的源码风格很好理解。比如没有实际的变量名,通过对栈的偏移来访问。大于0的表示从base基地址加起,负数的表示从top往后减,或者是表示特定的全局值。因为有这种访问上的规则,所以lua的源码对访问封装的层次很清晰,哪里要回退栈指针,哪里要增加top地址等等。


static int ll_require (lua_State *L) {
  const char *name = luaL_checkstring(L, 1);
  int i;

  lua_settop(L, 1);  /* _LOADED table will be at index 2 */
  lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
  lua_getfield(L, 2, name);


  if (lua_toboolean(L, -1)) {  /* is it there? */
    if (lua_touserdata(L, -1) == sentinel)  /* check loops */
      luaL_error(L, "loop or previous error loading module " LUA_QS, name);
    return 1;  /* package is already loaded */
  }
  /* else must load it; iterate over available loaders */
  lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
  if (!lua_istable(L, -1))
    luaL_error(L, LUA_QL("package.loaders") " must be a table");
  lua_pushliteral(L, "");  /* error message accumulator */

/*
至此栈的数据
0x00395108:LUA_REGISTRYINDEX, "_LOADED"
0x00395118:lua_getfield(L, 2, name)  //name,导入的模块名
0x00395128:LUA_ENVIRONINDEX, "loaders"
0x00395138:""
*/
  for (i=1; ; i++) {
/*
i=1:
从0x00395128取值赋到栈顶
0x00395148:LUA_ENVIRONINDEX, "loaders"[1]

i=2:
从0x00395128取值赋到栈顶
0x00395148:LUA_ENVIRONINDEX, "loaders"[2]

*/
    lua_rawgeti(L, -2, i);  /* get a loader */
    if (lua_isnil(L, -1))
      luaL_error(L, "module " LUA_QS " not found:%s",
                    name, lua_tostring(L, -2));
/*
i=1:
0x00395158:lua_pushstring(L, name);

i=2:
0x00395158:lua_pushstring(L, name);
*/
    lua_pushstring(L, name);
/*
i=1:
呼叫0x00395148的函数,name做为参数。呼叫过程见段1

i=2:
呼叫0x00395148的函数,name做为参数。呼叫过程见段2
*/
    lua_call(L, 1, 1);  /* call it */
/*
i=1:
判断是否找到模块名
*/
    if (lua_isfunction(L, -1))  /* did it find module? */
      break;  /* module loaded successfully */
    else if (lua_isstring(L, -1))  /* loader returned error message? */
      lua_concat(L, 2);  /* accumulate it */
    else
      lua_pop(L, 1);
  }
/*
0x00395158:sentinel
*/
  lua_pushlightuserdata(L, sentinel);
/*
基地址是L->base = 0x003950f8,
取到0x00395108:LUA_REGISTRYINDEX, "_LOADED"值。
把top的值(sentinel)给_LOADED[name],同时top--
*/
  lua_setfield(L, 2, name);  /* _LOADED[name] = sentinel */
/*
0x00395158:lua_pushstring(L, name)
*/
  lua_pushstring(L, name);  /* pass name as argument to module */
/*
  调用,将模块环境载入.并且修改了0x00395148函数块,压入一个lua的函数调用结构
*/
  lua_call(L, 1, 1);  /* run loaded module */
  if (!lua_isnil(L, -1))  /* non-nil return? */
    lua_setfield(L, 2, name);  /* _LOADED[name] = returned value */
/*
0x00395158:lua_pushstring(L, name)
接下来就是善后工作了。注意,_LOADED[name]被设置为true。
*/
  lua_getfield(L, 2, name);
  if (lua_touserdata(L, -1) == sentinel) {   /* module did not set a value? */
    lua_pushboolean(L, 1);  /* use true as result */
    lua_pushvalue(L, -1);  /* extra copy to be returned */
    lua_setfield(L, 2, name);  /* _LOADED[name] = true */
  }
  return 1;
}
 

/*
段1
*/
static int loader_preload (lua_State *L) {
/*
取得0x00395158:lua_pushstring(L, name);
*/
  const char *name = luaL_checkstring(L, 1);
/*
0x00395168:LUA_ENVIRONINDEX, "preload"
*/
  lua_getfield(L, LUA_ENVIRONINDEX, "preload");
  if (!lua_istable(L, -1))
    luaL_error(L, LUA_QL("package.preload") " must be a table");
/*
0x00395178:从0x00395168LUA_ENVIRONINDEX, "preload"表里,读取name的字段

*/
  lua_getfield(L, -1, name);
/*
 如果是自定义的,则没找到,压入字符串,供上层判断
*/
  if (lua_isnil(L, -1))  /* not found? */
    lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
  return 1;
}
 
/*
段2
*/
static int loader_Lua (lua_State *L) {
  const char *filename;
  const char *name = luaL_checkstring(L, 1);
/*
查找路径的规则。如果想知道具体没必要细跟。可以设置一个找不到模块名,
查看返回的错误信息(带有所有路径名的搜索)即可。
*/
  filename = findfile(L, name, "path");
  if (filename == NULL) return 1;  /* library not found in this path */
/*
luaL_loadfile很熟悉了
*/
  if (luaL_loadfile(L, filename) != 0)
    loaderror(L, filename);
  return 1;  /* library loaded successfully */
}
 
1
3
分享到:
评论

相关推荐

    Lua编程事例:调用Lua有参函数

    这次说明的了,在VC++ 6.0中怎么样调用一个lua脚本中的有参函数。

    tolua++ 版helloworld (lua脚本调用C++类的成员函数方法)

    关于tolua++的资料太少,这个通过实例让你知道如何通过tolua++和C++交互,简单明了。 通过5个文件来演示这个tolua++版 hello world hello.lua ,hello.h ,hello.pkg ,...这个程序实现了脚本调用C++类的成员函数方法

    Lua源码分析

    Lua源码分析Lua源码分析Lua源码分析Lua源码分析Lua源码分析Lua源码分析Lua源码分析Lua源码分析

    所有版本LUA源码

    所有版本LUA源码 lua-5.3.5 lua-5.3.4 lua-5.3.3 lua-5.3.2 lua-5.3.1 lua-5.3.0 lua-5.2.4 lua-5.2.3 lua-5.2.2 lua-5.2.1 lua-5.2.0 lua-5.1.5 lua-5.1.4 lua-5.1.3 lua-5.1.2 lua-5.1.1 lua-5.1 lua-5.0.3 lua-...

    Lua中使用.和:调用函数的区别

    主要介绍了Lua中使用.和:调用函数的区别,本文总结了它的调用函数的时传入参数的区别,并给出了一个代码实例,需要的朋友可以参考下

    lua5.3实例

    test pc: ubuntu 14.04 ...7. 文件夹class ## lua调用c++类 堆栈形式 8 文件夹student ## lua调用c++类, table形式 build: works/lua_demo$ ./build.sh e13.cpp e13 tests: works/lua_demo$ lua test.lua

    lua源码分析

    这个是lua的源码分析,lua的源码写的非常好,整个设计的结构非常巧妙,不管是对于学习lua本身还是c语言的数据结构都非常有帮助。

    Lua 学习教程 Android与Lua相互调用

    直接以JNI方式调用Lua解析引擎的接口十分麻烦,开源项目LuaJava(https://github.com/mkottman/AndroLua )对这些JNI接口进行了很好的封装,它是一个包含了LuaJava的Android平台的Lua解析器,它提供一系列映射到Lua ...

    Lua的使用入门之在C++程序中调用lua函数1

    基本的调用lua变量与函数,实现文本的获取与显示策略,若要改变显示方式,只要修改move()函数即可.

    云风-lua源码欣赏-lua-5.21

    第一章概览由甮由源文件划分 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮 甮

    Lua的最基本使用 C++与lua的互相调用

    C++调用Lua函数 以及Lua调用C++函数

    lua调用C++函数

    本人亲自编译通过的程序,如果无法通过只可能是您的编译环境有问题。本人的开发环境:VC++6.0,使用的是Win32 Console Application

    Lua中调用C函数

    在Linux底下,从Lua中调用C函数的一个简单例子。

    易语言lua的例子

    易语言lua的例子,静态易语言调用LUA51.DLL和模块

    lua调用c函数库的demo

    lua调用c函数库的demo 其中实现了对一个 数组的管理。 注意lua参数与c函数的对应, 如:b=lua_dllb.getarray(a,1) static int getarray(lua_State* L) { NumArray * a=(NumArray*)lua_touserdata(L,1); //对应lua...

    OC与Lua交互调用(不使用第三方库)Demo

    lua与oc的交互demo,封装了一层luaBridge,开源lua库,lua调用oc的过程

    tick:用于延迟函数调用的 Lua 模块

    一个小的 Lua 模块,它简化了在设定的时间间隔或延迟后调用函数。 用法 文件放入现有项目并为其所必需。 tick = require " tick " 在每一帧开始时,应该调用tick.update()并给tick.update()上次调用以来的增量时间...

    redis-lua 源码

    redis-lua 是 Redis 的 Lua 语言的客户端开发包。 示例代码: require 'redis' local redis = Redis.connect('127.0.0.1', 6379) local response = redis:ping() -- true redis:set('usr:nrk', 10) redis:set('usr...

    Lua调用C++函数实现

    NULL 博文链接:https://pirateyk.iteye.com/blog/513811

    lua 源码剖析

    里面有风云 大神写的对lua 的源码剖析。还有lua5.2源码。

Global site tag (gtag.js) - Google Analytics