Lua4.0 参考手册(六)5.8-5.14

(接上篇)
-------------------
5.8 执行 Lua 代码
-------------------
一个宿主程序可以执行写在文件中或在字符串中的 Lua 块,使用下面的函数:

    int lua_dofile (lua_State *L, const char *filename);
    int lua_dostring (lua_State *L, const char *string);
    int lua_dobuffer (lua_State *L, const char *buff,
                      size_t size, const char *name);

这些函数返回 0 表示成功,或者失败时返回一个错误码:
> LUA_ERRRUN - 执行模块时出错。
> LUA_ERRSYNTAX - 预编译时语法错误。
> LUA_ERRMEM - 内存分配错误。对于此类错误,Lua 不会调用 _ERRORMESSAGE (参见 4.7 节)。
> LUA_ERRERR - 执行 _ERRORMESSAGE 时出错。对于此类错误,Lua 不会再次调用 _ERRORMESSAGE ,以免死循环。
> LUA_ERRFILE - 打开文件错误(只针对 lua_dofile)。在这种情况下,你可能想要检查 errno,调用 strerror,或者调用 perror 去告诉用户哪里出了问题。

这些常量定义在 lua.h 中。

当通过 NULL 参数调用时,lua_dofile 执行标准输入流。lua_dofile 和 lua_dobuffer 都可以执行预编译的块。它们自动检测出块是文本或者二进制,并相应地加载它(参见程序 luac)。lua_dostring 只执行文本格式的源代码。

lua_dobuffer 的第三个参数是块的名字,它用在错误信息和调试信息中。如果名字是 NULL,Lua 会给块一个默认的名字。

这些函数把块最终返回的结果压栈。一个块可以返回任意数量的值;Lua 保证这些值可以存放到栈空间中,但是调用之后就需要你自己维护栈空间了。如果你需要压栈其它的元素在调用这些函数之后,并且你想安全地使用栈空间,你必须要么通过 lua_stackspace 来检查栈空间,要求从栈同移除元素(如果你不需要它们的话)。例如,下面的代码加载一个文件中的块并且丢弃所有的这个块返回的结果,把栈恢复为调用之间的状态:

   {
    int oldtop = lua_gettop(L);
    lua_dofile(L, filename);
    lua_settop(L, oldtop);
   }

-------------------
5.9 操纵 Lua 中的全局变量
-------------------
可以使用下面的函数读取 Lua 全局变量的值:

    void lua_getglobal (lua_State *L, const char *varname);

它将会把给定变量的值压栈。在 Lua 中,这个函数可能触发一个标签方法 ``getglobal‘‘(参见 4.8 节)。为了读取全局变量真正的值,而不唤起任何标签方法,在全局表上使用 lua_rawget(参见下面)。

保存一个值到全局变量,调用

    void lua_setglobal (lua_State *L, const char *varname);

它出栈需要保存到给定变量的值。在 Lua 中,这个函数可能会触发一个标签方法 ``setglobal‘‘ (参见 4.8 节)。为了设置全局变量的真正的值,而不唤起任何标签方法,在全局表上使用 lua_rawset (参见下面)。

所有的全局变量都保存在一个普通的表中。你可以获得这个表通过调用

    void lua_getglobals (lua_State *L);

它把当前的全局变量的表压栈。为设置其它的表作为全局变量的表,调用

    void lua_setglobals (lua_State *L);

将要使用的表出栈。
-------------------
5.10 操纵 Lua 中的表
-------------------
Lua 表也可以通过 API 来操作。
为读取表中的值,表必须在栈的某个地方。在这种情况下,调用

    void lua_gettable (lua_State *L, int index);

这里 index 指定表。lua_gettable 出栈一个 key,并且返回(在栈上)表在 key 处的内容。在 Lua 中,这个操作可能会触发一个标签方法 ``gettable‘‘ 。为了获得表的 key 的真正值,而不唤起任何标签方法,使用 raw 版本的:

    void lua_rawget (lua_State *L, int index);

为保存一个值到表中,表已经在栈的某个地方了,你压栈 key 和值(以这种顺序),然后调用

    void lua_settable (lua_State *L, int index);

这里的 index 指定表。lua_settable 出栈 key 和 value。在 Lua 中,这个操作可能会触发一个标签方法 ``settable‘‘ 。为了设置任意表的 index 的真正值,而不唤起任何标签方法,使用 raw 版本的:

    void lua_rawset (lua_State *L, int index);

最后,函数

    void lua_newtable (lua_State *L);

创建一个新的空表并压栈。

-------------------
5.11 把表作为数组使用
-------------------
有 API 函数可以使用 Lua 表作为数组,也就是说,表的索引都有数值:

    void lua_rawgeti (lua_State *L, int index, int n);
    void lua_rawseti (lua_State *L, int index, int n);
    int lua_getn (lua_State *L, int index);

lua_rawgeti 获得在栈的 index 处表的第 n 个元素。

lua_rawseti 设置在栈的 index 处表的第 n 个元素为栈顶的值。

lua_getn 返回在栈 index 处表的元素个数。这个数值是表中字段 n 的值,如果它有一个数值型值,或者表中最大的数值型索引不是一个 nil 值。

-------------------
5.12 调用 Lua 函数
-------------------
定义在 Lua 中的函数(或者注册到 Lua 的 C 函数)可以从宿主程序调用。这采用如下协议:首先,被调用的函数压栈;然后,函数的参数以直接顺序压栈(参见 5.5 节),即,第一个参数先压栈。最后,函数被调用通过:

    int lua_call (lua_State *L, int nargs, int nresults);

这个函数返回和 lua_dostring (参见 5.8 节)同样的错误码。如果你想传播这个错误,而不是返回一个错误码,使用

    void lua_rawcall (lua_State *L, int nargs, int nresults);

在这两个函数中,nargs 是你压栈的参数的个数。所有的参数和函数值都从栈中弹出,函数的返回值压栈。函数的返回值被调整(参见 4.3 节)为 nresults,除非 nresults 是 LUA_MULTRET。在这种情况下,所有的函数返回值都压栈。函数的返回值以直接顺序压栈(第一个返回值最先压栈),所以调用之后最后一个返回值在栈顶。
下面的例子显示宿主程序如何做到和 Lua 代码等价的:

    a,b = f("how", t.x, 4)

在 C 中:

    lua_getglobal(L, "t"); /* global `t‘ (for later use) */
    lua_getglobal(L, "f"); /* function to be called */
    lua_pushstring(L, "how"); /* 1st argument */
    lua_pushstring(L, "x"); /* push the string `x‘ */
    lua_gettable(L, -4); /* push result of t.x (2nd arg) */
    lua_pushnumber(L, 4); /* 3rd argument */
    lua_call(L, 3, 2); /* call function with 3 arguments and 2 results */
    lua_setglobal(L, "b"); /* set global variable `b‘ */
    lua_setglobal(L, "a"); /* set global variable `a‘ */
    lua_pop(L, 1); /* remove `t‘ from the stack */

注意,上面的代码是平衡的:在它结束时,栈被回退为它的原来配置。这被认为是好的编译实践。

一些特别的 Lua 函数有它们自己的 C 接口。宿主程序可以生成一个 Lua 错误通过调用函数

    void lua_error (lua_State *L, const char *message);

这个函数永远不返回。如果 lua_error 被从 Lua 调用的 C 函数中调用,相应的 Lua 执行被终结,就如同 Lua 代码中发生了一个错误。否则,整个宿主程序被一个 exit (EXIT_FAILURE)调用终止。在终结执行之前,message 被传递给错误处理函数 _ERRORMESSAGE (参见 4.7 节)。如果 message 为 NULL, _ERRORMESSAGE 便不会被调用。

标签方法可以通过下面的函数改变

    void lua_settagmethod (lua_State *L, int tag, const char *event);

第二个参数是标签,第三个参数是事件名字(参见 4.8 节);新的方法从栈上弹出。为获得当前的
标签方法的值,使用函数

    void lua_gettagmethod (lua_State *L, int tag, const char *event);

可以拷贝所有的标签方法从一个标签到另一个:

    int lua_copytagmethods (lua_State *L, int tagto, int tagfrom);

这个函数返回 tagto。
你可以遍历一个表通过函数

    int lua_next (lua_State *L, int index);

这里 index 指定被遍历的表。这个函数从栈中弹出一个 key,并从表中压栈一个 key-value 对(也就是给定 key 的下一个键值对)。如果没有元素了,函数返回 0 (不压栈)。一个典型的调用如下:

    /* table is in the stack at index `t‘ */
    lua_pushnil(L); /* first key */
    while (lua_next(L, t) != 0) {
      /* `key‘ is at index -2 and `value‘ at index -1 */
      printf("%s - %s\n",
        lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
      lua_pop(L, 1); /* removes `value‘; keeps `index‘ for next iteration */
    }

函数

    void lua_concat (lua_State *L, int n);

连接栈顶的 n 个值,弹出它们,并且压栈结果;n 最小为 2 。连接操作遵守 Lua 通用的语义(参见 4.5.5 节)。

-------------------
5.13 定义 C 函数
-------------------
注册 C 函数到 Lua ,用下面的宏:

    #define lua_register(L, n, f) (lua_pushcfunction(L, f), lua_setglobal(L, n))
    /* const char *n; */
    /* lua_CFunction f; */

它接受函数在 Lua 中的名字,和一个函数指针。这个指针的类型必须为 lua_CFunction,其定义为:

    typedef int (*lua_CFunction) (lua_State *L);

也就是一个 Lua 环境参数一个整型返回值的函数指针。

为了和 Lua 正确的交互,C 函数必须遵守下面的协议,这个协议规定了参数和返回值传递的方法:C 函数在栈里得到它从 Lua 获得的参数,以直接顺序(第一个参数最先压栈)。为了返回值到 Lua, C 函数可以把返回值顺序压栈(第一个返回值最先压栈),并且返回结果的个数。就像 Lua 函数一样,一个由 Lua 调用的 C 函数也可以返回多个值。

作为一个例子,下面的函数接受一个可变个数的数值型参数并且返回它们的平均数和总数:

    static int foo (lua_State *L) {
      int n = lua_gettop(L); /* number of arguments */
      double sum = 0;
      int i;
      for (i = 1; i <= n; i++) {
        if (!lua_isnumber(L, i))
          lua_error(L, "incorrect argument to function `average‘");
        sum += lua_tonumber(L, i);
      }
      lua_pushnumber(L, sum/n); /* first result */
      lua_pushnumber(L, sum); /* second result */
      return 2; /* number of results */
    }

函数可以作为 ‘average‘ 注册到 Lua ,通过调用

    lua_register(L, "average", foo);

当新建一个 C 函数时,可以为它关联一些 upvalue (参见 4.6 节),从而新建一个 C 闭包,当函数被调用时这些值被传递给它,作为普通的参数。为了为了一个 C 函数关联 upvalue,首先这些值应该压栈。然后函数

    void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

被用来压栈 C 函数,参数 n 说明应该有多少个 upvalue 被关联到函数(这些 upvalue 从栈上弹出);事实上,宏 pushcfunction 被定义为参数 n 为 0 的 lua_pushcclosure 。然后,无论何时 C 函数被调用时,这些 upvalue 被插入函数作为最后的参数,在函数调用的实际参数之后。这使得程序容易获得 upvalue 而不必知道函数接受多少个参数(回忆一下,Lua 中的函数可以接受任意数量的参数):第 i 个 upvalue 在栈里的索引为 i-(n+1),这里 n 为 upvalue 的个数。
更多的 C 函数和闭包的例子,参见官方发布版中的文件 lbaselib.c, liolib.c, lmathlib.c, 和 lstrlib.c 。

-------------------
5.14 Lua 对象的引用
-------------------
如果一个 C 代码需要在一个 C 函数的生存期之外保持一个 Lua 值的话, 它必须新建那个值的引用(reference)。下面的函数可以管理这种引用:

    int lua_ref (lua_State *L, int lock);
    int lua_getref (lua_State *L, int ref);
    void lua_unref (lua_State *L, int ref);

lua_ref 从栈顶弹出一个值,新建一个它的引用,并返回这个引用。一个 nil 值的引用永远为 LUA_REFNIL。(lua.h 也定义了一个不同于其它的有效引用的常量 LUA_NOREF 。)如果 lock 不是 0 的话,对象就被锁定:这意味着这个对象将不会被垃圾回收。没有锁定的引用可被垃圾回收。

当 C 中需要引用对象的时候,调用 lua_getref 把那个对象压栈;如果对象已经被垃圾回收了,lua_getref 返回 0 (不压栈任何东西)。

当一个引用不需要了,应该使用 lua_unref 调用来释放它。

注册
当 Lua 启动时,它在位置 LUA_REFREGISTRY 注意一个表。它可以通过宏来引用

  #define lua_getregistry(L) lua_getref(L, LUA_REFREGISTRY)

这个表可以被 C 库作为一个注册机制使用。任何 C 库可以在这个表中保存数据,只要它使用的 key 不同于其它的库。
(未完待续)

时间: 2024-11-05 21:49:38

Lua4.0 参考手册(六)5.8-5.14的相关文章

Lua4.0 参考手册(二)4.1-4.4

(接上篇)--------------------------------------4 语言--------------------------------------这节描述 Lua 的词法,语法和语义. -------------------4.1 词法约定-------------------Lua 中的标识符可以是任何字母,数字,下划线组成的字符串,且首字母不可为数字.这符合大多数语言中标识符的定义,除了字母的字义依赖于当前的区域设置:所有的在当前的区域设置中被认为是字母的字符可以被用

Lua4.0 参考手册(一)1-3

说明:这个文档是 doc 目录里的 manual.html 文件.原文版权归原作者所有,这篇翻译只是作为学习之用.如果翻译有不当之处,请参考原文.-------------------以下是正文-------------------编程语言 Lua4.0 的参考手册--------------------------------------1 简介--------------------------------------Lua 是一个扩展编程语言,支持通用编程功能与数据描述功能.作为一个强大

Lua4.0 参考手册(八)6.2-6.5

(接上篇)-------------------6.2 字符串处理-------------------这个库提供字符串处理的通用函数,如查找,提取子串和模式匹配.在 Lua 中索引一个字符串的时候,第一个字符的索引是 1(不像 C 中是 0).另外,索引可以为负数,负数被解释为逆向索引,从字符串的结尾开始.所以,最后一个字符位置是 -1,以此类推. strbyte (s [, i])返回 s 的第 i 个字符的内部数值码(例如:ASCII 码).如果没有 i,它被认为是 1 .i 可以为负.

Lua4.0 参考手册(七)6.1

(接上篇)--------------------------------------6 标准库--------------------------------------标准库提供了一些有用的函数,这些函数直接由标准 API 实现.因此,它们并非语言必需的部分,并且作为单独的 C 模块被提供.目前,Lua 有以下标准库:> 基本库:> 字符串处理:> 数学函数(sin, log, 等)> 输入输出(和一些系统功能) 为了能使用这些库,宿主程序必须调用函数 lua_baselibo

Lua4.0 参考手册(五)5.1-5.7

(接上篇)--------------------------------------5 API--------------------------------------这节描述 Lua 的 API, 也就是宿主程序和 Lua 交互的一组 C 函数.所有的 API 函数和相关联的类型及常量都在文件 lua.h 中声明. 所有的 API 提供的功能都可以由宏来替代,即使当我们使用术语函数(``function'').因为这样的宏只使用它的参数一次,所以不会产生隐蔽的副作用. ----------

Lua4.0 参考手册(三)4.5

(接上篇)-------------------4.5 表达式----------------------------4.5.1 基本表达式---------Lua 中基本表达式是:    exp ::= `(' exp `)'    exp ::= nil    exp ::= number    exp ::= literal    exp ::= var    exp ::= upvalue    exp ::= function    exp ::= functioncall    ex

Lua4.0 参考手册(九)7-8

(接上篇)--------------------------------------7 调试接口--------------------------------------Lua 没有内置的调试功能.而是借助于函数和钩子(hook)提供了一个特殊接口,可以用来构建不同种类的调试器,分析器(profile)和一些其它的需要解释器内部信息的工具.这个接口在 luadebug.h 文件中声明. -------------------7.1 栈和函数信息-------------------获得解释器

Lua4.0 参考手册(四)4.6-4.8

(接上篇)-------------------4.6 可见性和 Upvalue-------------------一个函数体可以引用它自己的局部变量(包括它的参数)和全局变量,只要它们没有被函数中同名的局部变量所隐藏(shadowed ).一个不可以使用包含它的函数的局部变量,因为这样的变量可能在函数调用的时候已经不存在了.然而,一个函数可通过 upvalue 使用包含它的函数中的局部变量.upvalue 的语法如下:    upvalue ::= `%' name一个 upvalue 多少

Vue.js 2.0 参考手册.CHM下载

下载地址 Vue.js 2.0 参考手册.CHM下载链接: http://pan.baidu.com/s/1kVbhd4b 密码: wxfh