Lua语法分析(4)- 表达式
2017-11-05 16:22
381 查看
欢迎关注公众号《Lua探索之旅》。
上一节介绍了二元操作符,本节以Lua EBNF为基础,介绍Lua表达式的各种表现形式。
Lua支持逗号分隔的表达式列表 explist,在多重返回值、多重赋值、参数列表等场景使用,示例如下:
从 explist 开始介绍表达式。
explist1
根据上面示例很好理解,逗号分隔的每一项为一个expr。
expr
上一节介绍了运算符优先级,也就是 subexpr 的实现。初始优先级 limit=0,逐个读取运算符,根据优先级递归解析,可参考《二元操作符》一节。
subexpr
一个表达式由运算符和子表达式组成,运算符分为一元运算符(unary operator)和二元运算符(binary
operator)。
simpleexp 表示子表达式。
unop subexpr 表示一元运算符和子表达式。
binop subexpr 表示二元运算符和子表达式。
以 "-9+10*5/(a+10) == #t1" 为例,推导如下:
Lua里一元操作符有:
'#' 取字符串长度,或table数组元素数量。
'-' 负号。
'not' 取反,相当于c语言的'!'取反。
simpleexp
前面6个产生式比较简单,分别对应nil、false、true、数字、常量字符串、可变参数...。
FUNCTION body 表示函数定义。
constructor 表示table初始化。
primaryexp 表示主表达式。
FUNCTION body
范例:
FUNCTION和END 为两个终结符。
chunk 表示函数体。
parlist 表示参数列表。
在Lua里函数是第一类型,和普通变量有相同的用法,可以作为参数、值传递,这一点类似python。
constructor
范例:
table是Lua里唯一的数据结构,可以理解为array和hash的组合。
{1,2,3} 存在数组部分。
{x=1} 存在哈希部分。
元素之间可以用 ',' 或 ';' 分隔。
{x=1} 等价于 {["x"]=1}。
语法分析总结
通过对Lua语法分析的一系列介绍,虽然没有接触实际源码,相信对Lua语法分析也有了一定的了解。这一块应该属于Lua源码相当难啃的一部分内容,通过先理论后实践的方法,避免陷入源码实现的黑洞,从而提升信心。
Lua的词法分析、语法分析、指令生成模块耦合在一起,并且Lua是基于寄存器的虚拟机。在生成指令的时候,已经指定每个指令所操作的寄存器位置,所有这些逻辑都要在lua脚本的一次遍历分析完成。
关于语法分析的介绍到此为止,后续将介绍指令生成部分,敬请期待!
上一节介绍了二元操作符,本节以Lua EBNF为基础,介绍Lua表达式的各种表现形式。
Lua支持逗号分隔的表达式列表 explist,在多重返回值、多重赋值、参数列表等场景使用,示例如下:
return a,b,c a,b,c=1,2,3 local a,b,c=1,2,3 f = function (a,b,c) end print(1,2,3)
从 explist 开始介绍表达式。
explist1
explist1 -> expr {`,` expr}
根据上面示例很好理解,逗号分隔的每一项为一个expr。
expr
expr -> subexpr(limit=0)
上一节介绍了运算符优先级,也就是 subexpr 的实现。初始优先级 limit=0,逐个读取运算符,根据优先级递归解析,可参考《二元操作符》一节。
subexpr
subexpr -> (simpleexp | unop subexpr) { binop subexpr }
一个表达式由运算符和子表达式组成,运算符分为一元运算符(unary operator)和二元运算符(binary
operator)。
simpleexp 表示子表达式。
unop subexpr 表示一元运算符和子表达式。
binop subexpr 表示二元运算符和子表达式。
以 "-9+10*5/(a+10) == #t1" 为例,推导如下:
"-9" -> unop subexpr "+10" -> binop subexpr "*5" -> binop subexpr "/(a+10)" -> binop subexpr "(a+10)" -> simpleexp "== #t1" -> binop subexpr "#t1" -> unop subexpr
Lua里一元操作符有:
'#' 取字符串长度,或table数组元素数量。
'-' 负号。
'not' 取反,相当于c语言的'!'取反。
simpleexp
simpleexp -> NIL | false | true | NUMBER | STRING | ... | FUNCTION body | primaryexp | constructor
前面6个产生式比较简单,分别对应nil、false、true、数字、常量字符串、可变参数...。
FUNCTION body 表示函数定义。
constructor 表示table初始化。
primaryexp 表示主表达式。
FUNCTION body
body -> `(`parlist`)` chunk END parlist -> [param {`,' param}] param -> NAME | `...'
范例:
f = function (a,b,c) return a+b+c end
FUNCTION和END 为两个终结符。
chunk 表示函数体。
parlist 表示参数列表。
在Lua里函数是第一类型,和普通变量有相同的用法,可以作为参数、值传递,这一点类似python。
constructor
constructor -> `{`[fieldlist]`}` fieldlist -> field { fieldsep field } [ fieldsep ] field -> `[` expr `]` `=` expr | name `=` expr | expr fieldsep -> `,` | `;`
范例:
a = {} a = {1,2,3} a = {x=1,["y2"]=2} a = {1,2;x=1,[y1]=2;["y2"]=2,3;}
table是Lua里唯一的数据结构,可以理解为array和hash的组合。
{1,2,3} 存在数组部分。
{x=1} 存在哈希部分。
元素之间可以用 ',' 或 ';' 分隔。
{x=1} 等价于 {["x"]=1}。
语法分析总结
通过对Lua语法分析的一系列介绍,虽然没有接触实际源码,相信对Lua语法分析也有了一定的了解。这一块应该属于Lua源码相当难啃的一部分内容,通过先理论后实践的方法,避免陷入源码实现的黑洞,从而提升信心。
Lua的词法分析、语法分析、指令生成模块耦合在一起,并且Lua是基于寄存器的虚拟机。在生成指令的时候,已经指定每个指令所操作的寄存器位置,所有这些逻辑都要在lua脚本的一次遍历分析完成。
关于语法分析的介绍到此为止,后续将介绍指令生成部分,敬请期待!
相关文章推荐
- 一个简单的自顶向下语法分析(表达式求值)
- 算术表达式语法分析
- 表达式语法分析——递归子程序法
- 语法分析:算术表达式递归下降分析程序设计
- 重磅来袭 - Lua语法分析(1)
- Lua基础(二):表达式及基本语法
- Atitit 表达式原理 语法分析 原理与实践 解析java的dsl 递归下降是现阶段主流的语法分析方法
- 表达式语法分析——递归子程序法
- Atitit 表达式原理 语法分析 原理与实践 解析java的dsl 递归下降是现阶段主流的语法分析方法
- SDUT 表达式语法分析——预测分析法
- Lua语法分析(2)- 控制语句
- 2147 表达式语法分析——递归子程序法
- 四则运算表达式的语法分析
- Lua5.3 虚拟机指令分析(三)表达式运算
- 语法分析:算术表达式预测分析程序设计
- 语法分析:算术表达式递归下降分析程序设计
- 编译原理之基于扫描器的表达式语法分析+逆波兰表达式生成
- C编译器剖析_3.1 语法分析_C语言的表达式(2)
- 实现自定义类似XML语法分析的正则表达式(原创)
- Lua语法分析(3)- 二元操作符