第一版是针对 Lua 5.0 编写的。虽然在很大程度上仍然适用于后续版本,但有一些不同之处。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还将帮助 支持 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++ 程序中包含此新文件。