语义分析总装
复习
- 符号表:记录名字及其属性,是语义分析的基础
- 名字解析:沿作用域从内到外确定名字指向哪个定义
- 类型检查:沿语法树自底向上确认每个运算的类型是否匹配
TL;DR
- 语义分析把名字、作用域、类型、控制规则合成一次完整检查
- 它建立在符号表和抽象语法树之上
- 通过之后,程序才算“讲得通”
- 之后就可以进入中间表示与优化
正文
这一章是语义分析的收尾。我们把前面几章的零件串起来,看看语义分析这一步在编译器里到底做了什么。
它到底在检查什么
语义分析要回答的核心问题只有一个:这棵语法树,在语义上成立吗? 具体拆开,它做了这几类事:
- 建符号表、做名字解析:弄清每个名字指向哪个定义
- 管理作用域:处理名字的可见性与遮蔽
- 做类型检查:确认每个运算、赋值、调用的类型都匹配
- 检查控制规则:条件类型、跳转位置、返回路径是否合法
- 必要时处理类型转换和类型推断
这些检查互相依赖,通常在遍历抽象语法树的过程中一并完成:一边进作用域、往符号表里登记名字,一边对每个节点做类型和规则检查。
它的产出是什么
语义分析之后,编译器得到的,通常是一棵带类型标注的语法树(有时叫“装饰过的”AST):每个表达式节点上,都附上了它的类型;每个名字,都指向了它的定义。
这棵树,就是后面阶段宝贵的输入:
- 中间表示可以从它翻译而来
- 优化可以借助类型信息做出更聪明的决定
- 代码生成能据此选择正确的指令
可以说,语义分析把“漂亮的语法结构”,升级成了“信息完备、可以往下走的结构”。
走到这里的意义
回头看看这条线:字符 → 词法单元 → 语法树 → 抽象语法树 → 带类型的 AST。每一步都在剥离表层、补充信息,让程序越来越“接近机器能处理的样子”。
这也正是编译器前端的完整旅程:读进来的是字符,交出去的是含义清晰、类型明确的结构。 至此,“读懂程序”这件事已经完成。
下一组,我们要从“读懂”转向“翻译”:把这棵带类型的树,变成与具体机器无关的中间表示。
思考题 1
语义分析大致要完成哪几件事?
思考题 2
语义分析的产出通常是什么?它为后续阶段提供了什么?
小结
知识点
- 语义分析综合检查名字、作用域、类型与控制规则
- 它在遍历 AST 时同步完成
- 产出通常为带类型标注的语法树
- 后续的中间表示、优化与代码生成都依赖它
参考资料
- Wikipedia(zh):语义分析:编译器前端中检查语义的阶段
- Wikipedia(zh):编译器:编译流程的整体阶段划分
思考题答案(仅供参考)
思考题 1
大致包括:建立符号表并进行名字解析,管理作用域与遮蔽,进行类型检查与控制流检查,必要时处理类型转换和类型推断。这些检查通常在遍历抽象语法树时一并完成。
思考题 2
产出通常是一棵带类型标注的语法树,其中每个表达式都带有类型、每个名字都指向其定义。它为中间表示、优化和代码生成提供了信息完备的输入。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪