Created
January 31, 2011 01:00
-
-
Save jweissbock/803500 to your computer and use it in GitHub Desktop.
HACK Assembler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# we need our imports | |
import string, sys | |
# global hash table | |
hashTable = {} | |
RAMstart = 16 # variables are stored in RAM[16] to... RAM[255]?? | |
# parse the assembly | |
def Assembler(filename): | |
# define the variables we need to | |
lineCount = 0 | |
# open the file | |
print "Opening File... " | |
f = open(filename, 'r') | |
print "Looking for symbols" | |
# first read through | |
# scan through once for symbols... into our hash table | |
for line in f: | |
# skip new lines | |
if line[:2] == "//" or line == '\n': | |
continue | |
# parse line | |
line = parseLine(line) | |
if not line: | |
continue | |
commandType = cType(line) | |
if commandType == 'L_COMMAND': | |
hashTable[line[1:-1]] = lineCount | |
else: | |
lineCount += 1 | |
# seek file back to start | |
f.seek(0); | |
# second read through - parse | |
# loop through it, print out non empty and new-line lines. | |
print "Reading, Assembling and Writing Files..." | |
# open file to write to | |
nFile = filename[0:filename.find('.')] + ".hack" | |
newFile = open(nFile, "w") | |
for line in f: | |
if line[:2] == "//" or line == '\n': | |
continue | |
# parse the line | |
line = parseLine(line) | |
# check if it's a blank line | |
if not line: | |
continue | |
# get the cType | |
commandType = cType(line) | |
# if we dunno what it is, break system | |
if commandType == 'Error': | |
print "Assembler Error on line : " + line | |
# print machine code | |
if commandType == 'A_COMMAND': | |
machineCode = aCommand(line) | |
newFile.write(machineCode + "\n") | |
elif commandType == 'C_COMMAND': | |
machineCode = cCommand(line) | |
newFile.write(machineCode + "\n") | |
# close the file | |
f.close() | |
newFile.close() | |
print "Assembled Successfully" | |
# returns the c-instruction code | |
def cCommand(input): | |
return '111' + comp(input) + dest(input) + jump(input) | |
# get the comp value | |
def comp(input) : | |
if input.find('=') > -1: | |
input = input[input.find('=')+1 :] | |
elif input.find(';') > -1: | |
input = input[0:input.find(';')] | |
else: | |
return '0000000' | |
comp = {'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'} | |
return comp[input] | |
# get the dest value | |
def dest(input) : | |
dest = {'M': '001', 'D': '010', 'MD': '011', 'A': '100', | |
'AM': '101', 'AD': '110', 'AMD': '111'} | |
if input.find('=') == -1: | |
return '000' | |
else: | |
destSgmt = input[0: input.find('=')] | |
return dest[destSgmt] | |
# get the jump value | |
def jump(input) : | |
jmp = {'JGT': '001', 'JEQ': '010', 'JGE': '011', 'JLT': '100', | |
'JNE': '101', 'JLE': '110', 'JMP': '111'} | |
if input.find(';') == -1: | |
return '000' | |
else: | |
jmpSgmt = input[input.find(';')+1 :] | |
return jmp[jmpSgmt] | |
# returns a-instruction code | |
def aCommand(input): | |
#map the special addresses | |
symbols = {'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' } | |
global RAMstart | |
input = input[1:] | |
if input in symbols.keys(): | |
input = symbols[input] | |
elif input.isdigit(): | |
input = input | |
elif input in hashTable.keys(): | |
input = hashTable[input] | |
else: | |
# it's a variable, store it, return RAM address | |
hashTable[input] = RAMstart | |
input = RAMstart | |
RAMstart += 1 | |
num = bin(int(input))[2:].zfill(15) | |
return '0' + str(num) | |
# Get the command type of this line | |
def cType(c): | |
# grab the variables we need | |
command = ['A_COMMAND', 'C_COMMAND', 'L_COMMAND', 'ERROR'] | |
# check if it is an A_COMMAND @likethis | |
if c[0] == '@': | |
return command[0] # is an A-instruction | |
elif c[0] == '(' and c[len(c)-1] == ')': | |
return command[2] # is a label | |
elif c.find(';') > -1 or c.find('=') > -1: | |
return command[1] # is C-instruction | |
else: | |
return command[3] # dunno what it is - break assembler error | |
# parse a line, remove white space and \n | |
def parseLine(input): | |
# parse out white space | |
input = string.join(input.split(), "") | |
# and new lines | |
input = input.rstrip('\n') | |
## check and remove comments | |
if input.find('//') > -1: | |
input = input[0:input.find('//')] | |
return input | |
# get file name | |
file = raw_input("Enter file name: ") | |
Assembler(file) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment