Lua1.1 Lua 的参考手册 (一)

转载出处:http://my.oschina.net/xhan/blog/310016

 

说明:

这个文档是 Lua1.1 的 doc 目录里的 manual.ps 文件。

原文版权归原作者所有,这篇翻译只是作为学习之用。如果翻译有不当之处,请参考原文。

-------------------以下是正文-------------------

编程语言 Lua 的参考手册

 

摘要:Lua 是嵌入式语言,被设计用来做为一个配置语言给其它程序使用。本文档描述 Lua 编程语言以及 Lua 程序和宿主 C 程序交互的 API。它展示了一些使用这些主要特点的例子。

 

--------------------------------------

1 简介

--------------------------------------

Lua 是一种嵌入式编程语言,支持过程式编程与数据描述功能。它经常做为别的程序的配置语言使用。Lua 是由 R. Ierusalimschy, L. H. de Figueiredo 和 W. Celes 设计, 由 W. Celes 实现。

 

Lua 被实现为由 C 语言写成的库。做为一个嵌入式语言,Lua 没有 "main" 函数的概念;它只能嵌入到宿主运行,叫做嵌入程序。宿主可以执行一段 Lua 代码,可以读写 Lua 变量,可以注册被 Lua 代码调用的 C 函数。通过注册 C 函数,Lua 可以扩展自己以应对不同的领域,从而创建可定制、共享语法框架的编程语言。

 

Lua 是自由分发的软件,正常提供没有什么保证。本文档里描述的这个实现可以从下面的匿名 ftp 得到:

 

www.lua.org/ftp/refman-1.1.ps.gz

 

--------------------------------------

2 环境和模块

--------------------------------------

Lua 中所有的语句都在一个全局环境中执行。这个全局环境持有所有的全局变量和函数,在嵌入语言一开始执行时进行初始化,并持续到结束。

 

这个全局环境可以用 Lua 代码或者嵌入程序来管理,可以通过 Lua 的实现库来读写全局变量。

 

全局变量不需要声明。所有的变量被认为是全局的除非明确声明为 local (详见 4.4.5 节,local 的声明)。在第一次赋值之前,全局变量的值为 nil。

 

Lua 的执行单元叫做模块(module) 。module 的语法为(注一):

 

 module --> { statement | function }

 

一个模块可以包含语句和/或函数定义,可以在一个文件中或者在一个宿主程序的字符串中。当执行一个模块,首先它所有的函数和语句被编译,函数被添加到全局环境,然后语句按顺序执行。模块对于全局环境的所有修改是持久的,这些修改在模块结束后依然可见。修改包括全局变量的修改和新函数的定义(注二)

 

注一:这里如常见的扩展的 BNF 范式一样,{ a } 表示 0 个或多个 a,[ a ] 表示一个可选的 a,{ a } +(加号是右上角标)表示一个或多个 a。

注二:实际上,一个函数的定义就是给一个全局变量赋值。(详见第 3 节)。

 

--------------------------------------

3 类型

--------------------------------------

Lua 是动态类型语言。变量没有类型;只有值有类型。所有值含有自己的类型。所有,Lua 语言中没有类型定义。

 

Lua 中有七种基本数据类型:nil, number, string, function, Cfunction, userdata, 和 table。Nil 是值为 nil 的类型,它的主要性质就是和其它值不同。Number 表示实数(浮点型),string 是字符串。

 

函数是第一类值(first-class values)。这意味着他们可以存储在变量中,做为参数传递给其他函数或者做为结果返回。当函数被定义,它的函数体被编译并保存在一个给定名称的全局变量。Lua 可以调用(和操作)写在 Lua 或 C 中的函数;后者的类型是 Cfunction。

 

userdata 类型允许 Lua 变量保存任意的 C 指针(void*)。它相当于 C 语言中的 void* 型指针,所以在 Lua 中除分配和相等测试操作以外,其它的操作是无效的。

 

table 类型实现为关联数组,即可以用数字和字符串索引的数组。因此,该类型不仅可用于表示普通数组,也可以用于表示符号表,集合,记录等。为表示一个记录,Lua 使用字段名为下标。语言通过提供 a.name 这种表示作为 a["name"] 的语法糖。

 

需要特点注意的是 table 是对象而非值。变量不能包含 table,只能引用它。赋值,参数传递,返回总是会涉及到 table 的引用,而不会对 table 进行拷贝。而且,table 必须在使用前显式创建。详见 4.5.7 节。

 

--------------------------------------

4 语言

--------------------------------------

这节介绍 Lua 的词法,语法和语义。

 

-------------------

4.1 词法约定

-------------------

Lua 是区别大小写的语言。标识符可以是任何字母,数字,下划线组成的字符串,且首字母不可为数字。下面这些是保留的关键字,不可用做标识符:

and     do     else     elseif     end

function     if     local     nil     not

or     repeat     return     until     then     while

 

下面的字符串留做它用:

~= <= >= < > = .. + - * / %

( ) { } [ ] @ ; , .

 

字符串常量可以由成对的单引号或双引号界定,并且可以包括 C 语言风格的转义序列 '\n', '\t' 和 '\r'。注释可在字符串外面的任何地方用两个连字符(--)开始,直到行尾。

 

数值常量可以由可选的小数部分,可选的指数部分写成。下面是一些有效的数值常量示例:

4 4. .4 4.57e-3 .3e12

 

-------------------

4.2 约定

-------------------

Lua 提供了一些自动转化。在字符串上的算术运算会试图把字符串转化为数值。更明确的说,字符串通过 C 函数 strtod 转化为数值。相反的,当一个数值参与字符串操作时,数值会被转化为字符串。按照以下规则:如果数值是一个整数,没有指数或小数点,则直接转化;否则,它和标准 C 函数 printf 用格式 "%g" 一样的格式转化。

 

-------------------

4.3 调整

-------------------

Lua 中的函数可以返回多个值。因为函数没有类型声明,编译器不知道函数会返回多少值。所以,有时候,值列表必须在运行时调整到给定长度:如果实际值多于所需,那么多余的值会被扔掉;如果需要的值多于实际的,根据需要在列表中进行 nil 扩展。调整也发生在其它地方,例如多重赋值。

 

-------------------

4.4 语句

-------------------

Lua 支持几乎所有常规的语句。常规的命令包括:赋值,控件结构和过程调用。非常规的命令包括 4.5.7 节中描述的表的构造函数,和局部变量的声明。

 

---------

4.4.1 块

---------

一个块(block)就是一个顺序执行的语句列表。任何语句都可以可选的后跟一个分号。

block --> { stat sc } [ret sc]

sc --> [ ';' ]

由于语义分析的原因, return 语句只能写作为一个块里的最后一句。这一个约束同时可以避免了“语句不可达”的错误。

 

---------

4.4.2 赋值

---------

Lua 支持多重赋值。所以,语法定义了赋值的左边可是一个变量列表,右边可以是一个表达式的列表。两个列表元素都以逗号分割。

stat --> varlist1 '=' explist1

varlist1 --> var { ',' var }

这个语句首先求出所有右边的值,再排列左边的变量,最后对其赋值。所以,可以这样交换两个变量的值,如下所示:

x, y = y, x

赋值前,值的列表被调整到和变量列表的长度相等(详见 4.3 节)。

一个名字可以指示一个全局变量或者局部变量。

var --> name

var --> var '[' exp1 ']' | var '.' |name

方括号用来索引 table。在这种情况下,var 经过求值必须是一个 table;否则,会有一个执行错误。语法 var.NAME 仅仅是 var['NAME'] 的语法糖。

 

---------

4.4.2 控制结构

---------

控制结构的条件表达式可以返回任何值。所有不是 nil 的值都被认为是真,nil 被认为是假。if, while 和 repeat 和别的语言中的意义一样。

stat --> while exp1 do block end

stat --> repeat block until exp1

stat --> if exp1 then block { elseif } [else block] end

elseif --> elseif exp1 then block

return 用于从函数中返回值。因为一个函数可以返回多个值,return 语句的语法是:

ret --> return explist

 

---------

4.4.2 表达式做为语句

---------

所有可能出现副作用的表达式都可以作为语句执行。这包括函数调用和列表的构造:

stat --> functioncall

stat --> tableconstructor

最后返回的值被丢弃。函数调用在 4.5.8 节解释,构造函数是 4.5.7 节的主题。

 

---------

4.4.2 局部声明

---------

局部变量可以在块中的任何位置声明。它的作用域从声明的地方开始,直到块结束。声明可以包含赋初始值。

stat --> local declist [init]

declist --> name { ',' name }

init --> '=' explist1

如果声明时含有赋初值操作,那么他和多重赋值有同样的语义。否则,所有的变量被初始化为 nil。

 

-------------------

4.5 表达式

-------------------

---------

4.5.1 简单表达式

---------

简单表达式是:

exp --> '(' exp ')'

exp --> nil

exp --> 'number'

exp --> 'literal'

exp --> var

数值(数值常量)和字符串常量在 4.1 节解释过了。变量在 4.4.2 节解释过了。

 

---------

4.5.2 算术运算符

---------

Lua 支持常见的算术运算符,意思也保持不变。这些操作符是二元操作符 +, -, *, / 和一元操作符 + 和 -。操作数必须是数值,或者可以根据 4.2 节中给出的规则转化为数值的字符串,

 

---------

4.5.3 关系运算符

---------

Lua 提供了以下的关系运算符:

< > <= >= ~= =

他们返回 nil 做为假,1 做为真。

 

相等首先比较两个操作数的类型。如果不同,结果为 nil。否则,比较它们的值。数值或字符串以常见的方式比较。表, Cfuntion 和函数按引用比较,也就是说,两个比较的表只有是同一个的时候才被认为是相等的。不等操作 ~= 和相等运算具有完全相反的结果。

 

其它的操作符只能应用于字符串或数值。如果一个参数是一个字符串,另一个也会被转化为字符串,并且它们的值以字典序进行比较。否则,两个都是数值的话,情况类似。

 

---------

4.5.4 逻辑运算符

---------

所有的逻辑运算符,如控制结构一样,认为 nil 为假而其它的都为真。像关系运算符一样,他们返回 nil 为假,1 为真。轮回运算符是:

and or not

and 和 or 是短路求值,也就是说,第二个操作数只在需要的时候才被求值。

 

---------

4.5.5 连接

---------

Lua 提供了一个字符串连接操作符“..",操作数必须是字符串或者数字,如果是数字的话,则按 4.2 节描述的规则进行转化。

 

---------

4.5.6 优先级

---------

操作符的优先级如下表所示,从低到高排列:

and or

< > <= >= ~= =

..

+ -

* /

not + (unary) - (unary)

二元操作符具体左结合性

 

---------

4.5.7 表的构造函数

---------

Table 的构造函数是创建表的构造函数。表的构造函数有不同的使用方法。最简单的一种是:

tableconstructor --> '@' '(' [exp1 ] ')'

这样的表达式会生成一个新的的空表。表的尺寸是可选的,并且可以给初始表的大小一个提示。Lua 中的表可以根据需要进行动态扩展无论初始大小是多大。

 

构造一个表并初始化一些字段可以用下面的语法:

tableconstructor --> '@' [name] fieldlist

这样的表达式会新建一个表,表的值是确定的,表中的一些字段根据 fieldlist 被初始化了。如果这里给出了 name,将会调用一个参数为这个表的 name 函数。该函数可以用来字段值,新建一些默认字段,或者用来做其它的有副作用的事。

fieldlist --> '{' [ffieldlist1 ] '}'

ffieldlist1 --> ffield { ',' ffield }

ffield --> name '=' exp

这些字段列表初始化表中具名的字段。如下面的例子:

a = @f { x = 1, y = 3 }

和下面的是等价的:

temp = @(2)

temp.x = 1

temp.y = 3

f(temp)

a = temp

可以使用下面的语法初始化列表

fieldlist --> '[' [lfieldlist1 ] ']'

lfieldlist1 --> exp { ',' exp }

例如:

a = @["v1", "vv"]

和下面的等价:

temp = @(2)

temp[1] = "v1"

temp[2] = "vv"

a = temp

在特定的情况下,下面的表达式是完全等价的:

@f{} @f[]

 

---------

4.5.8 函数调用

---------

函数调用语法如下:

functioncall --> var '(' [explist1 ] ')'

       explist1 --> { exp1 ',' } exp

这里,var 可是是什么变量(全局的,局部的,下标索引的等),只要它的类型为 function 或 Cfunction. 所有的表达式参数在函数调用之前被从左到右求值;然后参数被调整到和函数调用所用的参数个数一致(详见 4.3 节);之后被赋值对实际参数。

 

因为一个函数可以返回多个值(详见 4.4.3 节),返回值的个数在使用之前会进行调整。如果一个函数作为语句使用(详见 4.4.4 节),它的返回结果会被调整到 0 个(也就是全部丢弃)。如果一个函数在需要一个值(语法中被表示为非终结的 exp1)的地方调用,它的返回结果会被调整到 1 个。如果一个函数在需要多个值的地方调用(语法上表示为非终结的 exp),不对返回结果进行调整。

 

-------------------

4.6 函数定义

-------------------

函数可以在模块中的任何全局层面定义;函数不可以定义在另一个函数中。函数定义的语法是:

function --> function name '(' [parlist1 ] ')' block end

 

当 Lua 发现一个函数定义,它把函数体编译为字节码保存在全局变量 name 中,类型为 function。

 

参数和局部变量的表现一样,由参数值进行初始化。

parlist1 --> 'name' { ',' name }

 

结果由 return 语句返回(见 4.4.3)节。如果执行到函数最后也没有 return 指令的话,函数不返回值。

 

(未完待续)

你可能感兴趣的:(Lua1.1 Lua 的参考手册 (一))