第一章先开个头
看不明白的话也不要紧,下一章将从怎么编译介绍起。
源代码阅读贵在坚持,当然有一个好工具也是必要的。
推荐大家使用Source Insight ,这是一个非常好用的东西。
不管是阅读还是写C/C++/C#的代码,使用它都会感觉非常爽!
今天开始阅读,因为是开头,所以选择一个简单的文件--etc/min.c
作为开始,但是并不限于这个文件,我们还会发散到其他文件中。
//这段代码实现了一个非常简单的Lua的解释器
int main(void)
{
//打开一个Lua环境,其实就是一个Lua脚本执行的上下文,或者说Lua解析器对象
lua_State *L=lua_open();
//注册C函数print()到lua的全局变量print,print指向的值是一个C函数
lua_register(L,"print",print);
//打开并执行stdin(NULL==stdin)文件的内容,也就是标准输入输出,如果出错就打印出错信息
if (luaL_dofile(L,NULL)!=0) fprintf(stderr,"%s/n",lua_tostring(L,-1));
//关闭Lua上下文L
lua_close(L);
return 0;
}
这些很简单吧,需要住意的就是luaL_dofile()函数,当参数2为NULL时,自动打开stdin。
if (filename == NULL) {
lua_pushliteral(L, "=stdin");
lf.f = stdin;
}
#define lua_pushliteral(L, s) /
lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)//这里的参数3的值是6。
这个函数需要特别注意:
lua的string的概念和c的定义不同,c的字符串不能中间含有0x0,但是lua的字符串可以。
这里的sizeof(s)是特别需要注意的,这里是C语言的sizeof对一个字符数组求值,所以字符数组被看作是
按照0x0结尾的字符串来数数并且加上1!恐怖吧!
这也是为什么把字符串的长度暴露给调用者的原因,当需要传入中间含有0x0的字符串的时候,用户可以手动
写一个求长度的函数,而不是使用sizeof操作符。
#define luaL_dofile(L, fn) /
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
好!接下来,让我们看看luaL_loadfile()函数。
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
//描述待操作文件的结构体
//typedef struct LoadF {
// int extraline;
// FILE *f;//文件句柄
// char buff[LUAL_BUFFERSIZE];//缓冲区
//} LoadF;
LoadF lf;
int status, readstatus;
int c;
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
lf.extraline = 0;
if (filename == NULL) {//
lua_pushliteral(L, "=stdin");
lf.f = stdin;
}
else {
lua_pushfstring(L, "@%s", filename);
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
c = getc(lf.f);//获取文件中一个字符,并返回一个字符。
if (c == '#') { /* Unix exec. file? */
lf.extraline = 1;//跳过解析器指定行
while ((c = getc(lf.f)) != EOF && c != '/n') ; /* skip first line */
if (c == '/n') c = getc(lf.f);//跳过空行
}
//预编译文件标识
///* mark for precompiled code (`<esc>Lua') */
//#define LUA_SIGNATURE "/033Lua"
if (c == LUA_SIGNATURE[0] && lf.f != stdin) { /* binary file? */
fclose(lf.f);
lf.f = fopen(filename, "rb"); /* reopen in binary mode *///windows系统区分binary和text文件
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
/* skip eventual `#!...' */
while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
lf.extraline = 0;
}
ungetc(c, lf.f);//回显字符
status = lua_load(L, getF, &lf, lua_tostring(L, -1));//读入文件
readstatus = ferror(lf.f);
if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */
if (readstatus) {
lua_settop(L, fnameindex); /* ignore results from `lua_load' */
return errfile(L, "read", fnameindex);
}
lua_remove(L, fnameindex);
return status;
}
LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
const char *chunkname) {
ZIO z;
//struct Zio {
// size_t n; /* bytes still unread */
// const char *p; /* current position in buffer */
// lua_Reader reader;
// typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
// void* data; /* additional data */
// lua_State *L; /* Lua state (for reader) */
//};
int status;
lua_lock(L);//加锁 #define lua_lock(L) ((void) 0)
//因为lua内部实际上没有多线程,所以不需要加锁解锁
if (!chunkname) chunkname = "?";
luaZ_init(L, &z, reader, data);//初始化ZIO结构体,辅助描述lua_Reader对象
status = luaD_protectedparser(L, &z, chunkname);//执行
lua_unlock(L);//解锁 #define lua_unlock(L) ((void) 0)
return status;
}
int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) {
struct SParser p;
int status;
p.z = z; p.name = name;
luaZ_initbuffer(L, &p.buff);//初始化缓存,#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);//调用luaD_pcall执行真正的操作
luaZ_freebuffer(L, &p.buff);
return status;
}
int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t old_top, ptrdiff_t ef) {
int status;
unsigned short oldnCcalls = L->nCcalls;//嵌套的C调用计数
ptrdiff_t old_ci = saveci(L, L->ci);//老的C接口
lu_byte old_allowhooks = L->allowhook;//
ptrdiff_t old_errfunc = L->errfunc;
L->errfunc = ef;
status = luaD_rawrunprotected(L, func, u);
if (status != 0) { /* an error occurred? */
StkId oldtop = restorestack(L, old_top);
luaF_close(L, oldtop); /* close eventual pending closures */
luaD_seterrorobj(L, status, oldtop);
L->nCcalls = oldnCcalls;
L->ci = restoreci(L, old_ci);
L->base = L->ci->base;
L->savedpc = L->ci->savedpc;
L->allowhook = old_allowhooks;
restore_stack_limit(L);
}
L->errfunc = old_errfunc;
return status;
}
注意:
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
struct lua_longjmp lj;
lj.status = 0;
lj.previous = L->errorJmp; /* chain new error handler */
L->errorJmp = &lj;
LUAI_TRY(L, &lj,
(*f)(L, ud);
);
L->errorJmp = lj.previous; /* restore old error handler */
return lj.status;
}
下面是让人佩服的地方,虽然Lua是用pure C书写,但是还是不忘为C++的异常作了特别的优化。
/*
@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling.
** CHANGE them if you prefer to use longjmp/setjmp even with C++
** or if want/don't to use _longjmp/_setjmp instead of regular
** longjmp/setjmp. By default, Lua handles errors with exceptions when
** compiling as C++ code, with _longjmp/_setjmp when asked to use them,
** and with longjmp/setjmp otherwise.
*/
#if defined(__cplusplus)//使用此定义的时候,C++异常必须打开
/* C++ exceptions */
#define LUAI_THROW(L,c) throw(c)
#define LUAI_TRY(L,c,a) try { a } catch(...) /
{ if ((c)->status == 0) (c)->status = -1; }
#define luai_jmpbuf int /* dummy variable */
#elif defined(LUA_USE_ULONGJMP)
/* in Unix, try _longjmp/_setjmp (more efficient) */
#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#else
/* default handling with long jumps */
#define LUAI_THROW(L,c) longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#endif
顺便说一下,LuaJIT里面保留了同样的定义。
/* chain list of long jump buffers */
struct lua_longjmp {
struct lua_longjmp *previous;
luai_jmpbuf b;
volatile int status; /* error code *///这里volatile避免放变量到寄存器,因为如果是longjmp的话,
//寄存器内容没有保存
};
在来看一个函数:
static void restore_stack_limit (lua_State *L) {
//恢复调用栈的平衡
lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */
int inuse = cast_int(L->ci - L->base_ci);
if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */
luaD_reallocCI(L, LUAI_MAXCALLS);
}
}
/*
** `per thread' state
*/
struct lua_State {
CommonHeader;//通用头结构,一个GCObject指针,两个字节辅助描述
lu_byte status;//其实就是unsigned char
StkId top; /* first free slot in the stack */
StkId base; /* base of current function */
global_State *l_G;//所有线程共享的State的指针
CallInfo *ci; /* call info for current function */
const Instruction *savedpc; /* `savedpc' of current function *///当前保存的pc寄存器的植
StkId stack_last; /* last free slot in the stack *///
StkId stack; /* stack base */
CallInfo *end_ci; /* points after end of ci array*/
CallInfo *base_ci; /* array of CallInfo's */
int stacksize;
int size_ci; /* size of array `base_ci' */
unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask;
lu_byte allowhook;
int basehookcount;
int hookcount;
lua_Hook hook;//函数被调用被调试器在特殊的事件
TValue l_gt; /* table of globals */
TValue env; /* temporary place for environments */
GCObject *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */
ptrdiff_t errfunc; /* current error handling function (stack index) */
};
好吧,好像都很模糊,没有关系,刚开始就是这样。