Lua4.0 lua_dofile,lua_dostring

原创
2015/08/21 13:12
阅读数 1.2W

这两个函数的定义都位于 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;
}

先解析文件,如果解析无误,则调用。

由函数名字及下面的调用我们可以猜出,parse_file 应该是做的语法解析。

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

先根据文件名来判断输入的是什么?

如果文件名为空,则从标准输入读取。

否则从文件名读取。

取得文件的第一个字符,如果是 ID_CHUNK 的话,表示文件是一个已经编译好的 Lua 字节码文件。

bin 标志位就是用来标识这个文件是否为 Lua 字节码文件。

后面对 filename 进行编码,前面添加 '@' 符号。

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,不贴代码了。

翻了下之前的博客,最早的时候有一个虚拟机执行的分析。

这里就不再重复一次这种体力劳动了。

力气应该花在更有意义的地方!

----------------------------------------

到目前为止的问题:

无!

----------------------------------------

展开阅读全文
打赏
0
9 收藏
分享
加载中
更多评论
打赏
0 评论
9 收藏
0
分享
返回顶部
顶部