码迷,mamicode.com
首页 > 其他好文 > 详细

Lua4.0 编译入口

时间:2015-08-10 15:04:31      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:

解决上一篇的问题,上代码了。


C 语言程序的入口为 main 函数,Lua 编译器的入口为 luac.c 文件里的 main 函数。

先来看一下 main 函数:

int main(int argc, const char* argv[])
{
 Proto** P,*tf;
 int i=doargs(argc,argv);
 argc-=i; argv+=i;
 if (argc<=0) usage("no input files given",NULL);
 L=lua_open(0);
 P=luaM_newvector(L,argc,Proto*);
 for (i=0; i<argc; i++)
  P[i]=load(IS("-")? NULL : argv[i]);
 tf=combine(P,argc);
 if (dumping) luaU_optchunk(tf);
 if (listing) luaU_printchunk(tf);
 if (testing) luaU_testchunk(tf);
 if (dumping)
 {
  if (stripping) strip(tf);
  luaU_dumpchunk(tf,efopen(output,"wb"));
 }
 return 0;
}

程序上来先声明一个函数原型的二级指针 P(下面用的时候是把它做为函数原型的指针数组来用的),一个函数原型的指针 tf。

函数原型可以简单地认为是一个 lua 文件等价的编译后的东西。

每一个 lua 文件会生成一个函数原型,最后,所有的输入 lua 文件会拼成一个函数原型。


doargs 解析入参。主要是带中划线的那样的参数。就是一系列的 IS 宏调用的判断。这个函数的注释比较清楚。代码如下:

static int doargs(int argc, const char* argv[])
{
 int i;
 for (i=1; i<argc; i++)
 {
  if (*argv[i]!=‘-‘) /* end of options */
   break;
  else if (IS("-")) /* end of options; use stdin */
   return i;
  else if (IS("-l")) /* list */
   listing=1;
  else if (IS("-o")) /* output file */
  {
   output=argv[++i];
   if (output==NULL) usage(NULL,NULL);
  }
  else if (IS("-p")) /* parse only */
   dumping=0;
  else if (IS("-s")) /* strip debug information */
   stripping=1;
  else if (IS("-t")) /* test */
  {
   testing=1;
   dumping=0;
  }
  else if (IS("-v")) /* show version */
  {
   printf("%s  %s\n",LUA_VERSION,LUA_COPYRIGHT);
   if (argc==2) exit(0);
  }
  else /* unknown option */
   usage("unrecognized option `%s‘",argv[i]);
 }
 if (i==argc && (listing || testing))
 {
  dumping=0;
  argv[--i]=OUTPUT;
 }
 return i;
}

解析好的选项保存在相应的静态变量中。

如下所示:

static int listing=0;           /* list bytecodes? */
static int dumping=1;           /* dump bytecodes? */
static int stripping=0;         /* strip debug information? */
static int testing=0;           /* test integrity? */
static const char* output=OUTPUT;   /* output file name */

输出的文件名默认为 "luac.out",如果用户指定了,则用用户指定的名字。就是上面的 IS("-o") 这块儿。

如果出错,则调用 usage 提示用户。usage 中列出了各个参数的用户及意义。


参数解析完之后,如果还有剩余的命令行参数的话,都被当作输入的 lua 源代码文件。

新建一个 lua_state ,这就是 lua 中那个无处不在的 L 。

新建函数原型 Proto 指针数组。


为每一个命令行参数调用 load ,把它转化为一个函数原型。代码如下:

 for (i=0; i<argc; i++)
  P[i]=load(IS("-")? NULL : argv[i]);


把这个数组合并为一个函数原型。 tf=combine(P,argc);


最下面的几个 if 判断根据参数选项的不同,进行不同的操作。

dump 代码之前会先对函数原型进行优化。 if (dumping) luaU_optchunk(tf);

luaU_printchunk(tf); 打印函数原型内容。

luaU_dumpchunk : dump 函数原型。

这几个先列个问题,以后细说,虽说和主要的编译过程关系不是太大。


回到编译的问题上来,一个 lua 文件是如何转经为 Proto 的呢?

这里有一个 load 函数,就是做得这个事。

static Proto* load(const char* filename)
{
 Proto* tf;
 ZIO z;
 char source[512];
 FILE* f;
 int c,undump;
 if (filename==NULL)
 {
  f=stdin;
  filename="(stdin)";
 }
 else
  f=efopen(filename,"r");
 c=ungetc(fgetc(f),f);
 if (ferror(f))
 {
  fprintf(stderr,"luac: cannot read from ");
  perror(filename);
  exit(1);
 }
 undump=(c==ID_CHUNK);
 if (undump && f!=stdin)
 {
  fclose(f);
  f=efopen(filename,"rb");
 }
 sprintf(source,"@%.*s",Sizeof(source)-2,filename);
 luaZ_Fopen(&z,f,source);
 tf = undump ? luaU_undump(L,&z) : luaY_parser(L,&z);
 if (f!=stdin) fclose(f);
 return tf;
}


程序上来声明了一个 ZIO 变量,以后读源代码就从它读取了。

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

先读文件的第一个字符,如果是 ID_CHUNK 的话,则说明此时打开的文件是一个 lua 字节码文件。

最后根据打开的是否是 lua 字节码文件来决定是进行 undump 操作还是语法解释操作。


combine 把多个 Proto 拼成一个 Proto。

其中有一个需要注意的地方是,一个函数原型是一个 Closure。就是 for 循环里面的东西。


strip 把一些调试信息删掉。


这篇的内容先到这里,等后面几个相关的知识点说完这里自然就清楚了。


看下目前的问题列表,好像已经很多了。

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

到目前为止的问题:

> 函数原型优化 luaU_optchunk

> 打印函数原型 luaU_printchunk

> dump 函数原型 luaU_dumpchunk

> 内存分配 luaM_newvector

> ZIO 是什么

> 语法析 luaY_parser

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


Lua4.0 编译入口

标签:

原文地址:http://my.oschina.net/xhan/blog/490114

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!