Nand2Tetris|Assembler
汇编语句翻译
是连接硬件和软件的关键,也是课程第二部分开发的翻译器中最低级最接近硬件的一层
由于前面我们已经介绍了Hack指令集中A和C指令的二进制形式了(例如第一位0是A指令,1是C指令,C还额外分成comp,dest和jmp等)
因此现在想要实现Assembler本质上就是将对应的Hack指令翻译转换成二进制指令
先从最简单的A指令开始说起
我们前面的学习中介绍了A指令可以有两种operands,直接数,或者是符号。那时我们也提到了符号表实际上就是汇编器去实现的,汇编语言开发者并不关心。
- 直接数:将其值转化为16-bit binary,首位为0
- 符号:后面再说
C指令
首先前三位一定是111
之后七位是comp计算逻辑
三位dest目的地
三位跳转逻辑jmp
其实真值表都有了,所有的排列组合枚举都出来了,直接拆分成comp、dest和jmp三个部分查表最终组装在一起即可得出最终的C指令二进制形式
(定义一个指令转换器接口,转换指定一行的Hack汇编语句)
解析完整程序
对于整段完整的汇编程序,我们需要关注三个部分:
- 空白换行,什么时候换,注释怎么忽略,缩进怎么处理
- 指令转换
- 符号处理
空白换行
针对空白换行的需求:扫描文本并替换指定部分(注释)为空内容即可
指令转换
针对指令转换,从上至下,每一行内容进行转换,具体转换逻辑上面已经提到了
符号处理
针对符号处理,有点复杂,主要包括三种符号:
- Hack计算机自带的预定义符号,例如KBD,SCREEN
- 标签符号,程序过程中出现的用户编写的标签,例如LOOP,END等
- 变量符号,汇编程序定义的变量,例如i,j,k等
预定义符号
这个最简单,本质上就是一个kv map,扫描到内容后直接获取Hack计算机规定的指定value即可,例如R0就一定是0
(放在内存的kv map,实际上也不用维护,直接static,表示Hack计算机所支持的所有预定义符号集)
标签符号
扫描程序,标签所在行号就是最终的结果
变量符号
只要不是预定义符号或者是标签符号,就都是自定义符号
Hack语言规定,自定义符号绑定的实际地址从16开始
总结
至此我们可以归纳总结,所谓汇编器的符号表,本质上只是一个在初始化时根据硬件特性预先维护一些数据的map,之后在运行过程中扫描文本,更新这个map
符号表的生命周期:
- 程序启动时预先放入硬件系统规定的预定义符号
- 第一遍扫描代码,重点关注汇编代码中的标签,统计行数并维护标签的符号表信息
- 第二遍扫描代码,逐行翻译,并对变量符号进行更新维护
Nand2Tetris|Assembler
http://example.com/2025/01/22/Nand2Tetris-Assembler/