博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lua4.0 lua_dofile,lua_dostring
阅读量:5796 次
发布时间:2019-06-18

本文共 4002 字,大约阅读时间需要 13 分钟。

  hot3.png

这两个函数的定义都位于 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,不贴代码了。

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

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

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

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

到目前为止的问题:

无!

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

转载于:https://my.oschina.net/xhan/blog/495452

你可能感兴趣的文章
TEST
查看>>
PAT A1037
查看>>
ReactiveSwift源码解析(三) Signal代码的基本实现
查看>>
(六)Oracle学习笔记—— 约束
查看>>
[Oracle]如何在Oracle中设置Event
查看>>
top.location.href和localtion.href有什么不同
查看>>
02-创建hibernate工程
查看>>
information_schema系列五(表,触发器,视图,存储过程和函数)
查看>>
瓜子二手车的谎言!
查看>>
[转]使用Git Submodule管理子模块
查看>>
DICOM简介
查看>>
Scrum之 Sprint计划会议
查看>>
List<T> to DataTable
查看>>
[Java]Socket和ServerSocket学习笔记
查看>>
stupid soso spider
查看>>
svn命令在linux下的使用
查看>>
MySQL主从同步相关-主从多久的延迟?
查看>>
Gradle之module间依赖版本同步
查看>>
java springcloud版b2b2c社交电商spring cloud分布式微服务(十五)Springboot整合RabbitMQ...
查看>>
SpringCloud使用Prometheus监控(基于Eureka)
查看>>