Lua语法分析(3)- 二元操作符
来源:互联网 发布:微信模板消息 java 编辑:程序博客网 时间:2024/05/18 18:15
欢迎关注公众号《Lua探索之旅》。
表达式和语句
表达式(expression)和语句(statement)是两个不同的概念,表达式可以返回一个值,语句是一条执行命令,没有返回值,每类编程语言的处理方法不尽相同。
比如 "a=1" ,在C语言里既可以作为语句,也可以作为表达式,因此可以连续赋值。如"b=a=1;",先执行 "a=1",返回值为 a,再执行 "b=a"。
但在Lua里 "a=1" 属于赋值语句,不是表达式,所以 "b=a=1" 会语法解析错误。
在Lua里唯一既可以作为表达式,也可以作为语句的是函数调用(function call)。作为表达式时,有函数返回值;作为语句时,忽略函数返回值。
二元操作符
作为表达式的纽带,二元操作符将各个子表达式连接起来,构成复杂表达式。
Lua有如下几类二元操作符:
数学操作符:包括'+'、 '-'、 '*'、 '/'、 '%'。
比较操作符:包括'=='、 '~='、 '>'、 '<'、 '>='、 '<='。
逻辑操作符:包括 and、or。
其他运算符:如幂运算 '^'、字符串连接 '..'。
操作符有优先级的概念,'*' 的优先级等于 '/',大于 '+'、'-',高优先级的操作符优先计算。
比如 "1+2*3/3-2",有如下计算步骤:
2 * 3 = 6
6 / 3 = 2
1 + 2 = 3
3 - 2 = 1
人脑可以通过分析整个表达式,找出优先级最高的操作符,一步步演算得到结果。对程序而言,它只能从头开始扫描整个表达式,并不能预知后面的操作符,该如何解析表达式?
优先级递归解析
在《递归下降算法》小节里介绍过利用EBNF范式解析表达式的方法,这次介绍一种根据优先级递归解析的方法,下面分步骤介绍。
(1)操作符和优先级
为简单起见,设定只有数字、加、减、乘、除这5类Token,枚举如下:
enum TOKEN { NUMBER, ADD, SUB,
MUL, DIV, };
struct token{
TOKEN type;
int value;
};
优先级
int priority(token& tk) {
switch (tk.type) {
case ADD: return 6;
case SUB: return 6;
case MUL: return 7;
case DIV: return 7;
default: break;
}
return 0;
}
加、减的优先级为6,乘、除的优先级为7,值越大表示优先级越高。
(2)递归函数
struct expdesc {
int value;
token op;
};
expdesc nextNoHigherExp(int limit);
nextNoHigherExp函数,简称nextExp,每次返回下一个优先级不高于limit的子表达式,参数limit为当前优先级,其逻辑如下:
每次先取出一个数value 和后面的二元操作符 op。
若 op优先级 > limit,递归调用nextExp,传入op的优先级作为新的limit,并根据nextExp的返回值进行计算。
若 op优先级 <= limit,结束递归,返回 value和op。
以 "1+2*3/3-2" 为例,初始limit为0。
(1)优先级从0升到6(加号),再升到7(乘号),遇到"3/"返回:
nextExp(limit=0) -> "1+"
nextExp(limit=6) -> "2*"
nextExp(limit=7) -> "3/" <-返回
"2*" 和 "3/" 计算得到 "6/":
nextExp(limit=0) -> "1+"
nextExp(limit=6) -> "6/"
(2)"6/"的优先级大于6,再次升到7,遇到"3-"返回
nextExp(0) -> "1+"
nextExp(6) -> "6/"
nextExp(7) -> "3-" <-返回
"6/" 和 "3-" 计算得到 "2-":
nextExp(0) -> "1+" ->
nextExp(6) -> "2-"
(3)"2-"的优先级等于6,nextExp(6)返回
"1+" 和 "2-" 计算得到 "3-"
nextExp(0) -> "3-"
(4)"3-"的优先级大于0,优先级升到6,遇到"2"返回
nextExp(0) -> "3-"
nextExp(6) -> "2" <-返回
计算得到 "1"
nextExp(0) -> "1"
程序实现
(1)计算函数
int calc(token op, int v1, int v2) {
int v = 0;
switch (op.type) {
case ADD: v = v1 + v2; break;
case SUB: v = v1 - v2; break;
case MUL: v = v1 * v2; break;
case DIV: v = v1 / v2; break;
default: return 0;
}
return v;
}
(2)递归函数
expdesc nextExp(int limit) {
token tk = next_token();
/*取出下一个数和后面的操作符*/
expdesc exp;
exp.value = tk.value;
exp.op = next_token();
/*更高优先级的操作符递归调用*/
if (priority(exp.op) > limit) {
do {
expdesc exp2 =
nextExp(priority(exp.op));
exp.value = calc(exp.op,
exp.value, exp2.value);
exp.op = exp2.op;
}
while (priority(exp.op) > limit);
}
return exp;
}
nextExp返回下一个优先级不高于limit的 exp2,并和当前exp进行calc计算,并将exp2的op赋给exp。
比如 exp为 "2*",exp2为 "3/",先用exp的op计算,exp更新为 "6/"。
Lua实现
上述例子即为Lua源码中 subexpr函数的简易实现,在Lua里运算符的优先级如下:
其中 .. 和 ^ 区分左右优先级,用于实现右结合,比如 "2^1^2",右结合等于2,左结合等于4。其余运算符都是左结合。
本节重点介绍了Lua二元操作符的实现逻辑,作为理解Lua表达式的基础铺垫,敬请后续!
- Lua语法分析(3)- 二元操作符
- Lua语法分析(4)- 表达式
- Lua虚拟机之语法分析(二)
- Lua语法分析(2)- 控制语句
- 二元操作符重载
- 二元操作符重载
- 二元操作符重载
- lua词法语法分析
- lua语法分析原理介绍
- C++之二元操作符重载
- 二元操作符的返回值
- 二元判断操作符 ? 的写法
- 第三章 一元和二元操作符
- Java二元操作符instance的用法
- 二元操作符&& 与一元操作符++的求解秩序
- [lua源码学习笔记]词法语法分析
- Lua 长度操作符
- Lua逻辑操作符
- HLS协议学习总结
- opencv安装与python cv2安装
- MapReduce编程模型及实现WordCount
- MySQL 修改/忘记用户密码
- 51nod 1253 Kundu and Tree
- Lua语法分析(3)- 二元操作符
- 双向循环链表
- github上有关java的高质量项目(收集)
- 习题5.6
- 《剑指offer》Python语言 面试题3:二维数组中的查找
- jquery选中复选框没效果
- 反射
- win10+python3.6+anaconda5.0.1 xgboost安装
- Android --- 多媒体应用(MediaRecorder 录音)