コード例 #1
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def if_then_statement(subtree):
    condition_asm = subtree[2].assembly
    then_asm = subtree.find("then").assembly
    else_asm = subtree.find("else").assembly  # Empty string if no else block
    condition_slot = subtree[2].slot
    label_no = new_label_no()
    top_of_else_label = "ELSE_" + str(label_no) + "_top"
    bottom_of_else_label = "ELSE_" + str(label_no) + "_bottom"
    subtree.assembly = """
; begin if statement, test condition if ({dbg})
{condition_asm}
cmp {condition_slot}, 0
jz .{top_of_else_label}
; end if ({dbg}) condition check, begin then block
{then_asm}
jmp .{bottom_of_else_label}
; end if ({dbg}) then block, begin else block
.{top_of_else_label}:
{else_asm}
.{bottom_of_else_label}:
; end if ({dbg}) else block
""".format(
        dbg=collect_debug_text(subtree[2]),
        condition_asm=condition_asm,
        condition_slot=stack_slot_to_operand(condition_slot),
        bottom_of_else_label=bottom_of_else_label,
        then_asm=then_asm,
        top_of_else_label=top_of_else_label,
        else_asm=else_asm,
    )
コード例 #2
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def class_instance_creation(subtree):
    subtree.slot = generate_new_stack_slot(subtree)
    declaration_site = typechecker.resolve_constructor_name(subtree)
    size = (declaration_site.env.findclass("this").num_fields + 1) * 4
    # TODO: Initialize the vtable somehow
    constructor_name = mangle_fn_name(declaration_site)
    vtable_name = vtable_name_for_class(declaration_site.env.findclass("this"))
    pushes = push_arguments(subtree)
    return_slot = stack_slot_to_operand(subtree.slot)
    subtree.assembly = """
; invoke constructor {dbg}
mov eax, {size}
call __malloc
mov DWORD [eax], {vtable}
{pushes}
push eax
call {constructor}
mov {return_slot}, eax
; end invoke constructor
""".format(
        dbg=collect_debug_text(subtree),
        size=size,
        constructor=constructor_name,
        pushes="\n".join(pushes),
        return_slot=return_slot,
        vtable=vtable_name,
    )
コード例 #3
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def array_access(subtree):
    subtree.slot = generate_new_stack_slot(subtree)
    subtree.memory_location = generate_new_stack_slot(subtree)
    subtree.assembly = """
; array access {dbg}
mov eax, {expression_value}
mov ebx, {array_pointer}

; array bounds check
mov edx, [ebx + 8]
cmp edx, eax
jle __exception

mov ecx, 4
imul ecx
add eax, 12
add eax, ebx
mov {memory_location}, eax
mov ebx, [eax]
mov {destination}, ebx
; done array access
""".format(
        dbg=collect_debug_text(subtree),
        expression_value=stack_slot_to_operand(subtree[2].slot),
        array_pointer=stack_slot_to_operand(subtree[0].slot),
        memory_location=stack_slot_to_operand(subtree.memory_location),
        destination=stack_slot_to_operand(subtree.slot),
    )
コード例 #4
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def unary_expression_not_plus_minus(subtree):
    if subtree[0].tag == "tok_complement":
        # Unary boolean complement
        subtree.slot = subtree[1].slot
        subtree.assembly = """
; Unary complement {dbg}
not {reg}
""".format(
            dbg=collect_debug_text(subtree), reg=stack_slot_to_operand(subtree.slot)
        )
コード例 #5
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def unary_expression(subtree):
    if subtree[0].tag == "tok_minus":
        # Unary minus
        subtree.slot = subtree[1].slot
        subtree.assembly = """
; Unary Minus {dbg}
neg {reg}
""".format(
            dbg=collect_debug_text(subtree), reg=stack_slot_to_operand(subtree.slot)
        )
コード例 #6
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def local_variable_declaration(subtree):
    subtree.slot = generate_new_stack_slot(subtree)
    subtree.assembly = """
; local variable declaration {dbg}
mov eax, {source}
mov {dest}, eax
; end local variable declaration
""".format(
        dbg=collect_debug_text(subtree),
        dest=stack_slot_to_operand(subtree.slot),
        source=stack_slot_to_operand(subtree.find("expression").slot),
    )
コード例 #7
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def multiplicative_expression(subtree):
    lhs_location = subtree[0].slot
    rhs_location = subtree[2].slot
    new_stack_slot = generate_new_stack_slot(subtree)
    operator_type = collect_token_text(subtree[1])
    result = operator = ""
    if operator_type == "*":
        operator = "imul"
        result = "eax"
        check = ""
    elif operator_type == "/":
        operator = "idiv"
        result = "eax"
        label_no = new_label_no()
        check = """
sub ebx, 0
jne .{okay_label}
call __exception
.{okay_label}:
""".format(
            okay_label="DIV0_CHECK_" + str(label_no)
        )
    elif operator_type == "%":
        operator = "idiv"
        result = "edx"
        check = ""
    else:
        error_if(True, "Unknown argument to mulitplicative expression")
    subtree.assembly = """
; multiplicative {dbg}
mov edx, {lhs}
mov eax, edx
sar edx, 31
mov ebx, {rhs}
{check}
{op} ebx
mov {nss}, {result}
; end multiplicative
""".format(
        nss=stack_slot_to_operand(new_stack_slot),
        lhs=stack_slot_to_operand(lhs_location),
        rhs=stack_slot_to_operand(rhs_location),
        result=result,
        check=check,
        op=operator,
        imul_part=operator == "imul" and ", edx" or "",
        dbg=collect_debug_text(subtree),
    )
    subtree.slot = new_stack_slot
コード例 #8
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def empty_expression(subtree):
    value = subtree.get("value")
    if value == "True":
        value = true
    elif value == "False":
        value = false
    error_if(value is None, "None in empty expression!")
    new_stack_slot = generate_new_stack_slot(subtree)
    subtree.assembly = """
; empty expr {dbg}
mov {nss}, {val}
; end empty expr
""".format(
        nss=stack_slot_to_operand(new_stack_slot), val=value, dbg=collect_debug_text(subtree)
    )
    subtree.slot = new_stack_slot
コード例 #9
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def cast_expression(subtree):
    if subtree[1].tag == "name":
        expression_being_cast = subtree.find("unary_expression_not_plus_minus")
        cast_tree = subtree[1]
        # if element.find("dims"):
        #    cast_type += "[]"
    elif subtree[1].tag == "expression":
        # Expression case
        cast_tree = subtree[1]
        expression_being_cast = subtree[-1]
    elif subtree.find("dims") is not None:
        cast_tree = subtree[1]
        expression_being_cast = subtree[-1]
    else:
        # Primitive cast case
        subtree.slot = subtree[-1].slot
        if hasattr(subtree[-1], "memory_location"):
            subtree.memory_location = subtree[-1].memory_location
        return
    slot = generate_new_stack_slot(subtree)
    value_slot = expression_being_cast.slot
    debug_string = (
        "ClassCastException check  " + collect_debug_text(subtree) + " with result in " + stack_slot_to_operand(slot)
    )
    subtree.assembly = instanceof_assembly(
        value_slot, slot, cast_tree, debug_string, isarray=subtree.find("dims") is not None
    )
    valid_label = ".VALID_CAST_" + str(new_label_no())
    subtree.assembly += """
; Raise exception if instanceof check failed
mov eax, {test_slot}
sub eax, -1
jz {valid_label}
; check for null (can cast null to reference types)
mov eax, {lhs_slot}
sub eax, 0
jz {valid_label}
call __exception
{valid_label}:
""".format(
        lhs_slot=stack_slot_to_operand(value_slot), valid_label=valid_label, test_slot=stack_slot_to_operand(slot)
    )
    subtree.slot = subtree[-1].slot
    if hasattr(subtree[-1], "memory_location"):
        subtree.memory_location = subtree[-1].memory_location
コード例 #10
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def assignment(subtree):
    subtree.slot = generate_new_stack_slot(subtree)  # subtree[0].slot
    if hasattr(subtree[0], "memory_location"):
        subtree.memory_location = subtree[0].memory_location
        subtree.assembly = """
; assign {dbg}
mov eax, {value}
mov ebx, {memory_dst}
mov DWORD [ebx], eax
mov {value_dst}, eax
mov {value_dst2}, eax
; end assign
""".format(
            dbg=collect_debug_text(subtree),
            value=stack_slot_to_operand(subtree[-1].slot),
            memory_dst=stack_slot_to_operand(subtree.memory_location),
            value_dst=stack_slot_to_operand(subtree.slot),
            value_dst2=stack_slot_to_operand(subtree[0].slot),
        )
コード例 #11
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def for_statement(subtree):
    for_init_asm = subtree.find("for_init").assembly
    for_test_asm = subtree[3].assembly
    for_test_slot = subtree[3].slot
    for_update_asm = ""
    if subtree.find("for_update") is not None:
        for_update_asm = subtree.find("for_update").assembly
    body_asm = subtree[-1].assembly
    label_no = new_label_no()
    top_of_loop_label = "FOR_" + str(label_no) + "_top"
    bottom_of_loop_label = "FOR_" + str(label_no) + "_bottom"
    debug_string = collect_debug_text(subtree[0:6])
    subtree.assembly = """
; begin {dbg} init
{for_init_asm}
.{top_of_loop_label}:
; begin {dbg} test
{for_test}
; end for statement test
cmp {for_test_slot}, 0
jz .{bottom_of_loop_label}
; {dbg} body
{body_asm}
; end for statement body, for statement update:
{for_update_asm}
jmp .{top_of_loop_label}
.{bottom_of_loop_label}:
; end for statement {dbg}
""".format(
        dbg=debug_string,
        for_init_asm=for_init_asm,
        top_of_loop_label=top_of_loop_label,
        for_test=for_test_asm,
        for_test_slot=stack_slot_to_operand(for_test_slot),
        bottom_of_loop_label=bottom_of_loop_label,
        body_asm=body_asm,
        for_update_asm=for_update_asm,
    )
コード例 #12
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def method_invocation(subtree):
    method = subtree.declaration
    subtree.slot = generate_new_stack_slot(subtree)
    pushes = push_arguments(subtree)
    if "static" not in modifiers(method):
        if subtree[0].tag == "name":
            name(subtree[0], args=argument_list(subtree))
        pushes.append("push " + stack_slot_to_operand(subtree[0].slot))

    return_slot = stack_slot_to_operand(subtree.slot)
    if "native" in modifiers(method):
        call = "call " + mangle_native_fn_name(subtree.declaration)
        argument_slot = subtree.find("./argument_list").slot
        operand = stack_slot_to_operand(argument_slot)
        pushes = ["mov eax, {slot}".format(slot=operand)]
    elif "static" in modifiers(method):
        call = "call " + mangle_fn_name(subtree.declaration)
    else:
        call = """
mov eax, {this_ptr}
mov eax, [eax]
add eax, {method_offset}
mov eax, [eax]
call eax
""".format(
            this_ptr=stack_slot_to_operand(subtree[0].slot), method_offset=str(4 * method.mega_vtable_offset)
        )

    subtree.assembly = """
; method invocation {dbg}
{push_arguments}
{call}
mov {return_slot}, eax
; end method invocation
""".format(
        dbg=collect_debug_text(subtree), call=call, push_arguments="\n".join(pushes), return_slot=return_slot
    )
コード例 #13
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def eager_or_expression(subtree):
    error_if(subtree[1].tag != "tok_bit_or", "Unexpected structure to eager or expression")
    subtree.slot = generate_new_stack_slot(subtree)
    subtree.assembly = binary_operator_assembly(
        subtree[0].slot, subtree[2].slot, "or", subtree.slot, collect_debug_text(subtree)
    )
コード例 #14
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def additive_expression(subtree):
    lhs_slot = subtree[0].slot
    rhs_slot = subtree[2].slot
    result_slot = generate_new_stack_slot(subtree)

    lhs_type = subtree[0].get("type")
    rhs_type = subtree[2].get("type")
    if "java.lang.String" in [lhs_type, rhs_type]:
        (lhs_slot, lhs_assembly) = generate_promotion_to_string(subtree[0])
        (rhs_slot, rhs_assembly) = generate_promotion_to_string(subtree[2])
        assembly = """
; string additive expression
{lhs_assembly}
{rhs_assembly}

mov eax, {lhs_slot}
mov ebx, {rhs_slot}

push ebx
push eax
call java_lang_String_concat_java_lang_String_
mov {result_slot}, eax
""".format(
            lhs_assembly=lhs_assembly,
            rhs_assembly=rhs_assembly,
            rhs_slot=stack_slot_to_operand(rhs_slot),
            lhs_slot=stack_slot_to_operand(lhs_slot),
            result_slot=stack_slot_to_operand(result_slot),
        )
        subtree.assembly = assembly
        subtree.slot = result_slot
        return

    operator_type = collect_token_text(subtree[1])
    operator = ""
    if operator_type == "+":
        operator = "add"
    elif operator_type == "-":
        operator = "sub"
    else:
        error_if(True, "Unknown additive_expression operator_type")

    subtree.assembly = binary_operator_assembly(lhs_slot, rhs_slot, operator, result_slot, collect_debug_text(subtree))
    subtree.slot = result_slot
コード例 #15
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def instanceof_expression(subtree):
    lhs_location = subtree[0].slot
    subtree.slot = generate_new_stack_slot(subtree)
    subtree.assembly = instanceof_assembly(lhs_location, subtree.slot, subtree[2], collect_debug_text(subtree))
コード例 #16
0
ファイル: generate.py プロジェクト: thurn/cs444-compiler
def name(subtree, args=None):
    # TODO: pathing
    # subtree.slot = subtree.declaration.slot
    try:
        path = subtree.env.get_declaration_path_for_name(name_to_str(subtree), args)
        if not path:
            return

        subtree.assembly = "; name {dbg}\n".format(dbg=collect_debug_text(subtree))
        if path[0].tag == "method" or path[0].tag == "abstract_method":
            subtree.slot = this
        if path[0].tag == "class":
            subtree.slot = generate_new_stack_slot(subtree)
            subtree.memory_location = generate_new_stack_slot(subtree)
            mangled_name = mangle_field_name(path[1])
            subtree.assembly += """
mov eax, {mangled_name}
mov ebx, DWORD [eax]
mov {memory_dst}, eax
mov {value_dst}, ebx
""".format(
                mangled_name=mangled_name,
                memory_dst=stack_slot_to_operand(subtree.memory_location),
                value_dst=stack_slot_to_operand(subtree.slot),
            )
            path = path[1:]
        elif path[0].tag == "field":
            subtree.slot = generate_new_stack_slot(subtree)
            subtree.memory_location = generate_new_stack_slot(subtree)
            subtree.assembly += """
mov eax, DWORD [ebp + 8] ; this -> eax
mov ebx, [eax + {field_location}]
add eax, {field_location}
mov {mem_loc}, eax
mov {dest}, ebx
""".format(
                field_location=path[0].field_offset * 4,
                dest=stack_slot_to_operand(subtree.slot),
                mem_loc=stack_slot_to_operand(subtree.memory_location),
            )
        elif path[0].tag == "local_variable_declaration" or path[0].tag == "param":
            if not hasattr(path[0], "slot"):
                return
            subtree.slot = generate_new_stack_slot(subtree)
            subtree.memory_location = generate_new_stack_slot(subtree)
            subtree.assembly += """
mov eax, {source}
mov {dest}, eax
mov ebx, ebp
sub ebx, {source_stack_slot}
mov {mem_loc}, ebx
""".format(
                source=stack_slot_to_operand(path[0].slot),
                source_stack_slot=path[0].slot * 4,
                mem_loc=stack_slot_to_operand(subtree.memory_location),
                dest=stack_slot_to_operand(subtree.slot),
            )
        for child in path[1:]:
            if child.tag in ["method", "abstract_method"]:
                return
            former_slot = subtree.slot
            subtree.slot = generate_new_stack_slot(subtree)
            subtree.memory_location = generate_new_stack_slot(subtree)
            if not hasattr(subtree, "assembly"):
                subtree.assembly = ""
            subtree.assembly += """
mov eax, {former_location}
mov ebx, [eax + {field_location}]
add eax, {field_location}
mov {mem_loc}, eax
mov {dest}, ebx
""".format(
                former_location=stack_slot_to_operand(former_slot),
                field_location=child.field_offset * 4,
                dest=stack_slot_to_operand(subtree.slot),
                mem_loc=stack_slot_to_operand(subtree.memory_location),
            )

    except JoosSyntaxException:
        pass