2016年2月10日水曜日

開発環境

  • OS X El Capitan - Apple (OS)
  • Emacs(Text Editor)
  • Java (実行環境)
  • Python 3.5(プログラミング言語)

コンピュータシステムの理論と実装 (Noam Nisan (著)、Shimon Schocken (著)、斎藤 康毅(翻訳)、オライリージャパン)の6章(アセンブラ)、6.5(プロジェクト)を取り組んでみる。

6.5(プロジェクト)

コード(Emacs)

assembler.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys

def commandType(line):
    if line[0] == '@':
        return 'A_COMMAND'    
    if line[0] == '(' and line[-1] == ')':
        return 'L_COMMAND'
    return 'C_COMMAND'

def symbol(line):
    type = commandType(line)
    if type == 'A_COMMAND':
        return line[1:]
    if type == 'L_COMMAND':
        return line[1:-1]

def dest(line):
    i = line.find('=')
    if i != -1:
        return line[:i]
    
def comp(line):
    i = line.find('=')
    if i == -1:
        i = -1
    j = line.find(';')
    if j == -1:
        return line[i+1:]
    return line[i+1:j]

def jump(line):
    i = line.find(';')
    if i != -1:
        return line[i + 1:]

def dest2bin(dest):
    if dest is None:
        return '000'
    if dest == 'M':
        return '001'
    if dest == 'D':
        return '010'
    if dest == 'MD':
        return '011'
    if dest == 'A':
        return '100'
    if dest == 'AM':
        return '101'
    if dest == 'AD':
        return '110'
    if dest == 'AMD':
        return '111'
    raise Exception('dest2bin: {0}'.format(dest))

def comp2bin(comp):
    if comp == '0':
        return '0101010'
    if comp == '1':
        return '0111111'
    if comp == '-1':
        return '0111010'
    if comp == 'D':
        return '0001100'
    if comp == 'A':
        return '0110000'
    if comp == '!D':
        return '0001101'
    if comp == '!A':
        return '0110001'
    if comp == '-D':
        return '0001111'
    if comp == '-A':
        return '0110011'
    if comp == 'D+1':
        return '0011111'
    if comp == 'A+1':
        return '0110111'
    if comp == 'D-1':
        return '0001110'
    if comp == 'A-1':
        return '0110010'
    if comp == 'D+A':
        return '0000010'
    if comp == 'D-A':
        return '0010011'
    if comp == 'A-D':
        return '0000111'
    if comp == 'D&A':
        return '0000000'
    if comp == 'D|A':
        return '0010101'
    if comp == 'M':
        return '1110000'
    if comp == '!M':
        return '1110001'
    if comp == '-M':
        return '1110011'
    if comp == 'M+1':
        return '1110111'
    if comp == 'M-1':
        return '1110010'
    if comp == 'D+M':
        return '1000010'
    if comp == 'D-M':
        return '1010011'
    if comp == 'M-D':
        return '1000111'
    if comp == 'D&M':
        return '1000000'
    if comp == 'D|M':
        return '1010101'
    raise Exception("comp2bin: '{0}'".format(comp))
    

def jump2bin(jump):
    if jump == 'JGT':
        return '001'
    if jump == 'JEQ':
        return '010'
    if jump == 'JGE':
        return '011'
    if jump == 'JLT':
        return '100'
    if jump == 'JNE':
        return '101'
    if jump == 'JLE':
        return '110'
    if jump == 'JMP':
        return '111'
    if jump is None:
        return '000'
    raise Exception('jump2bin: {0}'.format(jump))

base_addr = 16
symtab = dict(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)

def toBin16bit(n):
    s = '0'
    for x in range(14, -1, -1):
        s += str(n // 2**x)
        n = n % 2**x
    return s

def is_num(s):
    for ch in s:
        if '0' <= ch <= '9':
            continue
        return False
    return True

if __name__ == '__main__':
    file1 = sys.argv[1]
    file2 = file1.replace(".asm", ".hack")
    with open(file1) as inf, open(file2, 'w') as outf:
        addr = 0
        for line in inf:
            line = line.strip()
            i = line.find('//')
            if i != -1:
                line = line[0:i].strip()
            if line == '':
                continue
            if commandType(line) == 'L_COMMAND':
                symtab[symbol(line)] = addr
            else:
                addr += 1
        inf.seek(0)
        for line in inf:
            line = line.strip()
            i = line.find('//')
            if i != -1:
                line = line[0:i].strip()
            if line == '':
                continue
            if commandType(line) == 'A_COMMAND':
                s = symbol(line)
                if is_num(s):
                    print(toBin16bit(int(s)), file=outf)
                else:
                    if s in symtab:
                        print(toBin16bit(int(symtab[s])), file=outf)
                    else:
                        print(toBin16bit(base_addr), file=outf)
                        symtab[s] = base_addr                        
                        base_addr += 1
            elif commandType(line) == 'C_COMMAND':
                print('111{comp}{dest}{jump}'.format(
                    comp=comp2bin(comp(line)), dest=dest2bin(dest(line)),
                    jump=jump2bin(jump(line))),
                      file=outf)

0 コメント:

コメントを投稿