def __write_cmp(jump_type): """Pop 2 items off the stack, compare them, push the result back on""" # pop an item off the stack # D = M # pop another item off the stack # D = D - M # @TRUE_0 # D; JEQ # (FALSE_0) # D = 0 # @END_0 # 0; jump_type # (TRUE_0) # D = 1 # (END_0) # push() if jump_type not in ['EQ', 'GT', 'LT', 'GE', 'LE', 'NE']: raise Exception("Unexpected Jump Type: {0}".format(jump_type)) true_label = unique("TRUE") false_label = unique("FALSE") end_label = unique("END") return (pop() + ['D=M'] + pop() + ['D=M-D', at(true_label), 'D;J{0}'.format(jump_type), '({0})'.format(false_label), 'D=0', at(end_label), '0;JMP', '({0})'.format(true_label), 'D=-1', # -1 == 11111...11 in 2's complement '({0})'.format(end_label)] + push())
def write_pop(segment, i, ftitle=None): """Pop a value from the stack and store it at position i in segment""" # local, argument, this, and that are implemented the same way standard_segs = { "local": "LCL", "argument": "ARG", "this": "THIS", "that": "THAT", } if segment in standard_segs: segname = standard_segs[segment] return ([ at(segname), # addr=segname+i "D=M", at(i), "D=D+A", at('addr'), "M=D" ] + pop() + [ "D=M", at('addr'), # *addr=*SP "A=M", "M=D" ]) elif segment == "temp": return ([ at(5), # temp base address is 5 "D=A", at(i), "D=D+A", at('addr'), "M=D" ] + pop() + [ "D=M", at('addr'), # *addr=*SP "A=M", "M=D" ]) elif segment == "static": label = "{0}.{1}".format(ftitle, i) return pop() + ["D=M", at(label), "M=D"] elif segment == "pointer": if int(i) not in [0, 1]: raise Exception('Invalid i for pop pointer: ' + str(i)) target = "THAT" if int(i) else "THIS" return [ "@SP", # SP-- "M=M-1", "A=M", # THIS/THAT = *SP "D=M", at(target), "M=D" ] raise Exception("{0} segment type not implemented yet".format(segment))
def write_return(): # endFrame = LCL # retAddr = *(endFrame-5) # *ARG = pop(), sets return value to arg[0] # SP = ARG+1 # endFrame -=1, THAT = *(endFrame) # endFrame -=1, THIS = *(endFrame) # endFrame -=1, ARG = *(endFrame) # endFrame -=1, LCL = *(endFrame) # goto retAddr # ---- implementation ---- # endFrame = LCL output = [at("LCL"), "D=M", at("endFrame"), "M=D"] # retAddr = *(endFrame-5) output += __write_save_retAddr() # *ARG = pop() output += (["// *ARG = pop()"] + pop() + ["D=M", "@ARG", "A=M", "M=D"]) # SP = ARG+1 output += ["// SP = ARG+1", "@ARG", "D=M+1", "@SP", "M=D"] # endFrame -=1, segm_var = *(endFrame) output += __write_restore("THAT") output += __write_restore("THIS") output += __write_restore("ARG") output += __write_restore("LCL") # goto retAddr output += ["// goto retAddr", "@retAddr", "A=M", "0;JMP"] return output
def __write_bitwise(op): """Pop 2 items off the stack, do a bitwise operation, push result back on this is only used for operations which do not need a jump""" if op not in ['|', '&', '+', '-']: raise Exception("Unexpected Bitwise Operation: {0}".format(op)) return pop() + ['D=M'] + pop() + ['D=M{0}D'.format(op)] + push()
def write_not(): """Pop 1 item off the stack, negate it, push the result back on""" return pop() + ['D=!M'] + push()
def write_if_goto(label, func): return pop() + ["D=M", at(func + '$' + label), "D; JNE"]
def __write_save_retAddr(): """Saves the return address in a local variable. """ return (["// retAddr = *(endFrame - 5)", at("endFrame"), "D=M"] + push() + [at(5), "D=A", "// push"] + push() + ["// write_sub"] + write_sub() + ["// pop"] + pop() + ["A=M", "D=M", at("retAddr"), "M=D"])