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())
Example #2
0
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"])