Exemplo n.º 1
0
def case_statement(stmnt, symbol_table):
    try:
        _ = symbol_table['__ switch __']
    except KeyError as _:
        raise ValueError('{l} case statement outside switch statement'.format(l=loc(stmnt)))
    initial_instr = Pass(loc(stmnt))
    stmnt.stack = deepcopy(symbol_table['__ stack __'])  # case statements may be placed in nested compound statements.
    initial_instr.case = stmnt
    return chain((initial_instr,), symbol_table['__ statement __'](stmnt.statement, symbol_table))
Exemplo n.º 2
0
def static_definition(stmnt, symbol_table):
    def load_address(self, location):
        return push(Address(self._initial_data, location), location)

    data = static_def_binaries(stmnt, (Pass(loc(stmnt)),))
    stmnt._initial_data = peek(data)
    stmnt.end_of_data = Pass(loc(stmnt))
    stmnt.load_address = bind_load_address_func(load_address, stmnt)
    symbol_table[declarations.name(stmnt)] = stmnt
    return chain(  # jump over embedded data ...
        relative_jump(Offset(stmnt.end_of_data, loc(stmnt)), loc(stmnt)), consume_all(data), (stmnt.end_of_data,)
    )
Exemplo n.º 3
0
def case_statement(stmnt, symbol_table):
    try:
        _ = symbol_table['__ switch __']
    except KeyError as _:
        raise ValueError(
            '{l} case statement outside switch statement'.format(l=loc(stmnt)))
    initial_instr = Pass(loc(stmnt))
    stmnt.stack = deepcopy(
        symbol_table['__ stack __']
    )  # case statements may be placed in nested compound statements.
    initial_instr.case = stmnt
    return chain((initial_instr, ),
                 symbol_table['__ statement __'](stmnt.statement,
                                                 symbol_table))
Exemplo n.º 4
0
def ternary_expression(expr, symbol_table):
    if_false_instr, end_of_conditional_instr = Pass(loc(expr)), Pass(loc(expr))
    expression = symbol_table['__ expression __']
    return chain(
        get_jump_false(size_arrays_as_pointers(c_type(exp(expr))))(expression(
            exp(expr), symbol_table), Offset(if_false_instr, loc(expr)),
                                                                   loc(expr)),
        expression(left_exp(expr), symbol_table),
        relative_jump(
            Offset(end_of_conditional_instr, loc(end_of_conditional_instr)),
            loc(expr)),
        (if_false_instr, ),
        expression(right_exp(expr), symbol_table),
        (end_of_conditional_instr, ),
    )
Exemplo n.º 5
0
def remove_allocation(instrs):
    """
        optimize 1 or more sequence of allocations ...
        take their sum and if zero replace with the next instruction in case this one is referenced.
        other wise do one allocation and remove rest
        replace allocate 1 with POP, which only requires a single address translation vs 2 (instr, oprn) for allocate.
    """
    alloc_instrs = tuple(
        takewhile(
            lambda i: isinstance(i, Allocate) and isinstance(
                opern(i), (int, long)), instrs))

    if not alloc_instrs:  # Operand must be non-primitive type (Address) ... must wait for its value.
        yield consume(instrs)
    else:
        total = sum(imap(opern, alloc_instrs))

        if total:  # non-zero allocates changes the state of the stack.
            if total in pop_instrs:
                new_instr = next(pop_instrs[total](loc(alloc_instrs[0])))
            elif len(alloc_instrs) != 1:
                new_instr = alloc_instrs[0]
            else:
                new_instr = Allocate(loc(alloc_instrs[-1]), total)
            yield replace_instrs(new_instr, alloc_instrs)
        else:  # stack remains unchanged, get next instruction for referencing, it one exists ...
            if peek_or_terminal(instrs) is terminal:
                yield replace_instr(Pass(loc(alloc_instrs[-1])), alloc_instrs)
            else:
                replace_instrs(peek(instrs), alloc_instrs)
Exemplo n.º 6
0
def declaration(stmnt, symbol_table):
    # This are non-global declarations they don't require any space
    # but they could be referenced (extern, or function type)
    symbol_type = Code if isinstance(c_type(stmnt), FunctionType) else Data
    stmnt.symbol = symbol_type(declarations.name(stmnt), (), None, stmnt.storage_class, loc(stmnt))
    stmnt.symbol.size = size(c_type(stmnt), overrides={FunctionType: None})
    symbol_table[declarations.name(stmnt)] = stmnt
    yield Pass(loc(stmnt))
Exemplo n.º 7
0
def set_binaries(symbol):
    assert not symbol.binaries and isinstance(symbol, object_file.Data)
    instrs = starmap(Byte, repeat((0, loc(symbol)), symbol.size))
    first_instr = next(instrs, terminal)
    symbol.first_element = Pass(
        loc(symbol)
    ) if first_instr is terminal else first_instr  # zero sized decl use Pass
    symbol.binaries = chain((symbol.first_element, ), instrs)
    return symbol.binaries
Exemplo n.º 8
0
def if_statement(stmnt, symbol_table):
    end_of_if, end_of_else = Pass(loc(stmnt)), Pass(loc(stmnt))
    expression, statement = imap(symbol_table.__getitem__,
                                 ('__ expression __', '__ statement __'))
    for instr in chain(
            get_jump_false(size_arrays_as_pointers(c_type(exp(stmnt))))(
                expression(exp(stmnt), symbol_table),
                Offset(end_of_if, loc(end_of_if)), loc(end_of_if)),
            statement(stmnt.statement, symbol_table)):
        yield instr

    else_stmnt = stmnt.else_statement.statement
    if else_stmnt:
        for instr in chain(
                relative_jump(Offset(end_of_else, loc(end_of_else)),
                              loc(stmnt)),
            (end_of_if, ),
                statement(else_stmnt, symbol_table),
            (end_of_else, ),
        ):
            yield instr
    else:
        yield end_of_if
Exemplo n.º 9
0
def label_statement(stmnt, symbol_table):
    instr = Pass(loc(stmnt))
    labels, gotos, stack, statement = imap(
        symbol_table.__getitem__, ('__ LABELS __', '__ GOTOS __', '__ stack __', '__ statement __')
    )
    labels[name(stmnt)] = (instr, symbol_table['__ stack __'].stack_pointer)

    # update all previous gotos referring to this lbl
    for alloc_instr, rel_jump_instr, goto_stack_pointer in gotos[name(stmnt)]:
        # TODO: bug! set_address uses obj.address.
        alloc_instr[0].obj.address = alloc_instr.address + (stack.stack_pointer - goto_stack_pointer)
        rel_jump_instr[0].obj = instr

    del gotos[name(stmnt)][:]
    return chain((instr,), statement(stmnt.statement, symbol_table))
Exemplo n.º 10
0
def switch_statement(stmnt, symbol_table):
    _ = (not isinstance(c_type(exp(stmnt)), IntegralType)) and raise_error(
        '{l} Expected an integral type got {g}'.format(g=c_type(exp(stmnt)),
                                                       l=loc(stmnt)))

    end_switch = Pass(loc(stmnt))
    stmnt.stack = deepcopy(symbol_table['__ stack __'])

    # if switch inside loop, only update end_instruct, since continue jumps to start of loop break goes to end of switch
    def body(stmnt, symbol_table, end_switch):
        symbol_table = push(symbol_table)
        stack, statement = imap(symbol_table.__getitem__,
                                ('__ stack __', '__ statement __'))
        symbol_table['__ break __'] = (end_switch, stack.stack_pointer)
        symbol_table['__ switch __'] = True

        allocation_table = [
        ]  # create an allocation table to update stack before jump in case of nested definitions
        switch_body_instrs = []
        cases = {'default': Offset(end_switch, loc(stmnt))}

        for instr in statement(stmnt.statement, symbol_table):
            if isinstance(getattr(instr, 'case', None), CaseStatement):
                start = Pass(loc(instr))
                allocation_table.append(
                    chain(
                        (start, ),
                        update_stack(stmnt.stack.stack_pointer,
                                     instr.case.stack.stack_pointer,
                                     loc(instr)),
                        relative_jump(Offset(instr, loc(instr)), loc(instr)),
                    ))

                cases[error_if_not_type(exp(exp(instr.case)),
                                        (int, long, str))] = Offset(
                                            start, loc(instr))
                del instr.case
            switch_body_instrs.append(instr)

        max_switch_value = 2**(8 *
                               size_arrays_as_pointers(c_type(exp(stmnt)))) - 1
        for instr in jump_table(loc(stmnt), cases, allocation_table,
                                max_switch_value, switch_body_instrs):
            yield instr
        _ = pop(symbol_table)

    return chain(symbol_table['__ expression __'](exp(stmnt), symbol_table),
                 body(stmnt, symbol_table, end_switch), (end_switch, ))
Exemplo n.º 11
0
def function_call(expr, symbol_table):
    assert not isinstance(c_type(expr), ArrayType)
    l, return_instr = loc(expr), Pass(loc(expr))
    total_size_of_arguments = sum(
        imap(size_arrays_as_pointers, imap(c_type, right_exp(expr))))
    return_size = size(c_type(expr), overrides={VoidType: 0})
    omit_pointer_for_return_value = not return_size

    # if omit_pointer_for_return_value:
    #     # if the function call is a statement or its return type has zero size.
    #     # lets do some minor optimizations, since function calls already quite expensive as it is.
    #     expr.c_type = VoidType(loc(l))  # change the return type of the expression to void.
    #     # since we are omitting the return pointer, we have to update the parameter offsets, since they are calculated
    #     # assuming that a return pointer is added ...
    #     # all sets should be decrease by size(void_pointer) for this expression but this may not be true for other
    #     # function call expressions that may actually use the return value of this as such ... :(
    # we would need to check if the functions return value is ALWAYS ignored if and only if then can we omit
    # the return pointer for know its only applicable for for functions whose return size is zero ...
    # TODO: post-compilation optimization that optimizes functions whose returned values is ALWAYS ignored.
    expression = symbol_table['__ expression __']
    return chain(
        # Allocate space for return value, save frame.
        allocate(return_size, l),
        push_frame(
            # Push arguments in reverse order (right to left) ...
            chain.from_iterable(
                imap(expression, reverse(right_exp(expr)),
                     repeat(symbol_table))),
            location=l,
            total_size_of_arguments=total_size_of_arguments,
            omit_pointer_for_return_value=omit_pointer_for_return_value),
        push(Address(return_instr, l),
             l),  # make callee aware of were to return to.
        call_function(expr, symbol_table),
        (return_instr, ),
        # Pop Frame, first stack pointer then base stack pointer
        pop_frame(location=l,
                  total_size_of_arguments=total_size_of_arguments,
                  omit_pointer_for_return_value=omit_pointer_for_return_value))
Exemplo n.º 12
0
    def body(stmnt, symbol_table, end_switch):
        symbol_table = push(symbol_table)
        stack, statement = imap(symbol_table.__getitem__,
                                ('__ stack __', '__ statement __'))
        symbol_table['__ break __'] = (end_switch, stack.stack_pointer)
        symbol_table['__ switch __'] = True

        allocation_table = [
        ]  # create an allocation table to update stack before jump in case of nested definitions
        switch_body_instrs = []
        cases = {'default': Offset(end_switch, loc(stmnt))}

        for instr in statement(stmnt.statement, symbol_table):
            if isinstance(getattr(instr, 'case', None), CaseStatement):
                start = Pass(loc(instr))
                allocation_table.append(
                    chain(
                        (start, ),
                        update_stack(stmnt.stack.stack_pointer,
                                     instr.case.stack.stack_pointer,
                                     loc(instr)),
                        relative_jump(Offset(instr, loc(instr)), loc(instr)),
                    ))

                cases[error_if_not_type(exp(exp(instr.case)),
                                        (int, long, str))] = Offset(
                                            start, loc(instr))
                del instr.case
            switch_body_instrs.append(instr)

        max_switch_value = 2**(8 *
                               size_arrays_as_pointers(c_type(exp(stmnt)))) - 1
        for instr in jump_table(loc(stmnt), cases, allocation_table,
                                max_switch_value, switch_body_instrs):
            yield instr
        _ = pop(symbol_table)
Exemplo n.º 13
0
 def pop_symbol_table(symbol_table, location=loc(
     dec)):  # pop symbol table once all binaries have being emitted
     yield (pop(symbol_table) or 1) and Pass(location)