`
hellhell
  • 浏览: 24080 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

lua源码注释 1

阅读更多
最近读了点lua的源码,打算记录下来,将来也知道自己这一段干了啥。
其实我以前也试图读过lua源码,不过一直没有找对下手方向,比如我一直试图从main下手,这个是错误的,还没有进行正题,就被一大堆初始化给搞晕了,加之决心不大,就这样一直拖着没有看。
不过最近因为工作的原因,熟悉了lua的c api,发现从c api入手是个不错的方法。但是首先,还是要熟悉下Lua里面的基础数据结构:
/*
** Tagged Values
*/

#define TValuefields    Value value; int tt

typedef struct lua_TValue {
  TValuefields;
} TValue;



lua里面所有的值都是存放在TValue里的,TValue是所谓的tagged values。tt域表示的是值的类型(lua的8种基本类型),value域是表示具体的值,这个是一个union,
/*
** Union of all Lua values
*/
typedef union {
  GCObject *gc;
  void *p;
  lua_Number n;
  int b;
} Value;

关于这两个结构,可以浏览下lobject.h,里面有详细的说明和lua里面的用法,通过宏来操作。

lstate.h里有global_State,这个是整个运行环境中只有一份的。lua_State,表示每个thread(这是一个coroutine,并非posix意义上的thread)的state。还有GCObject,lua有gc机制,GCObject包括了table, userdata(重型),string, function和thread。

/*
** Union of all collectable objects
*/
union GCObject {
  GCheader gch;
  union TString ts;
  union Udata u;
  union Closure cl;
  struct Table h;
  struct Proto p;
  struct UpVal uv;
  struct lua_State th;  /* thread */
};



接下来就从lapi.c这个文件起。

static 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);
    }
  }
}


lua和c交互方式比较特别,是通过一个虚拟栈来交互的,通过阅读lapi.c,可以了解下这个虚拟栈的运作,为更深入的理解lua source打基础,这个index2adr的函数,是基础中的基础,它定义了栈的标识(即index)是如何转化为实际的地址的。
如果idx > 0,那么从栈底开始向上算,如果idx <= 0还大于LUA_REGISTRYINDEX(-10000),那么从栈顶开始向下数,栈上每个元素都是一个指向TValue的指针。
同时,这个函数还可以处理pseudo-indices,这是一类特殊的index,这个index不表示栈上的值,而表示lua registry,这个是一个全局的表,只对程序员可见,lua脚本没有办法使用。LUA_ENVIRONINDEX和GLOBALSINDEX来取运行时环境表和全局表,最后还有一招,似乎很少有人使用,就是可以取当前函数的upvalue,第n个upvalue就是用LUA_GLOBALSINDEX - n。
另外,这里最最重要的一点是,按照文档,传入-1表示的是栈顶元素,也就是说L->top-1是栈顶元素,L->top表示栈上下一个待使用空间。

接下来一段都比较好懂,直到
LUA_API int lua_checkstack (lua_State *L, int size) {
  int res;
  lua_lock(L);
  if ((L->top - L->base + size) > LUAI_MAXCSTACK)
    res = 0;  /* stack overflow */
  else {
    luaD_checkstack(L, size);
    if (L->ci->top < L->top + size)
      L->ci->top = L->top + size;
    res = 1;
  }
  lua_unlock(L);
  return res;
}

这里出现了个L->ci->top,ci是个CallInfo结构,看source code上的注释是表示当前的运行的函数的信息。L->ci->top和L->top的关系是什么,我现在还没有把源码看完,不敢下定论,我的感觉是L->ci->top表示了当前函数最多需要使用的栈空间,我就用到L->ci->top,不需要更多了。

接下来的函数又比较简单,顺着读就可以了。不要受诱惑,一层一层代码看下去,人脑不是电脑,管理不了那么多层递归。我觉得这些函数中值得一提的是
LUA_API void lua_insert (lua_State *L, int idx) {
  StkId p;
  StkId q;
  lua_lock(L);
  p = index2adr(L, idx);
  api_checkvalidindex(L, p);
  for (q = L->top; q>p; q--) setobjs2s(L, q, q-1);
  setobjs2s(L, p, L->top);
  lua_unlock(L);
}

这个函数名为insert,实际上栈上并没有增加新的元素,不过是将栈顶的值交换到idx位置,而在L->top上那个元素处于无人管理的状态,等待gc回收。

在lua_call函数之前有一个宏
#define checkresults(L,na,nr) \
     api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)))

佐证了我之前的想法,栈上预留的空间,要大于返回值的个数减掉参数的个数。
分享到:
评论

相关推荐

    Lua-5.1.5-部分源码注释.rar

    这个压缩包“Lua-5.1.5-部分源码注释.rar”包含了对Lua 5.1.5版本的部分源代码的注释,帮助开发者更好地理解和学习Lua的内部工作原理。 首先,我们来看看Lua的源码结构。Lua的源码主要分为几个部分:`lapi.c`, `...

    Lua源码欣赏2012年11月-云风.pdf

    1. “源文件划分”涉及到Lua源码的组织结构,将展示整个Lua解释器是如何被分解为多个文件和模块的。 2. “代码风格”会探讨Lua源码的编写习惯和风格,包括命名规则、代码组织以及注释等。 3. “核心”部分将聚焦...

    lua源码导读---云风

    ### lua源码导读---云风 #### 概览 **Lua** 是一门轻量级、高效能的脚本语言,广泛应用于游戏开发、系统管理工具、网络应用等多个领域。本书《lua源码导读》旨在深入剖析 Lua 的源代码,帮助读者理解其内部实现...

    Lua-5.1.5-部分源码注释

    前段时间阅读lua5.1.5,并把部分源码写了注释,包括Object,string table,state,部分词法分析,现在改看lua5.2了,详细可加Q群讨论3-0-1-5-4-8-7-4-8(lua技术交流)

    lua-5.4-comment:学习lua源码的时顺带翻译的注释

    a学习lua源码的时候顺带翻译的注释版本:lua5.4

    lua源码 5.4.3版本

    学习Lua源码可以帮助我们理解其背后的机制,如何执行脚本、如何管理内存、如何实现虚拟机等等。这对于想要深入优化Lua应用、开发C/C++扩展或者想要设计类似脚本语言的人来说是非常有价值的。同时,阅读源码也可以...

    lua编译&反编译,lua反编译工具,Java源码.zip

    虽然Lua的字节码是可以理解的,但直接从字节码恢复到原始源代码并不总是可能的,因为编译过程中可能会丢失一些元数据和注释。有一些第三方工具,如luadec,可以尝试对Lua字节码进行反编译,但其结果可能与原始源代码...

    Lua各版本源码阅读.md

    lua源码的各个版本,内含各个版本的注释

    Delphi-Lua 实例源码

    最后对CSDN上发源码的朋友说一句,发源码希望不要糊弄了事,注释多一些,说明详细些,重复的、完全是糊弄人的源码少发些。大家时间都很宝贵,下载积分也来之不易。浪费在无意义的下载上,实在心疼。

    cpp-Lua514版本代码注释

    《深入理解Lua 5.1.4版本源码:C++视角下的解析与注释》 Lua是一款轻量级的脚本语言,以其简洁、高效和易嵌入的特点,广泛应用于游戏开发、系统配置、自动化工具等多个领域。本文将针对Lua 5.1.4版本的源代码进行...

    redis 源码 完整注释

    1. **Redis 数据结构** Redis 支持多种数据结构,包括字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。这些数据结构的设计和实现是 Redis 高效的关键。例如,哈希表用于存储...

    最新版redis源码4.0.9带注释

    Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区...

    lua脚本解析器静态库源码

    1. 游戏逻辑:Lua脚本可以控制角色行为、任务流程、AI算法等。 2. 热更新:通过网络下载并执行新的Lua脚本,实现游戏内容的动态更新,无需用户重新下载整个游戏。 3. 错误处理:Lua脚本可以捕获和报告错误,方便调试...

    EditPlus Lua.stx Lua安装包

    1. **安装Lua插件**:EditPlus允许用户自定义工具栏和菜单,可以通过添加新的命令来调用Lua解释器。在“工具”菜单下选择“配置工具”,然后新建一个工具,将命令设置为Lua解释器的路径,这样就可以直接在EditPlus中...

    lua_reading:Lua 5.3.0源码阅读,阅读过程中加入注释方便理解

    1. **Lua虚拟机(VM)** Lua的执行核心是基于栈的虚拟机,它的设计简洁且高效。在源码中,你可以找到`lvm.c`文件,这是实现虚拟机的主要部分。通过阅读这部分代码,可以了解到如何执行字节码、如何处理操作数以及...

    lua教程.ppt.docx

    **注释**:Lua 支持两种注释方式——单行注释和多行注释。单行注释使用两个减号 `--` 开始,直到行尾。多行注释使用 `--[[ ... --]]` 包围起来。 **标识符**:Lua 中的标识符用于定义变量、函数等。标识符必须以...

    lua:关于lua原始码注释,以及一些代码

    在深入探讨Lua源码注释和代码之前,我们需要了解一些基本的背景知识。 Lua的语法简洁明了,它的设计目标是易于嵌入和扩展。它支持动态类型、垃圾回收机制、基于表的面向对象编程、以及强大的元编程能力。Lua的源码...

    龙灵修-讲Lua的cocos2d-x进阶视频.rar

    cocos2d-x进阶教程1_3Lua语言的注释、变量、语句块.mp4 cocos2d-x进阶教程1_4Lua中函数、条件判断语句.mp4 cocos2d-x进阶教程1_5Lua中循环语句和逻辑运算关键字.mp4 cocos2d-x进阶教程1_6LuaTable使用1.mp4 cocos2d-...

Global site tag (gtag.js) - Google Analytics