首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用 Lua 编写可嵌入式脚本(1)

使用 Lua 编写可嵌入式脚本(1)

尽管诸如 Perl、Python、PHP 和 Ruby 之类的解释性编程语言日益被 Web 应用程序广泛地采纳 —— 它们已经长期用来实现自动化系统管理任务 —— 但是诸如 C、C++ 之类的编译性编程语言依然是必需的。编译性编程语言的性能是脚本语言所无法企及的(只有手工调优的汇编程序的性能才能超过它),有些软件 —— 包括操作系统和设备驱动程序 ——  只能使用编译代码来高效地实现。实际上,当软件和硬件需要进行无缝地连接操作时,程序员本能地就会选择 C 编译器:C 非常基础,距离 “原始金属材料非常近” —— 即可以操作硬件的很多特性 —— 并且 C 的表现力非常强大,可以提供高级编程结构,例如结构、循环、命名变量和作用域。
然而,脚本语言也有自己独特的优点。例如,当某种语言的解释器被成功移植到一种平台上以后,使用这种语言编写的大量脚本就可以不加任何修改在这种新平台上运行 —— 它们没有诸如系统特定的函数库之类的依赖限制。(我们可以考虑一下 Microsoft® Windows® 操作系统上的许多 DLL 文件和 UNIX® 及 Linux® 上的很多 libcs)。另外,脚本语言通常都还会提供高级编程构造和便利的操作,程序员可以使用这些功能来提高生产效率和灵活性。另外,使用解释语言来编程的程序员工作的速度更快,因为这不需要编译和链接的步骤。C 及其类似语言中的 “编码、编译、链接、运行” 周期缩减成了更为紧凑的 “编写脚本、运行”。
Lua 新特性与其他脚本语言一样,Lua 也有自己的一些特性:
  • Lua 类型。在 Lua 中,值可以有类型,但是变量的类型都是动态决定的。nil、布尔型、数字字符串 类型的工作方式与我们期望的一样。
    • Nil 是值为 nil 的一种特殊类型,用来表示没有值。
    • 布尔型的值可以是 true 和                                                        false 常量。(Nil 也可以表示 false,任何非 nil 的值都表示 true。)
    • Lua 中所有的数字都是双精度的(不过我们可以非常简便地编写一些代码来实现其他数字类型)。
    • 字符串是定长字符数组。(因此,要在一个字符串后面附加上字符,必须对其进行拷贝。)
  • 表、函数线程 类型都是引用。每个都可以赋值给一个变量,作为参数传递,或作为返回值从函数中返回。例如,下面是一个存储函数的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    -- example of an anonymous function
    -- returned as a value
    -- see http://www.tecgraf.puc-rio.br/~lhf/ftp/doc/hopl.pdf
    function add(x)
      return function (y) return (x + y) end
    end
    f = add(2)
    print(type(f), f(10))
    function  12




  • Lua 线程。线程是通过调用内嵌函数 coroutine.create(f) 创建的一个协同例程 (co-routine),其中 f 是一个 Lua 函数。线程不会在创建时启动;相反,它是在创建之后使用 coroutine.resume(t) 启动的,其中 t 就是一个线程。每个协同例程都必须使用 coroutine.yield() 偶尔获得其他协同例程的处理器。
  • 赋值语句。Lua 允许使用多种赋值语句,可以先对表达式进行求值,然后再进行赋值。例如,下面的语句:

    1
    2
    3
    4
    i = 3
    a = {1, 3, 5, 7, 9}
    i, a, a[i+1], b = i+1, a[i+1], a
    print (i, a[3], a[4], b, I)





                                            会生成 4 7 5 nil nil。如果变量列表的个数大于值列表的个数,那么多出的变量都被赋值为 nil;因此,b 就是 nil。如果值的个数多于变量的个数,那么多出的值部分就会简单地丢弃。在 Lua 中,变量名是大小写敏感的,这可以解释为什么 I 的值是 nil。
  • 块(Chunk)。 可以是任何 Lua 语句序列。块可以保存到文件中,或者保存到 Lua 程序中的字符串中。每个块都是作为一个匿名函数体来执行的。因此,块可以定义局部变量和返回值。
  • 更酷的东西。Lua 具有一个标记-清理垃圾收集器。在 Lua 5.1 中,垃圾收集器是以增量方式工作的。Lua 具有完整的词法闭包(这与 Scheme 类似,而与 Python 不同)。Lua 具有可靠的尾部调用语义(同样,这也与 Scheme 类似,而与 Python 不同)。
Programming in Lua 和 Lua-users wiki (链接请参见后面的  部分)中可以找到更多 Lua 代码的例子。
在所有的工程任务中,要在编译性语言和解释性语言之间作出选择,就意味着要在这种环境中对每种语言的优缺点、权重和折中进行评测,并接受所带来的风险。
在两个世界之间最好地进行混合如果您希望充分利用这两个世界的优点,应该怎样办呢,是选择最好的性能还是选择高级强大的抽象?更进一步说,如果我们希望对处理器密集且依赖于系统的算法和函数以及与系统无关且很容易根据需要而进行修改的单独逻辑进行优化,那又当如何呢?
对高性能代码和高级编程的需要进行平衡是 Lua(一种可嵌入式脚本语言)要解决的问题。在需要时我们可以使用编译后的代码来实现底层的功能,然后调用 Lua 脚本来操作复杂的数据。由于 Lua 脚本是与编译代码独立的,因此我们可以单独修改这些脚本。使用 Lua,开发周期就非常类似于 “编码、编译、运行、编写脚本、编写脚本、编写脚本 ...”。
例如,Lua Web 站点 “使用” 页面(请参见 )列出了主流市场上的几个计算机游戏,包括 World of Warcraft 和(家用版的)Defender,它们集成 Lua 来实现很多东西,从用户界面到敌人的人工智能都可以。Lua 的其他应用程序包括流行的 Linux 软件更新工具 apt-rpm 的扩展机制,还有 “Crazy Ivan” Robocup 2000 冠军联赛的控制逻辑。这个页面上的很多推荐感言都对 Lua 的小巧与杰出性能赞不绝口。
开始使用 LuaLua 5.0.2 版本是撰写本文时的最新版本,不过最近刚刚发布了 5.1 版本。您可以从 lua.org 上下载 Lua 的源代码,在 Lua-users wiki(链接请参见 参考资料)上可以找到预先编译好的二进制文件。完整的 Lua 5.0.2 核心文件中包括了标准库和 Lua 编译器,不过只有 200KB 大小。
如果您使用的是 Debian Linux,那么可以以超级用户的身份运行下面的命令来快速安装 Lua 5.0:
1
# apt-get install lua50




本文中给出的例子都是在 Debian Linux Sarge 上运行的,使用的是 Lua 5.0.2 和 2.4.27-2-686 版本的 Linux 内核。
在系统上安装好 Lua 之后,我们可以首先来试用一下单独的 Lua 解释器。(所有的 Lua 应用程序必须要嵌入到宿主应用程序中。解释器只是一种特殊类型的宿主,对于开发和调试工作来说非常有用。)创建一个名为 factorial.lua 的文件,然后输入下面的代码:
1
2
3
4
5
6
7
8
9
10
11
12
-- defines a factorial function
function fact (n)
  if n == 0 then
    return 1
  else
    return n * fact(n-1)
  end
end

print("enter a number:")
a = io.read("*number")
print(fact(a))




factorial.lua 中的代码 —— 更确切地说是任何 Lua 语句序列 —— 都称为一个,这在上面的  中已经进行了介绍。要执行刚才创建的代码块,请运行命令 lua factorial.lua:
1
2
3
4
$ lua factorial.lua
enter a number:
10
3628800




或者像在其他解释性语言中一样,我们可以在代码顶部添加一行 “标识符”(#!),使这个脚本变成可执行的,然后像单独命令一样来运行这个文件:
1
2
3
4
5
6
$ (echo '#! /usr/bin/lua'; cat factorial.lua) > factorial
$ chmod u+x factorial
$ ./factorial
enter a number:
4
24

返回列表