[Coursera][From Nand to Tetris / Part I] 第六周 汇编器项目 python 实现

今天折腾一上午,终于 完成了 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()

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java架构

前大众点评资深研发专家对Mysql索引的解析与底层数据结构的解刨

mysql索引: 是一种帮助mysql高效的获取数据的数据结构,这些数据结构以某种方式引用数据,这种结构就是索引。可简单理解为排好序的快速查找数据结构。如果要查...

2204
来自专栏大数据架构

Spark SQL / Catalyst 内部原理 与 RBO

从上图可见,无论是直接使用 SQL 语句还是使用 DataFrame,都会经过如下步骤转换成 DAG 对 RDD 的操作

3246
来自专栏GIS讲堂

SQL之学生选课数据库

Restrict说明删除是有条件的,cascade说明该表的删除没有任何限制。

4933
来自专栏lgp20151222

postgresql安装,java简单使用postgresql

由于本人的学过的技术太多太乱了,于是决定一个一个的整合到一个springboot项目里面。

881
来自专栏Spark学习技巧

Table API&SQL的基本概念及使用介绍

Table API和SQL集成在共同API中。这个API的中心概念是一个用作查询的输入和输出的表。本文档显示了具有表API和SQL查询的程序的常见结构,如何注册...

2.2K6
来自专栏GreenLeaves

使用group by rollup和group by cube后的辅助函数

本文主要介绍,报表在使用group by rollup和group by cube后的辅助函数。 CREATE TABLE TEST8 ( "ID...

2587
来自专栏Java3y

移动商城第七篇【购物车增删改查、提交订单】

把商品加入购物车 接下来我们要做的就是将商品加入到购物车中。我们这次使用的是Cookie来将用户的信息存储起来。那为什么要用cookie呢?? 如果将购物车存储...

1.3K14
来自专栏跟着阿笨一起玩NET

C#常用工具类——Excel操作类

1591
来自专栏大数据架构

Spark SQL / Catalyst 内部原理 与 RBO

从上图可见,无论是直接使用 SQL 语句还是使用 DataFrame,都会经过如下步骤转换成 DAG 对 RDD 的操作

1072
来自专栏JavaEdge

MySQL索引及其实现原理(基于MyISAM及InnoDB引擎)

查询是数据库的最主要功能之一。我们都希望查询速度能尽可能快,因此数据库系统的设计者会从查询算法角度优化

3.7K10

扫码关注云+社区

领取腾讯云代金券