[Coursera][From Nand to Tetris / Part I] 第六周 汇编器项目 python 实现
admin
2023-07-31 01:51:19
0

今天折腾一上午,终于 完成了 Coursera 上 From Nand to Tetris / Part I 这个课程的最后一个汇编器项目。这套课程真是没白跟,收获良多,现在已经等不及想看下一期的软件部分了,哈哈。

下面是我的 python 实现,存个档,同时给同样在看这课程的同学们参考。

注释风格看起来可能有点奇怪,拍脑袋想的,没多少 python 编码经验,还望包涵,稍微解释一下:

#-----------------#
# 大块代码用途描述 #
#-----------------#

## 分级注释

### 分级注释

#### 分级注释

import sys
import os.path


#--------#
# tables #
#--------#

## symbol table

SYMB_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 table

COMP_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 table

DEST_TABLE = {
    \"null\": \"000\",
    \"M\":    \"001\",
    \"D\":    \"010\",
    \"MD\":   \"011\",
    \"A\":    \"100\",
    \"AM\":   \"101\",
    \"AD\":   \"110\",
    \"AMD\":  \"111\"
}

## jump table

JUMP_TABLE = {
    \"null\": \"000\",
    \"JGT\":  \"001\",
    \"JEQ\":  \"010\",
    \"JGE\":  \"011\",
    \"JLT\":  \"100\",
    \"JNE\":  \"101\",
    \"JLE\":  \"110\",
    \"JMP\":  \"111\"
}


#------------------#
# helper functions #
#------------------#

## determine is Int

def isInt(str):
    try:
        int(str)
        return True
    except ValueError:
        return False

## determine instruction type

def getInsType(ins):
    if ins[0] == \'@\':
        return \'a\'
    return \'c\'

## split instruction

### instruction A

ram_variable_num = 16

def 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 C

def 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 file

sf_name = sys.argv[1]
sf = open(sf_name, \'r\')

### destination file

df_name = os.path.splitext(sf_name)[0] + \".tmp\"
df = open(df_name, \'w\')

line_num = 0

for 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 += 1

sf.close()
df.close()

## second pass

### source file

sf_name = os.path.splitext(sf_name)[0] + \".tmp\"
sf = open(sf_name, \'r\')

### destination file

df_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()

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...