第一版是針對 Lua 5.0 編寫的。雖然大部分內容仍然適用於後續版本,但仍有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買書籍,您也能 贊助 Lua 專案


24.1 – 第一個範例

我們將從一個應用程式範例開始這個概觀:一個獨立的 Lua 解譯器。我們可以撰寫一個原始的獨立解譯器,如下所示

警告:此程式碼適用於 Lua 5.0。要在 Lua 5.1 中執行,您必須將五個呼叫 luaopen_*(L) 變更為單一呼叫 luaL_openlibs(L)

    #include <stdio.h>
    #include <string.h>
    #include <lua.h>
    #include <lauxlib.h>
    #include <lualib.h>
    
    int main (void) {
      char buff[256];
      int error;
      lua_State *L = lua_open();   /* opens Lua */
      luaopen_base(L);             /* opens the basic library */
      luaopen_table(L);            /* opens the table library */
      luaopen_io(L);               /* opens the I/O library */
      luaopen_string(L);           /* opens the string lib. */
      luaopen_math(L);             /* opens the math lib. */
    
      while (fgets(buff, sizeof(buff), stdin) != NULL) {
        error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
                lua_pcall(L, 0, 0, 0);
        if (error) {
          fprintf(stderr, "%s", lua_tostring(L, -1));
          lua_pop(L, 1);  /* pop error message from the stack */
        }
      }
    
      lua_close(L);
      return 0;
    }
標頭檔 lua.h 定義 Lua 提供的基本函式。其中包括建立新的 Lua 環境(例如 lua_open)、呼叫 Lua 函式(例如 lua_pcall)、讀取和寫入 Lua 環境中的全域變數、註冊新的函式以供 Lua 呼叫,等等。在 lua.h 中定義的所有內容都帶有 lua_ 前綴。

標頭檔 lauxlib.h 定義輔助函式庫(auxlib)提供的函式。其所有定義都以 luaL_ 開頭(例如 luaL_loadbuffer)。輔助函式庫使用 lua.h 提供的基本 API 提供較高的抽象層級;所有 Lua 標準函式庫都使用 auxlib。基本 API 追求精簡和正交性,而 auxlib 則追求實用性以執行常見任務。當然,您的程式也可以非常容易地建立其他它需要的抽象。請記住,auxlib 無法存取 Lua 的內部。它透過官方基本 API 完成所有工作。

Lua 函式庫完全沒有定義任何全域變數。它將所有狀態保留在動態結構 lua_State 中,而且指向此結構的指標會傳遞為 Lua 內部所有函式的引數。此實作讓 Lua 可重新進入,並準備好在多執行緒程式碼中使用。

lua_open 函數會建立一個新的環境(或稱狀態)。當 lua_open 建立一個新的環境時,這個環境不包含任何預先定義的函數,甚至連 print 都沒有。為了讓 Lua 保持精簡,所有標準函式庫都以獨立套件的形式提供,因此您不必在不需要時使用它們。標頭檔 lualib.h 定義了開啟函式庫的函數。例如,呼叫 luaopen_io 會建立 io 表格,並在其中註冊 I/O 函數(io.readio.write 等)。

在建立一個狀態並使用標準函式庫填充它之後,就可以開始詮釋使用者的輸入了。對於使用者輸入的每一行,程式會先呼叫 luaL_loadbuffer 來編譯程式碼。如果沒有錯誤,呼叫會傳回零並將產生的區塊推入堆疊中。(請記住,我們將在下一個區段詳細討論這個「神奇」的堆疊。)然後,程式會呼叫 lua_pcall,它會從堆疊中彈出區塊並在受保護模式中執行它。與 luaL_loadbuffer 相同,如果沒有錯誤,lua_pcall 會傳回零。如果發生錯誤,這兩個函數都會在堆疊中推入一個錯誤訊息;我們可以使用 lua_tostring 取得這個訊息,並在列印它之後使用 lua_pop 將它從堆疊中移除。

請注意,如果發生錯誤,這個程式只會將錯誤訊息列印到標準錯誤串流中。真正的錯誤處理在 C 中可能相當複雜,而且處理方式會根據應用程式的性質而有所不同。Lua 核心從來不會直接將任何內容寫入任何輸出串流中;它會透過傳回錯誤碼和錯誤訊息來表示錯誤。每個應用程式都可以用最適合其需求的方式來處理這些訊號。為了簡化我們的討論,我們現在假設一個簡單的錯誤處理常式,如下所示,它會列印錯誤訊息、關閉 Lua 狀態,並退出整個應用程式

    #include <stdarg.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    void error (lua_State *L, const char *fmt, ...) {
      va_list argp;
      va_start(argp, fmt);
      vfprintf(stderr, argp);
      va_end(argp);
      lua_close(L);
      exit(EXIT_FAILURE);
    }
稍後我們將在應用程式程式碼中進一步討論錯誤處理。

由於您可以將 Lua 編譯為 C 和 C++ 程式碼,因此 lua.h 不包含在其他幾個 C 函式庫中存在的這個典型調整程式碼

    #ifdef __cplusplus
    extern "C" {
    #endif
       ...
    #ifdef __cplusplus
    }
    #endif
因此,如果您已將 Lua 編譯為 C 程式碼(最常見的情況)並在 C++ 中使用它,您必須如下所示包含 lua.h
    extern "C" {
    #include <lua.h>
    }
一個常見的技巧是建立一個包含上述程式碼的標頭檔 lua.hpp,並在您的 C++ 程式中包含這個新檔案。