迷惘的码农。
分类:
2008-08-15 11:07:10
本节描述Lua的词法、语法和语义。换句话说,本节描述了哪些记号(token)是有效的,它们可以怎样组合,以及组合的含义。
语言的构成概念将用常见的扩展的BNF记法(notation)进行说明,其中{a} 表示 0或多个a,[a] 表示一个可选的a。非最终符号(non-terminal)原样显示,关键字显示似kword,其他最终符号(terminal symbols)显示似`=´。Lua的完整语法放在本手册的最后。
Lua中的名称(也称为标识符(identifier))是非数字开头的字母、数字和下划线构成的任何字符串。这与多数语言的名称定义相符。(字母的定义依赖于当前环境,其中的字母表中的任何字符都可用于标识符。)标识符用于命名变量和表的字段。
下面的关键字是保留的,不能用作名字:
and break do else elseif
end false for function if
in local nil not or
repeat return then true until while
Lua是大小写敏感的语言:and
是保留字,但And
和AND
是不同的合法名字。通常约定,以下划线开头后跟大写字母(如_VERSION
)的名字被Lua留作内部全局变量。
下面的字符串表示其他的记号:
+ - * / % ^ #
== ~= <= >= < > =
( ) { } [ ]
; : , . .. ...
字面(literal)字符串可用单引号或双引号定界,而且可包含下面C风格的转义序列:
'此外,反斜线后跟真正的换行符会实际在字符串中插入一个换行符。在字符串中,也可利用转义序列\a
' (响铃)
'\b
' (退格)
'\f
' (换页)
'\n
' (换行)
'\r
' (回车)
'\t
' (横向制表符)
'\v
' (纵向制表符)
'\\
' (反斜线)
'\"
' (双引号)
'\'
' (单引号)
\ddd
通过字符的数字值指定它,此处的ddd是最多3位的十进制数字序列。(注意,如果数字转义后面必须紧接着一个数字,必须严格地使用3个数字表示。)Lua中的字符串可以包含任意8位值,包括由‘\0
’指定的内嵌的0。
要把双(单)引号、换行、反斜线、回车或内嵌的0放在双(单)引号封闭的字面字符串中,你必须使用转义序列。任何其他字符可直接插入字面值。(一些控制字符可能导致文件系统出问题,但它们对Lua没有影响。)
字面字符串也能通过一种用长括号括起来长格式进行定义。我们把在2个开方括号中间插入n个等号的符号定义为n级开长括号。所以,0级开长括号记为[[
,1级开长括号记为[=[
,依次类推。闭长括号的定义类似;例如,4级闭长括号记为]====]
。一个以任意级别开长括号开头的长字符串结束于第一个同级闭长括号。这种形式中的字面值可以跨越多行,不解释任何转义序列,并且忽略任何其他级别的长括号。除了合适级别的闭括号,无所不包。
出于方便性的考虑,当开长括号后面直接跟着一个换行时,该换行被忽略。举个例子,在使用ASCII的系统(其中‘a
’被编码为97,换行是10,‘1
’是49)中,下面的5个字面值表示相同的字符串:
a = 'alo\n123"'
a = "alo\n123\""
a = '\97lo\10\04923"'
a = [[alo
123"]]
a = [==[
alo
123"]==]
数字常量可被写成带有可选的小树不分和可选的十进制指数部分。Lua也接受十六进制整数常量,只需前缀0x
。合法的数字常量的例子是
3 3.0 3.1416 314.16e-2 0.31416E1 0xff 0x56
注释可在字符串外的任何地方以两个连字符(--
)开始。
如果--
直接后跟的文本不是开长括号,它就是短注释,到行尾结束。否则就是长注释,它直到相应的闭长括号结束。长注释常用于临时屏蔽代码。
Lua种动态类型语言。这表明变量没有类型;只有值才有。语言中不存在类型定义。所有值自带类型信息。
Lua中的所有值都是一等(first-class)的值。这表示所有值都能存于变量中,作为参数传入函数,以及作为结果返回。
Lua中有8中基本类型:nil,boolean,number,string,function,userdata,thread和table。
Nil是值nil的类型,该值得主要性质是与其他的所有值都不同;常用于表示一个无意义的值。Boolean是值false和true的类型。nil和false都使条件为假;任何其他值得到真。Number表现实数(双精度浮点数)。(很容易使用数值的其他内部表示形式,如单精度浮点数或长整型,构建Lua解释器,参考文件luaconf.h
。)String表示字符数组。Lua使用完全的8位:字符串可含有任何8位字符,包括内嵌的0(‘\0
’)(见)。
Lua能调用(以及操作)用Lua和C写的函数(见)。
类型userdata允许在Lua变量中存储任意的C数据。该类型对应一块原始内存,除了赋值和一致性判断,没有预定义的Lua操作。然而,通过使用metatables,程序员可以为用户数据值定义各种操作(见)。 在Lua中不能创建或修改用户数据,只能通过C API。这样确保宿主程序持有的数据的完整性。
类型thread表示独立的执行线程,并且被用于实现协同例程(coroutine,见)。不要把Lua线程同操作系统的线程搞混了。所有系统上的Lua都支持协程,甚至是不支持线程的系统。
类型table实现了关联数组,不只是数字,任何值都可以做索引(除了nil)。表可为异质的;即可以包含所有类型(除了nil)的值。表是Lua中唯一一种提供数据结构的机制;它们可用来表现普通的数组、符号表、集合、记录、图、树,等等。Lua用字段名作为索引可表现记录。在语言层面通过提供a.name
作为a["name"]
的语法糖来支持这种表现形式(记录)。有多种便利的方式在Lua中创建表(见)。
跟索引一样,表字段的值可为任意类型(除了nil)。特别是,由于函数是一等值,表字段可含有函数。由此表也可支持方法(见)。
表、函数、线程和(完整的)用户数据的值是对象:变量并不实际持有这些值,只是引用这些值。赋值、传参和函数返回总是操作对这些值的引用;这些操作不包含任何性质的拷贝。
库函数返回描述给定值的类型的字符串。
Lua提供运行时字符串和数字值间的自动转换。将数学运算符用于字符串会尝试依照通常的转换规则将该字符串转为数字。反过来,当把数字用在期望字符串的地方时,数字以合理的格式被转为字符串。要完全控制数字到字符串的转换,使用字符串库德format
函数(见)。
变量是存储值的地方。Lua中有3种变量:全局变量、局部变量和表字段。
单个名字可表示全局变量或局部变量(或函数的形式参数,它是一种特殊的局部变量):
var ::= Name
Name表示中定义的标识符。
如果未明确地声明为局部的(见),任何变量都假定为全局的。局部变量具有词法作用域(lexically scoped):局部变量可被定义于它们所在作用域内的函数自由访问(见)。
在首次赋值以前,变量的职为nil。
方括号被用于索引一个标:
var ::= prefixexp `[´ exp `]´
对全局变量和表字段的访问的含义可通过元表(metatable)进行改变。对索引的变量t[i]
的访问等价于调用gettable_event(t,i)
。(函数gettable_event
的完整描述见。在Lua中该函数并不存在或不可访问。我们这儿用它只作说明的目的。)
语法var.Name
仅仅是var["Name"]
的语法糖:
var ::= prefixexp `.´ Name
所有全局变量都作为字段存在于一个普通的Lua表中,称为环境表或简称环境(见)。每个函数都有个引用指向某个环境,所以此函数内的所有全局变量都将引用该环境表。创建一个函数时,它从创建它的函数继承了环境。调用可得到Lua函数的环境表。调用可替换它。(你只能通过调试库来操作C函数的环境;见)
访问全局变量x
等价于_env.x
,后者又等价于
gettable_event(_env, "x")
这里的_env
是当前运行的函数的环境。(函数gettable_event
的完整描述见。在Lua中该函数并不存在或不可访问。同样地,变量_env
也未在Lua中定义。我们这儿用它们只作说明的目的。)