Lua2.4 編譯器入口 luac.c

luac.c 是編譯器 luac 的入口文件。
老規矩,從 main 函數看起,看看這個過程當中程序都作了些什麼?

函數

int main(int argc, char* argv[])
{
 char* d="luac.out";            /* default output file */
 int i;
 for (i=1; i<argc; i++)
 {
  if (argv[i][0]!='-')            /* end of options */
   break;
  else if (IS("-"))            /* use stdin */
   break;
  else if (IS("-d"))            /* debug */
   lua_debug=1;
  else if (IS("-l"))            /* list */
   listing=1;
  else if (IS("-o"))            /* output file */
   d=argv[++i];
  else if (IS("-p"))            /* parse only (for timing purposes) */
   dumping=0;
  else if (IS("-v"))            /* show version */
   printf("%s  %s\n(written by %s)\n\n",LUA_VERSION,LUA_COPYRIGHT,LUA_AUTHORS);
  else                    /* unknown option */
   usage();
 }
 --i;                    /* fake new argv[0] */
 argc-=i;
 argv+=i;
 if (argc<2) usage();
 for (i=1; i<argc; i++)
  if (IS(d))
  {
   fprintf(stderr,"luac: will not overwrite input file \"%s\"\n",d);
   exit(1);
  }
 D=(dumping) ? fopen(d,"wb") : stdout;    /* must open in  binary mode */
 if (D==NULL)
 {
  fprintf(stderr,"luac: cannot open ");
  perror(d);
  exit(1);
 }
 for (i=1; i<argc; i++) compile(IS("-")? NULL : argv[i]);
 fclose(D);
 return 0;
}

看這個代碼的時候,最好參考一下 luac 的手冊,對比各類選項能看的更清楚點。

程序一開始就定義了一個默認的輸出文件,"luac.out"。

接下來,開始遍歷命令行的輸入,以得到用戶從命令行輸入的選項。

一旦程序遇到一個不是中劃線(減號 '-')打頭的選項,遍歷結束。
luac 的命令行選項的格式都是中劃線後加一個字符,以空白分割,這點和 unix 的傳統是同樣的。而且和通常的命令行程序操做界面也是一致的。

選項若是隻是一箇中劃線,使用標準輸入作爲輸入文件,遍歷結束。
這裏的 IS 是一個宏,這是 C 語言裏面的一個令代碼更有實際意義及更加容易閱讀的一個方法,Lua 的源代碼裏用到了很多的宏,除了能夠減小代碼量外,最重要的就是讓代碼更易讀,以及更有意義。

'-d' 調試選項,若是打開的話,程序會在生成字節碼的時候生成一些調試相關的信息。好比行號和其它一些方便調試的內容。有一些調試接口是隻在你打開調試時,它纔有意義。

'-l' 是否打印字節碼。

'-o' 設置輸出文件,輸出文件句直接在選項的後面,若是不使用這個選項,則使用上面提到的那個 luac.out 文件作爲輸出文件。

'-p' 只進行語法分析。

'-v' 顯示 Lua 的版本號,版權信息及做者。

不然,若是有錯誤的選項,調用 usage,打印使用方法。

ui

static void usage(void)
{
 fprintf(stderr,"usage: luac [-dlpv] [-o output] file ...\n");
 exit(0);
}

命令行選項遍歷退出時,說明這時命令行選項應該是到了 Lua 腳本的源代碼文件了。
若是參數個數不對,則也一樣調用 usage , 打印使用方法。

在對文件進行編譯以前,要先檢查一下 Lua 腳本文件是否和輸出文件同名了,若是同名,打印出錯信息並退出。就是這個 for 循環:
lua

 for (i=1; i<argc; i++)
  if (IS(d))
  {
   fprintf(stderr,"luac: will not overwrite input file \"%s\"\n",d);
   exit(1);
  }

打開輸出文件,若是不須要輸出的話,打開標準輸出做爲輸出。若是打開文件出錯,則打印錯誤並退出。
這裏的 dumping 標誌隻影響編譯後字節碼的輸出,其它過程無影響。
命令行

 D=(dumping) ? fopen(d,"wb") : stdout;    /* must open in  binary mode */
 if (D==NULL)
 {
  fprintf(stderr,"luac: cannot open ");
  perror(d);
  exit(1);
 }

最後一個 for 循環,是編譯全部的 Lua 腳本文件。
debug

 for (i=1; i<argc; i++) compile(IS("-")? NULL : argv[i]);

compile 函數的做用就是打開文件,編譯,並關閉文件。
unix

static void compile(char* filename)
{
 if (lua_openfile(filename)==NULL)
 {
  fprintf(stderr,"luac: cannot open ");
  perror(filename);
  exit(1);
 }
 do_compile();
 lua_closefile();
}

do_compile 編譯,並輸出。
調試

static void do_compile(void)
{
 TFunc* tf=new(TFunc);
 luaI_initTFunc(tf);
 tf->fileName = lua_parsedfile;
 lua_parse(tf);
 do_dump(tf);
}

do_dump 看名字能夠看出,作實際的 dump 工做的,也就是輸出字節碼,或者叫轉存字節碼。
code

static void do_dump(TFunc* tf)        /* only for tf==main */
{
 if (dumping) DumpHeader(D);
 while (tf!=NULL)
 {
  TFunc* nf;
  if (listing) PrintFunction(tf);
  if (dumping) DumpFunction(tf,D);
  nf=tf->next;                /* list only built after first main */
  luaI_freefunc(tf);
  tf=nf;
 }
}

這個文件結束了,不過,這裏有好幾個東西都沒有說,好比,上面的那個打開關閉文件是幹什麼的,以及爲何要那麼作?
do_compile 裏的 TFunc 是什麼?那個初始化是什麼?lua_parser 是什麼? do_dump 方法裏調的那幾個方法又分別是幹什麼的?

這些東西都會根據這裏調用的順序一點點慢慢的展示出來的。
接口

相關文章
相關標籤/搜索