语义分析是编译系统的第三部分,负责赋值检查,表达式检查以及代码生成.
基本思想
代码沿用了上一部分的文法表, 利用递归下降算法对每一个非终结符写一个函数. 但是文法多达70多条, 工作量太大, 就只实现了赋值语句, 表达式, 条件语句这几个代表性的文法规则. 其他实现起来也类似, 多写几个函数即可.
函数介绍
需要注意的几个细节:
- compare_var_type用于比较类型, 比较失败则raise一个CompileError
- 在生成代码过程中, 有的传入了其他的变量, 是为了回填
- 把if回填做成了label的方式, 可以在后阶段再处理
- 未初始化的变量调用也留给了后阶段处理.
函数表:
成员函数 | 对应非终结符 | 备注 |
---|---|---|
init() | 初始化 | |
get_register() | 分配寄存器 | |
get_label_no() | 分配记号 | |
compare_var_type(var_type_1,var_type_2) | 比较类型,raise错误 | |
build_table(x) | 建立符号表 | |
check_factor(factor) | <因式> | 用于检查 |
check_factors(factor) | <因式递归> | 用于检查 |
check_factor_c(fc) | <因子> | 用于检查 |
check_term(term) | <项> | 用于检查 |
check_exp(x) | <表达式> | 用于检查 |
check_stm(x) | <赋值函数> | 用于检查 |
generate_factor(factor) | <因式> | 用于生成 |
generate_factors(factors,factor) | <因式递归> | 用于生成 |
generate_factor_c(fc) | <因子> | 用于生成 |
generate_term(term,factor) | <项> | 用于生成 |
generate_exp(x) | <表达式> | 用于生成 |
generate_stm(x) | <赋值函数> | 用于生成 |
generate_func_blocks(x) | <函数块闭包> | 用于生成 |
generate_func_block(x) | <函数块> | 用于生成 |
generate_else_block(x) | <否则语句> | 用于生成 |
generate_logical(x) | <逻辑表达式> | 用于生成 |
generate_if(x) | <条件语句> | 用于生成 |
generate_code(tree) | <函数定义> | 用于生成 |
dfs(tree,func) | 搜索函数 | |
run(code) | 获取生成结果 |
文法表
1 | <函数定义>-><修饰词闭包><类型><变量>[(]<参数声明>[)][{]<函数块>[}] |
代码实现
知道了思路还是很好读的, 无非是看每个非终结符对应了哪条规则, 再利用分支调用对应的分支.
1 | import json |