這兩個函數的定義都位於 ldo.c 中,看看這兩個函數都作了什麼事兒?函數
先來看一下 lua_dofile 執行文件編碼
LUA_API int lua_dofile (lua_State *L, const char *filename) { int status = parse_file(L, filename); if (status == 0) /* parse OK? */ status = lua_call(L, 0, LUA_MULTRET); /* call main */ return status; }
先解析文件,若是解析無誤,則調用。lua
由函數名字及下面的調用咱們能夠猜出,parse_file 應該是作的語法解析。spa
static int parse_file (lua_State *L, const char *filename) { ZIO z; int status; int bin; /* flag for file mode */ int c; /* look ahead char */ FILE *f = (filename == NULL) ? stdin : fopen(filename, "r"); if (f == NULL) return LUA_ERRFILE; /* unable to open file */ c = fgetc(f); ungetc(c, f); bin = (c == ID_CHUNK); if (bin && f != stdin) { f = freopen(filename, "rb", f); /* set binary mode */ if (f == NULL) return LUA_ERRFILE; /* unable to reopen file */ } lua_pushstring(L, "@"); lua_pushstring(L, (filename == NULL) ? "(stdin)" : filename); lua_concat(L, 2); c = lua_gettop(L); filename = lua_tostring(L, c); /* filename = '@'..filename */ luaZ_Fopen(&z, f, filename); status = protectedparser(L, &z, bin); lua_remove(L, c); /* remove `filename' from the stack */ if (f != stdin) fclose(f); return status; }
先根據文件名來判斷輸入的是什麼?設計
若是文件名爲空,則從標準輸入讀取。code
不然從文件名讀取。orm
取得文件的第一個字符,若是是 ID_CHUNK 的話,表示文件是一個已經編譯好的 Lua 字節碼文件。rem
bin 標誌位就是用來標識這個文件是否爲 Lua 字節碼文件。字符串
後面對 filename 進行編碼,前面添加 '@' 符號。get
luaZ_Fopen 打開緩衝區。
protectedparser 解析。
先不看 protectedparser 裏作什麼了。
先看下 lua_dostring,由於最後也是調到了 protectedparser 身上。
LUA_API int lua_dostring (lua_State *L, const char *str) { return lua_dobuffer(L, str, strlen(str), str); }
lua_dostring 內部調用 lua_dobuffer 來實現。
能夠看出這裏調用 lua_dobuffer 時 str 即當 buff 參數,又當 name 參數。
LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name) { int status = parse_buffer(L, buff, size, name); if (status == 0) /* parse OK? */ status = lua_call(L, 0, LUA_MULTRET); /* call main */ return status; }
一樣,和文件類型,也是先語法解析。
解析無誤,則調用。
static int parse_buffer (lua_State *L, const char *buff, size_t size, const char *name) { ZIO z; if (!name) name = "?"; luaZ_mopen(&z, buff, size, name); return protectedparser(L, &z, buff[0]==ID_CHUNK); }
能夠看到,在解析字符串 buffer 時,最後也是調到了 protectedparser 身上。
到 protectedparser 時,因爲緩衝區 ZIO 的做用,已經沒有文件或者字符串的區別了。
很不錯的設計思想!
這時候,再來看看 protectedparser 。
static int protectedparser (lua_State *L, ZIO *z, int bin) { struct ParserS p; unsigned long old_blocks; int status; p.z = z; p.bin = bin; /* before parsing, give a (good) chance to GC */ if (L->nblocks/8 >= L->GCthreshold/10) luaC_collectgarbage(L); old_blocks = L->nblocks; status = luaD_runprotected(L, f_parser, &p); if (status == 0) { /* add new memory to threshold (as it probably will stay) */ L->GCthreshold += (L->nblocks - old_blocks); } else if (status == LUA_ERRRUN) /* an error occurred: correct error code */ status = LUA_ERRSYNTAX; return status; }
能夠看到它裏面調用了 f_parser 。
static void f_parser (lua_State *L, void *ud) { struct ParserS *p = (struct ParserS *)ud; Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z); luaV_Lclosure(L, tf, 0); }
f_parser 裏調用 luaY_parser 來作具體的語法解析。
若是已是字節碼的文件,就不用語法解析了,直接 luaU_undump 字節碼就好。
到這裏,就差 lua_call 的執行了。
LUA_API int lua_call (lua_State *L, int nargs, int nresults) { StkId func = L->top - (nargs+1); /* function to be called */ struct CallS c; int status; c.func = func; c.nresults = nresults; status = luaD_runprotected(L, f_call, &c); if (status != 0) /* an error occurred? */ L->top = func; /* remove parameters from the stack */ return status; }
lua_call 裏調用 f_call
static void f_call (lua_State *L, void *ud) { struct CallS *c = (struct CallS *)ud; luaD_call(L, c->func, c->nresults); }
f_call 裏調用 luaD_call。
而後是 luaV_execute(L, cl, func+1));
這個就是虛擬機執行字節碼指令了。
luaV_execute 就是個大大的 switch case,不貼代碼了。
翻了下以前的博客,最先的時候有一個虛擬機執行的分析。
這裏就再也不重複一次這種體力勞動了。
力氣應該花在更有意義的地方!
----------------------------------------
到目前爲止的問題:
> 無!
----------------------------------------