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_push(segment, i, ftitle=None): """Push value i from a segment onto the stack""" # 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", "A=D", "D=M" ] + push()) elif segment == "temp": return ([ at(5), # temp base address is 5 "D=A", at(i), "D=D+A", "A=D", "D=M" ] + push()) elif segment == "static": label = "{0}.{1}".format(ftitle, i) return [at(label), "D=M"] + push() elif segment == "pointer": if int(i) not in [0, 1]: raise Exception('Invalid i for push pointer: ' + str(i)) target = "THAT" if int(i) else "THIS" return [ at(target), # *SP = THIS/THAT "D=M", "@SP", "A=M", "M=D", "@SP", # SP++ "M=M+1" ] elif segment == "constant": return [at(i), "D=A"] + push() raise Exception("{0} segment type not implemented yet".format(segment))
def write_call(func_name, num_args, curr_func, num_calls): return_label = "{0}$ret.{1}".format(curr_func, num_calls) # push returnLabel output = [at(return_label), "D=A"] + push() # push LCL output += [at("LCL"), "D=M"] + push() # push ARG output += [at("ARG"), "D=M"] + push() # push THIS output += [at("THIS"), "D=M"] + push() # push THAT output += [at("THAT"), "D=M"] + push() # ARG=SP-5-nArgs output += [at("SP"), "D=M-1"] for i in range(3 + int(num_args)): output.append("D=D-1") output += [at("ARG"), "M=D-1"] # LCL=SP output += [at("SP"), "D=M", at("LCL"), "M=D"] # goto functionName output += [at(func_name), "0;JMP"] # (returnLabel) output.append("({0})".format(return_label)) 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_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"])
def write_function(func_name, num_vars): output = ["({0})".format(func_name)] for i in range(int(num_vars)): output += ["D=0"] + push() return output