再看看另外的几个自带的程序,简单的分析一下。
test 目录里有几个 Lua 程序,其中 sort 子目录里又有两个 Lua 程序(这两个和外面的 sort.lua 差不多)。先看下 sort 目录里面的:q.lua,sort.lua里面都包含了一个快速排序和一个选择排序。不同的是,q.lua 把代码都写到了函数里,比如它的执行入口在最后一行 main(),而 sort.lua 则直接执行脚本。没有把执行入口放到函数里。这也是脚本语言和其它通用型语言(如 C 语言)不同的地方。在 C 语言里,默认的函数执行入口是 main 函数。而脚本语言则没有这个限制。看下代码,发现一个奇怪的地方,main 函数里调用 sort 时 sort 其实并没有定义,把选择排序的注释打开,运行了下,也是正常的。这个比较不合常理,比如在 C 语言里,调用函数之前,函数是要有前置声明或者是已经定义的。这是怎么回事?Lua 代码为什么能这样呢?原因其实很简单,Lua 脚本代码并不是一行行从上到下解释执行的,执行的是字节码,也就是把脚本代码编译为字节码之后才执行。虽然,在编译为字节码时 sort 还没有定义,但是,sort 在全局符号表已经注册了。等到下面 function sort(a,n) 函数定义的时候,把函数体存过去。在字节码执行的时候就都是定义过的了,这算是生成中间字节码的一个好处吧。由于这个脚本比较长,生成的字节码也很多,不再一句一句分析,只简单说一下。可以看到,字节码分成好几个 CODE 段,每一个函数为一个段,全局调用的部分也为一个段。这种安排倒是和汇编很像,汇编通过汇编器和链接器生成可执行程序,可执行程序交给真机 CPU 执行。Lua 脚本程序编译成字节码,交由 Lua 虚拟机执行。说点题外话,可以认为每一个 Lua 脚本程序是对 Lua 运行时(Lua 运行的环境和虚拟机)的一定程度上的扩展,这点倒和 Lisp 很像。Lua 实现时本身就是参考了 Scheme,使用了对用户友好的语法。到后面会看到,Lua 的语法分析器也是手写的,为了实现一次扫描就能生成字节码,一定程序上对语法做了限制,这也是为什么有时候有人问 Lua 中怎么没有某种写法或者某种写法怎么就是语法错误了的原因。扯的有点远,编译器前端是另一个话题了,还是回到正题。对比行号和字节码里的 SETLINE 指令比较容易看出脚本代码和字节码的对应关系。这里不再详细对比分析说明。简单说下 test 目录里的脚本代码都是干什么的。通过学习脚本代码,可以了解到当时的语法,这些代码有的还是比较实用的。 这里只是学习之用,如果有理解上的偏差的话,请以程序的实际执行结果为准。当然,如果真是要实用的话,建议还是用比较新的 Lua 版本,比如 5.1 或 5.2。因为比较新的版本用的人多,研究的人也比较多,各种资料也比较丰富。sort/q.luasort/sort.luasort.lua排序,包括快速排序和选择排序。array.lua新建数组,赋值,并遍历输出。dumpsave.lua递归保存 table,如果table 的元素为 table 也可以正常的保存。loop.luarepeat...until 循环split.lua分割文件路径与文件名teste.lua选择排序,这个可能是为了测下性能,数组元素 5000 个。type.luatable 的构造函数,可以对新建的 table 进行元素类型检查和赋默认值。至此,不再对 Lua1.1 脚本的使用做进一步的分析,具体的请参考手册,开始关注于它的实现。