`

LUA源码分析二:了解lua的文件结构和思考方式

    博客分类:
  • LUA
阅读更多

版本整理日期:2011/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.2
  lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
  return 1;
}

 


/*
	1.1
	lauxlib.c
	调用lua_tonumber,并且对参数进行一个检测,可以看成是一个辅助性的函数
*/
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
	//lua_tonumber见1.1.1
  lua_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.1
	lapi.c
	观察是怎么取出一个值的.其中index2adr,tonumber等都是很常见的函数,
	不做单独的段落分析,统一放在末尾一起分析
*/
lua_tonumber()
{
	//从栈上取出一个TValue变量
	const TValue *o = index2adr(L, idx);			
	//一个宏转换,是否是number类型
  if (tonumber(o, &n))											
  	//从TValue里取出值
    return nvalue(o);												
  else
  	//失败返回0	
    return 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 TValuefields	Value 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;
  }
  else
    return 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.2
	lapi.c
  lua_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.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);
    }
  }
}

 

 

先不具体去追究里面意思,可以知道这么几个信息

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是最基础的结构文件

1
8
分享到:
评论

相关推荐

    lua 源码剖析

    《lua 源码剖析》是一本深入探讨lua编程语言...通过对lua源码的学习,开发者不仅能掌握lua语言的精髓,还能提升编程技巧,更好地利用lua解决实际问题。同时,源码阅读也能培养程序员的底层思维,增强系统级编程能力。

    Lua源码剖析

    ### Lua源码剖析:深入理解Lua的内部机制 #### 引言 Lua,作为一种轻量级、高效且可嵌入的脚本语言,在游戏开发、Web应用、自动化脚本等领域有着广泛的应用。其源码的剖析不仅能够帮助我们更深入地理解Lua的工作...

    xLua框架源码

    在项目中,通常会创建一个或多个Lua文件,用于编写游戏逻辑或特定功能。这些文件可以被C#代码动态加载和执行,实现代码的热更新。 `ReadMe.md`文件是xLua框架的重要组成部分,它提供了详细的使用指南和注意事项。在...

    redis源码日志

    通过以上知识点的梳理,我们可以看到《Redis源码日志》不仅深入浅出地介绍了Redis的核心技术细节,还提供了丰富的实践指导和思考方向。这对于希望深入了解Redis内部机制的专业人士来说,是一份非常有价值的参考资料...

    小游戏源码-逼死强迫症.rar

    "小游戏源码-逼死强迫症.rar"揭示了这是一个包含小游戏源代码的压缩文件,特别标注了“逼死强迫症”,可能意味着游戏设计上具有挑战性,需要玩家有高度的专注力和精确的操作,或者游戏关卡设计充满了需要细致入微...

    圣战2源码 圣战2源码

    通过分析和研究这款源码,我们可以学习到许多关键的游戏开发技术与原理,包括但不限于以下几个方面: 1. 游戏引擎架构:《圣战2》的源码揭示了游戏引擎的基础结构,包括场景管理、渲染引擎、物理系统、碰撞检测、AI...

    小游戏源码-影子传说.rar

    源码学习的价值不仅在于技术层面,还在于培养问题解决能力、逻辑思维和工程实践。通过阅读和理解源码,开发者能够掌握最佳实践,学习如何组织代码以提高可读性和可维护性,这对于任何软件开发项目都是至关重要的。 ...

    Java思维导图xmind文件+导出图片

    基于Zookeeper Watcher 核心机制深入源码分析 Zookeeper集群升级、迁移 基于Zookeeper实现分布式服务器动态上下线感知 深入分析Zookeeper Zab协议及选举机制源码解读 Dubbo 使用Dubbo对单一应用服务化改造 ...

    卡通横版冒险游戏-《香蕉岛》源码.zip

    7. 文件系统:游戏中的资源配置、存档系统通常涉及文件读写操作,学习源码能让我们了解如何高效地管理游戏的数据文件。 8. 网络通信:如果《香蕉岛》支持多人在线功能,源码中将包含网络编程的相关代码,如TCP/IP...

    智力游戏-小青蛙过河源码 v1.0

    对于学习者来说,分析这个游戏的源码可以深入了解游戏开发的基本流程和编程思维,特别是对状态机模型和搜索算法的应用。此外,通过修改源码,还可以尝试增加新的功能,如增加难度等级、添加障碍物或增加玩家自定义...

    小游戏源码-变态测试题.rar

    7. **学习与借鉴**:对于初学者,分析这些源码可以帮助他们理解游戏开发的基本结构和流程,学习如何处理用户输入、碰撞检测、动画制作、得分系统等关键部分。 8. **二次开发**:拥有源码意味着可以对游戏进行个性化...

    抽象话生成器-普通话转换成抽象化的表达方式.zip

    在当今信息爆炸的时代,人们追求新鲜、独特的交流方式,以表达个性和创新思维。"抽象话生成器"正是这样一款工具,它能将普通的普通话转化为富有创意和趣味性的抽象化表达。这款应用的核心在于将常规的语句转化成一种...

    神谕之剑游戏源码.rar

    《神谕之剑游戏源码》是一个压缩包文件,包含了制作神谕之剑游戏的原始代码。虽然没有提供具体的标签,但我们可以从标题和描述中推测出这可能是一款基于计算机的角色扮演游戏(RPG)的源代码。源码是程序的核心部分...

    动画地图编辑器.rar

    通过分析和理解这个源码,我们可以了解到以下关键知识点: 1. **图形用户界面(GUI)设计**:动画地图编辑器的界面设计是用户友好和直观的,它使用了易语言提供的窗口控件和布局管理技术。理解这些控件的用法和交互...

    pico-8-projects:只是我用于模拟和写下我一直在思考的基本实现的存储库

    在压缩包中的“pico-8-projects-master”文件很可能包含了项目源码、资源文件和可能的说明文档。这些内容可以用来研究作者是如何利用PICO-8的工具和限制进行游戏开发的,包括但不限于: 1. **代码结构**:理解如何...

    技术整理成的pdf,欢迎下载

    虽然描述中提到“NULL”,但通过提供的信息,我们可以了解文档的主要内容和结构,以及作者对于技术感想和技术分享的态度和风格。作者通过分享个人经历和专业见解,为IT行业的从业者提供了丰富的学习资源和参考资料。

    Semaforo:Semaforo团队使用PICO-8 @FEUP为RetroJam创建的项目存储库

    通过查看和分析项目源码,可以学习到如何在PICO-8的环境中有效地组织代码、管理资源,以及如何利用Lua的特性来创建交互性和趣味性。同时,参与RetroJam这样的活动也是对开发者创新思维和复古美学理解的锻炼。 总结...

    braievaluck:使用其他语言的Brainf * ck实现

    "braievaluck-master" 可能是项目的主分支或者源码库的名称,表明这是项目的核心代码仓库,可能包含了各个语言实现 Brainf*ck 的源代码文件和相关文档。 **知识点详解:** 1. **编程语言实现原理**:理解每种语言...

Global site tag (gtag.js) - Google Analytics