今天折腾一上午,终于 完成了 Coursera 上 这个课程的最后一个汇编器项目。这套课程真是没白跟,收获良多,现在已经等不及想看下一期的软件部分了,哈哈。
下面是我的 python 实现,存个档,同时给同样在看这课程的同学们参考。
注释风格看起来可能有点奇怪,拍脑袋想的,没多少 python 编码经验,还望包涵,稍微解释一下:
#-----------------## 大块代码用途描述 ##-----------------### 分级注释### 分级注释#### 分级注释
import sysimport os.path#--------## tables ##--------### symbol tableSYMB_TABLE = { "SP": 0, "LCL": 1, "ARG": 2, "THIS": 3, "THAT": 4, "R0": 0, "R1": 1, "R2": 2, "R3": 3, "R4": 4, "R5": 5, "R6": 6, "R7": 7, "R8": 8, "R9": 9, "R10": 10, "R11": 11, "R12": 12, "R13": 13, "R14": 14, "R15": 15, "SCREEN": 16384, "KBD": 24576}## comp tableCOMP_TABLE = { "0": "0101010", "1": "0111111", "-1": "0111010", "D": "0001100", "A": "0110000", "!D": "0001101", "!A": "0110001", "-D": "0001111", "-A": "0110011", "D+1": "0011111", "A+1": "0110111", "D-1": "0001110", "A-1": "0110010", "D+A": "0000010", "D-A": "0010011", "A-D": "0000111", "D&A": "0000000", "D|A": "0010101", "M": "1110000", "!M": "1110001", "-M": "1110011", "M+1": "1110111", "M-1": "1110010", "D+M": "1000010", "D-M": "1010011", "M-D": "1000111", "D&M": "1000000", "D|M": "1010101"}## dest tableDEST_TABLE = { "null": "000", "M": "001", "D": "010", "MD": "011", "A": "100", "AM": "101", "AD": "110", "AMD": "111"}## jump tableJUMP_TABLE = { "null": "000", "JGT": "001", "JEQ": "010", "JGE": "011", "JLT": "100", "JNE": "101", "JLE": "110", "JMP": "111"}#------------------## helper functions ##------------------### determine is Intdef isInt(str): try: int(str) return True except ValueError: return False## determine instruction typedef getInsType(ins): if ins[0] == '@': return 'a' return 'c'## split instruction### instruction Aram_variable_num = 16def valueOfAIns(ins): global ram_variable_num if SYMB_TABLE.has_key(ins[1:]): ins = SYMB_TABLE[ins[1:]] elif isInt(ins[1:]): ins = ins[1:] else: SYMB_TABLE[ins[1:]] = ram_variable_num ram_variable_num += 1 ins = SYMB_TABLE[ins[1:]] bin_value = bin(int(ins))[2:] zero_count = 16 - len(bin_value) zero_str = '0' * zero_count return zero_str + bin_value### instruction Cdef splitCIns(ins): c_parts = {} dest_splited = ins.split('=') if len(dest_splited) == 1: c_parts['dest'] = 'null' jump_splited = dest_splited[0].split(';') else: c_parts['dest'] = dest_splited[0] jump_splited = dest_splited[1].split(';') if len(jump_splited) == 1: c_parts['jump'] = 'null' else: c_parts['jump'] = jump_splited[1] c_parts['comp'] = jump_splited[0] return c_parts#------------## main logic ##------------### first pass### source filesf_name = sys.argv[1]sf = open(sf_name, 'r')### destination filedf_name = os.path.splitext(sf_name)[0] + ".tmp"df = open(df_name, 'w')line_num = 0for ins in sf: # comment ins = ins.split('//')[0] # white space ins = ins.strip() if len(ins) == 0: continue # label if ins[0] == '(' and ins[-1] == ')': SYMB_TABLE[ins[1:-1]] = line_num continue df.write(ins + '\n') line_num += 1sf.close()df.close()## second pass### source filesf_name = os.path.splitext(sf_name)[0] + ".tmp"sf = open(sf_name, 'r')### destination filedf_name = os.path.splitext(sf_name)[0] + ".hack"df = open(df_name, 'w')for ins in sf: ins = ins.strip() ins_type = getInsType(ins) if ins_type == 'a': val = valueOfAIns(ins) + '\n' df.write(val) elif ins_type == 'c': parts = splitCIns(ins) val = '111' + COMP_TABLE[parts['comp']] + DEST_TABLE[parts['dest']] + JUMP_TABLE[parts['jump']] + '\n' df.write(val)sf.close()df.close()