练习
本节阅读量:这一页适合读完第二章后回头做,不必一次全部完成。练习 1~4 主要检查作用域和环境;练习 5~8 对照 IR 与栈槽;最后一题需要修改代码。
练习 1:手画 AST
画出下面程序的 AST:
|
|
参考形状:
|
|
再指出:新建立的 x 对 value 和 body 中的哪一部分可见?
练习 2:追踪 shadowing 环境
不用写代码,只写出环境变化:
|
|
参考形式:
|
|
练习 3:分清 value 和 body 的环境
先不要运行,判断下面程序中每个 x 对应哪一层绑定:
|
|
分别写出:
|
|
然后运行下面两个命令,检查你的推导:
|
|
重点观察:内层绑定要等 value 处理完成后,才会加入解释器环境或 lowerer 环境。
练习 4:判断结果
判断下面程序的结果:
|
|
再判断:
|
|
说明第二个程序为什么没有修改外层的 x。
练习 5:手写 IR
给下面程序写出 IR:
|
|
参考形式:
|
|
注意 value 里的加法会先生成临时结果,变量引用本身不会生成新的操作。
练习 6:区分语法错误和未绑定变量
下面程序语法合法,但变量没有绑定:
|
|
分别运行:
|
|
解释为什么 ast 能成功,而解释器和编译器会在各自的环境查找阶段报错。
练习 7:从 shadowing 画出栈帧
编译:
|
|
先找出:
|
|
再回答:
|
|
最后画出包含 %rbp、%rsp、x0、x1 和 t.0 的栈帧。
练习 8:变量引用会生成 IR 吗
分别查看下面两个程序的 IR:
|
|
|
|
数一数每个程序生成了多少条 copy 和多少条 add,再回答:
|
|
结合 lowerer 的 ExprKind::variable 分支解释答案。
练习 9(代码):让同名变量连续编号
当前 lowerer 使用一个全局的 next_local_ 为所有 let 绑定编号。对于依次绑定 x、y、x 的程序:
|
|
生成的内部名字是:
|
|
修改内部名字的生成方式,让每个源码名字分别计数,得到:
|
|
修改后重新构建并运行:
|
|
确认 IR 中同名变量的编号连续,同时程序结果仍然是 5。这个改动只影响 IR 名字是否容易阅读,不应该改变变量查找、shadowing 或栈槽分配的行为。
本节目录