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

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

-------------------
7.1 栈和函数信息
-------------------
获得解释器栈信息的主要函数是:
    int lua_getstack (lua_State *L, int level, lua_Debug *ar);
它用给定层级上正在执行的一个活动记录标识填充部分 lua_Debug 结构。0 级是正在运行的函数,层级 n+1 是调用层级 n 的函数。通常,lua_getstack 返回 1 ;当以一个高于栈的深度的层次来调用时,它返回 0 。

结构 lua_Debug 用来携带一个活动函数的不同信息片段:
    typedef struct lua_Debug {
      const char *event; /* "call", "return" */
      int currentline; /* (l) */
      const char *name; /* (n) */
      const char *namewhat; /* (n) global, tag method, local, field */
      int nups; /* (u) number of upvalues */
      int linedefined; /* (S) */
      const char *what; /* (S) "Lua" function, "C" function, Lua "main" */
      const char *source; /* (S) */
      char short_src[LUA_IDSIZE]; /* (S) */
      /* private part */
      ...
    } lua_Debug;
lua_getstack 只填充这个结构的私有部分,为后来使用。用有用信息填充 lua_Debug 其它的字段,调用
    int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
这个函数出错时返回 0 (例如,一个 what 的无效选项)。字符串 what 中的每个字符选择一些被填充的 ar 的字段,如上面 lua_Debug 的定义中被一个括号中的字母标识出来的: `S‘ 填充字段 source, linedefined, 和 what; `l‘ 填充字段 currentline, 等。而且, `f‘ 压栈在给定层级上正在执行的函数。
为获得一个不活动函数的信息(即,不在栈里),可以把函数压栈,并字符 > 放在字符串 what 的起头。例如,为了获取一个函数 f 在哪里定义,你可以
    lua_Debug ar;
    lua_getglobal(L, "f");
    lua_getinfo(L, ">S", &ar);
    printf("%d\n", ar.linedefined);

lua_Debug 的字段有下列意思
source
    如果函数被定义在字符串中,source 就是那个字符串;如果函数定义在一个文件中,source 由 @ 开始并后跟文件名。
short_src
    一个 ``printable‘‘ 版本的 source,用在错误信息中。
linedefined
    函数定义开始处的等号。
what
    字符串 "Lua" 如果这是一个 Lua 函数, "C" 如果这是一个 C 函数, 或者 "main" 如果这是一个块的主要部分。
currentline
    给定函数正在执行的当前行。如果没有行信息, currentline 被设置为 -1.
name
    一个给定函数的合理的名字。因为函数在 Lua 中第一类值,它们没有一个固定的名字:一些函数可能是很多全局变量的值,而其它的可能只保存在一个表的字段中。lua_getinfo 函数检查给定的函数是标签方法或者是一个全局变量的名字。如果给定函数是一个标签方法,那么 name 指向相应的事件名。如果给定的函数是一个全局变量的值,那么 name 指向变量名字。如果给定函数既不是一个标签方法也不是一个全局变量,name 被设置为 NULL。
namewhat
    解释之前的字段。如果函数是一个全局变量,namewhat 是 "global";如果函数是一个标签方法,namewhat 是 "tag-method";否则,namewhat 是 "" (空字符串)。
nups
    一个函数的 upvalue 的个数。

-------------------
7.2 局部变量的操作
-------------------
luadebug.h 使用索引来操纵局部变量:第一个参数或者局部变量的索引为 1,以此类推,直到最后一个活动的局部变量。
下面的函数可以用来操纵给定活动记录的局部变量:
    const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
    const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
参数 ar 必须是一个有效的活动记录,被之前的 lua_getstack 调用填充或者作为一个 hook 参数给定(参见 7.3 节)。函数 lua_getlocal 获得一个局部变量(n)的索引,把它的值压栈,并返回它的名字。对于 lua_setlocal,你把新值压栈,这个函数把新值赋给那个变量并返回它的名字。两个函数失败时均返回 NULL;如果索引大于活动局部变量的时候这处情况就会发生。
作为一个例子,下面的函数列出一个在栈的给定层次上的所有的局部变量的名字:
    int listvars (lua_State *L, int level) {
      lua_Debug ar;
      int i = 1;
      const char *name;
      if (lua_getstack(L, level, &ar) == 0)
        return 0; /* failure: no such level in the stack */
      while ((name = lua_getlocal(L, &ar, i++)) != NULL) {
        printf("%s\n", name);
        lua_pop(L, 1); /* remove variable value */
      }
      return 1;
    }

-------------------
7.3 钩子 (Hooks)
-------------------
Lua 解释器为调试提供了两个钩子(Hook),一个 call hook, 一个 line hook。它两个有相同的类型:
    typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
你可以使用下面的函数来设置它们:
    lua_Hook lua_setcallhook (lua_State *L, lua_Hook func);
    lua_Hook lua_setlinehook (lua_State *L, lua_Hook func);
钩子是无效的如果它的值为 NULL ,NULL 也是两个钩子的默认值。函数 lua_setcallhook 和 lua_setlinehook 设置他们相应的钩子并返回它们之前的值。

当解释器进入或者离开一个函数时,call hook 会被调用。ar 的 event 字段的字符串是 "call" 或者 "return"。这个 ar 之后可以被用在调用 lua_getinfo, lua_getlocal, 和 lua_setlocal 去获得更多的关于函数和操纵局部变量的信息。

当解释器每次改变它执行的代码行号时会调用 line hook。ar 的字符 event 的字符串是 "line" , 并且 currentline 字段有行号。再次强调,你可以使用这个 ar 在其它的调用 API 的调用中。

当 Lua 在执行一个钩子时,它禁用了其它的钩子的调用。因此,如果一个钩子调用 Lua 去执行一个函数或者一个块,这个执行将不会再有其它的钩子调用。

-------------------
7.3 自反的调用接口
-------------------
库 ldblib 为 Lua 程序提供调试接口的功能。如果你想使用这个库,你的宿主应用程序必须打开它,通过调用 lua_dblibopen。

当使用这个库时你应该万分小心。这里提供的函数应该仅仅用于调试或者类似的任务(例如,性能分析)。请抵制把他们作为常用工具的诱惑。它们很慢并且违反了一些语言的安全性。(例如,局部变量的私密性)。作为一个一般性规则,如果你的程序不需要这个库,不要打开它。

getinfo (function, [what])
这个函数返回一个带有函数信息的表。你可以直接给出函数,或者你可以给出一个数字作为函数的值,它意味着函数正在栈上执行的函数的层次:Level 0 是当前的函数(getinfo 它自己);Level 1 是调用 getinfo 的函数;以此类推。如果函数的值比活动函数的个数多,那么 getinfo 返回 nil。
返回的表包含所有由 lua_getinfo 返回的字段,用一个字符串 what 来描述获取什么。what 的默认值是获得所有的可用信息。
例如,表达式 getinfo(1, "n").name 返回当前函数的名字,如果可以找到一个合理的名字,getinfo(print) 返回一个关于 print 函数的所有可用信息的表。

getlocal (level, local)
函数返回局部变量的名字和值,局部变量的 index 为 local ,它位于栈上的层级 level 的函数中。(第一个参数或者局部变量的 index 为 1,以此类推,直到最后一个活动的局部变量。)函数返回 nil 如果没有给定索引的局部变量,并发生一个错误当以一个范围之外的 level 调用时。(你可以调用 getinfo 去检查 level 是否有效。)
setlocal (level, local, value)
函数设置局部变量的值为 value,局部变量的 index 为 local ,它位于栈上的层级 level 的函数中。函数返回 nil 如果没有给定索引的局部变量,并发生一个错误当以一个范围之外的 level 调用时。

setcallhook (hook)
设置函数 hook 为调用钩子;这个钩子在每次解释器开始或者退出一个函数执行时将会被调用。调用钩子唯一的参数是事件名称("call" 或者 "return")。你可以以 level 2 调用 getinfo 去获得更多的正在被调用或正在返回的函数信息(level 0 是 getinfo 函数,level1 是钩子函数)。当无参调用时,这个函数关闭调用钩子。setcallhook 返回老的钩子。
setlinehook (hook)
设置函数 hook 为行钩子;这个钩子在每次解释器改变正在执行的代码的行时将会被调用。行钩子的唯一参数是解释器将要执行的行号。当无参调用时,这个函数关闭调用钩子。setlinehook 返回老的钩子。

--------------------------------------
8 独立执行的 Lua
--------------------------------------
尽管 Lua 被设计作为一个扩展语言,被嵌入到一个 C 宿主程序,它也经常被做为一个独立的语言使用。一个作为独立语言使用的 Lua 解释器,叫做简单的 lua,在标准发布版中被提供。这个程序可以被以下的参数以任意顺序调用:
-sNUM
    设置栈的大小为 NUM(如果存在,这必须是第一个选项);
-
    把标准输入作为文件执行。
-c
    调用 lua_close 在执行完所有参数之后;
-e \rmstat
    执行字符串 stat;
-f filename
    执行文件 filename 所有剩余的参数在表 arg 中;
-i
    进入交互模式,显示一个提示符;
-q
    进入交互模式,不显示提示符。
-v
    打印版本信息;
var=value
    设置全局变量 var 为字符串 "value";
filename
    执行文件 filename。

当无参调用时,lua 的行为和 lua -v -i 一样当标准输入是一个终端时,否则像 lua - 。
所有的参数按顺序处理,除了 -c 。例如,一个调用
    $ lua -i a=test prog.lua
将首先和用户交互直到一个 EOF 出现在标准输入中,然后设置 a 为 "test",最后执行文件 prog.lua。(这里,$ 是一个 shell 提示符。你的提示符可能与此不同。)
当选项 -f filename 被使用时,所有命令行中剩余的参数放进一个叫做 arg 的表中被传给 Lua 程序 filename 。在这个表中,字段 n 获得最后的参数的索引,字段 0 获得 "filename"。例如,在调用
    $ lua a.lua -f b.lua t1 t3
解释器首先执行文件 a.lua,然后新建一个表
    arg = {"t1", "t3"; n = 2, [0] = "b.lua"}
最后,执行文件 b.lua。独立的解释器也提示了一个 getargs 函数可以用来存取所有的命令行参数。例如,如果你这样调用 Lua
    $ lua -c a b
那么一个 getargs 的调用在 a 或者 b 中将返回表
    {[0] = "lua", [1] = "-c", [2] = "a", [3] = "b", n = 3}
在交互模式中,一个多行的句子可以在行尾以反斜杠结束。如果全局变量 _PROMPT 被定义为一个字符串,那么它的值将被用做提示符。所以,提示符可以直接在命令行中修改:
    $ lua _PROMPT=‘myprompt> ‘ -i
或者在任意的 Lua 程序中给 _PROMPT 赋值。
在 Unix 系统中,Lua 脚本可以被设置为可执行的程序,使用 chmod +x 和 #! 格式,像在 #!/usr/local/bin/lua, 或者 #!/usr/local/bin/lua -f 去获得其它的参数。

--------------------------------------
鸣谢
--------------------------------------
作者要感谢 CENPES/PETROBROBAS 和 TeCGraf 一起,使用该系统的早期版本,并提出宝贵意见。作者还要感谢 Carlos Henrique Levy,为这个语言起了个名字。Lua 在葡萄牙语里是月亮的意思。
--------------------------------------
其它(略)
--------------------------------------
和之前版本的不兼容及索引。
--------------------------------------
Lua 完整的语法
--------------------------------------
chunk ::= {stat [`;‘]}
block ::= chunk
stat ::= varlist1 `=‘ explist1
| functioncall
| do block end
| while exp1 do block end
| repeat block until exp1
| if exp1 then block {elseif exp1 then block} [else block] end
| return [explist1]
| break
| for `name‘ `=‘ exp1 `,‘ exp1 [`,‘ exp1] do block end
| for `name‘ `,‘ `name‘ in exp1 do block end
| function funcname `(‘ [parlist1] `)‘ block end
| local declist [init]
funcname ::= `name‘ | `name‘ `.‘ `name‘ | `name‘ `:‘ `name‘
varlist1 ::= var {`,‘ var}
var ::= `name‘ | varorfunc `[‘ exp1 `]‘ | varorfunc `.‘ `name‘
varorfunc ::= var | functioncall
declist ::= `name‘ {`,‘ `name‘}
init ::= `=‘ explist1
explist1 ::= {exp1 `,‘} exp
exp1 ::= exp
exp ::= nil | `number‘ | `literal‘ | var | function | upvalue
| functioncall | tableconstructor | `(‘ exp `)‘ | exp binop exp | unop exp
functioncall ::= varorfunc args | varorfunc `:‘ `name‘ args
args ::= `(‘ [explist1] `)‘ | tableconstructor | `literal‘
function ::= function `(‘ [parlist1] `)‘ block end
parlist1 ::= `...‘ | `name‘ {`,‘ `name‘} [`,‘ `...‘]
upvalue ::= `%‘ `name‘
tableconstructor ::= `{‘ fieldlist `}‘ fieldlist ::= lfieldlist | ffieldlist | lfieldlist `;‘ ffieldlist | ffieldlist `;‘ lfieldlist lfieldlist ::= [lfieldlist1] ffieldlist ::= [ffieldlist1] lfieldlist1 ::= exp {`,‘ exp} [`,‘] ffieldlist1 ::= ffield {`,‘ ffield} [`,‘] ffield ::= `[‘ exp `]‘ `=‘ exp | `name‘ `=‘ exp
binop ::= `+‘ | `-‘ | `*‘ | `/‘ | `\^{ ‘ | `..‘
| `<‘ | `<=‘ | `>‘ | `>=‘ | `==‘ | `\ { ‘=}
| and | or}
unop ::= `-‘ | not

时间: 2024-08-29 14:38:50

Lua4.0 参考手册(九)7-8的相关文章

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 参考手册(六)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 

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

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

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 参考手册(四)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