词法分析与递归表达式求值
1. 词法分析基础
1.1 词法分析概念
- 定义:识别表达式中的基本单元(token)
- token:有独立含义的子串,如数字、运算符、括号等
1.2 复杂表达式示例
"0x80100000+ ($a0 +5)*4 - *( $t1 + 8) + number"
包含:十六进制整数、小括号、寄存器访问、指针解引用、变量访问等
1.3 正则表达式应用
- 利用正则表达式识别各类token
- 规则:(正则表达式, token类型)组成的二元组
- 常见token类型:
- 十进制整数
- 运算符:+, -, *, /
- 括号:(, )
- 空格串:一个或多个空格(类型为TK_NOTYPE,识别后丢弃)
1.4 Token结构体
typedef struct token {
int type; // token类型
char str[32]; // token字符串表示
} Token;
- 大部分token仅需记录类型(如运算符)
- 对于数字等token,需记录其字符串表示用于后续求值
- 注意str长度限制,防止缓冲区溢出
2. 递归求值机制
2.1 算术表达式BNF定义
<expr> ::= <number> // 一个数是表达式
| "(" <expr> ")" // 在表达式两边加个括号也是表达式
| <expr> "+" <expr> // 两个表达式相加也是表达式
| <expr> "-" <expr> // 两个表达式相减也是表达式
| <expr> "*" <expr> // 两个表达式相乘也是表达式
| <expr> "/" <expr> // 两个表达式相除也是表达式
2.2 求值函数框架
eval(p, q) { // p和q指示子表达式的开始和结束位置
if (p > q) {
/* 错误表达式 */
}
else if (p == q) {
/* 单个token(数字),返回其值 */
}
else if (check_parentheses(p, q) == true) {
/* 整个表达式被匹配的括号包围,移除括号 */
return eval(p + 1, q - 1);
}
else {
/* 处理复合表达式 */
op = 找到主运算符位置;
val1 = eval(p, op - 1);
val2 = eval(op + 1, q);
switch (op_type) {
case '+': return val1 + val2;
case '-': return val1 - val2;
case '*': return val1 * val2;
case '/': return val1 / val2;
default: assert(0);
}
}
}
2.3 括号匹配检查
check_parentheses(p, q)
函数用于:
- 判断表达式是否被一对匹配的括号包围
- 检查表达式的左右括号是否匹配
示例:
"(2 - 1)"
- 返回true"(4 + 3 * (2 - 1))"
- 返回true"4 + 3 * (2 - 1)"
- 返回false(不被括号包围)"(4 + 3)) * ((2 - 1)"
- 返回false(括号不匹配)"(4 + 3) * (2 - 1)"
- 返回false(最左和最右括号不匹配)
2.4 主运算符识别
主运算符:表达式最后一步进行运算的运算符
主运算符识别规则:
- 非运算符token不是主运算符
- 出现在一对括号中的token不是主运算符
- 主运算符优先级在表达式中最低(最后计算)
- 当多个运算符优先级相同时,根据结合性,最后被结合的是主运算符
示例:"4 + 3 * (2 - 1)"
中的主运算符是+
2.5 错误处理
- 在求值过程中检查表达式合法性
- 对非法表达式返回错误标识或终止程序
- 合法表达式的结果以uint32_t类型返回