Example #1
0
def argument_address(func_type, cpu, mem):
    index = size(void_pointer_type) + (size(void_pointer_type) if size(
        c_type(c_type(func_type)), overrides={VoidType: 0}) else 0)

    for ctype in imap(c_type, func_type):
        yield cpu.base_pointer + index
        index += size(ctype)
Example #2
0
def compound_assignment(expr, symbol_table):
    assert all(imap(isinstance, imap(c_type, (left_exp(expr), right_exp(expr))), repeat(NumericType)))
    assert not isinstance(c_type(left_exp(expr)), ArrayType)

    if isinstance(left_exp(expr), IdentifierExpression) and \
       base_c_type(c_type(left_exp(expr))) == base_c_type(c_type(right_exp(expr))) and \
       size(c_type(left_exp(expr))) == size(c_type(right_exp(expr))):
        # check that both operands are of the same kind (integral vs numeric) and have the same size ...
        return simple_numeric_assignment_no_casting(expr, symbol_table, rules(compound_assignment)[oper(expr)])

    max_type = max(imap(c_type, (left_exp(expr), right_exp(expr))))  # cast to largest type.
    expression = symbol_table['__ expression __']
    left_instrs = cast(  # cast to max_type
        patch_comp_left_instrs(expression(left_exp(expr), symbol_table),  loc(expr), size(c_type(left_exp(expr)))),
        c_type(left_exp(expr)),
        max_type,
        loc(expr),
    )
    right_instrs = cast(expression(right_exp(expr), symbol_table), c_type(right_exp(expr)), max_type, loc(expr))
    return patch_comp_assignment(
        cast(  # Cast the result back, swap the value and the destination address call set to save.
            rules(compound_assignment)[oper(expr)](
                left_instrs,
                right_instrs,
                loc(expr),
                (max_type, c_type(left_exp(expr)), c_type(right_exp(expr)))
            ),
            max_type,
            c_type(expr),
            loc(expr)
        ),
        c_type(expr),
        loc(expr),
    )
Example #3
0
def argument_address(func_type, cpu, mem):
    index = size(void_pointer_type) + (
        size(void_pointer_type) if size(c_type(c_type(func_type)), overrides={VoidType: 0}) else 0
    )

    for ctype in imap(c_type, func_type):
        yield cpu.base_pointer + index
        index += size(ctype)
Example #4
0
def element_selection(expr, symbol_table):
    instrs = symbol_table['__ expression __'](left_exp(expr), symbol_table)
    # if we are loading the structure then just remove the Load instr, calculate the elements offset and Load that elem
    if is_load(instrs):
        return element_instrs(c_type(left_exp(expr)),
                              right_exp(expr),
                              loc(expr),
                              load_instrs=all_but_last(instrs, Loads,
                                                       loc(expr)))

    struct_size, member_size = size(c_type(
        left_exp(expr))), size_arrays_as_pointers(c_type(expr))
    addr_instrs = add(  # calculate the loaded structured members address
        load_stack_pointer(loc(expr)),
        push(struct_member_offset(c_type(left_exp(expr)), right_exp(expr)),
             loc(expr)), loc(expr))
    return chain(  # copy the element then move it to the base of the structure and deallocate everything else
        set_instr(
            chain(  # load the value in question if its not an array (which is just an address ...)
                (addr_instrs if isinstance(c_type(expr), ArrayType) else load(
                    addr_instrs, member_size, loc(expr))),
                add(load_stack_pointer(loc(expr)),
                    push((struct_size + member_size), loc(expr)), loc(expr)),
            ),
            member_size,
            loc(expr)),
        allocate(-(struct_size - member_size), loc(
            expr))  # deallocate structure and copied member (set leaves value)
    )
Example #5
0
def element_selection(expr, symbol_table):
    instrs = symbol_table['__ expression __'](left_exp(expr), symbol_table)
    # if we are loading the structure then just remove the Load instr, calculate the elements offset and Load that elem
    if is_load(instrs):
        return element_instrs(
            c_type(left_exp(expr)), right_exp(expr), loc(expr), load_instrs=all_but_last(instrs, Loads, loc(expr))
        )

    struct_size, member_size = size(c_type(left_exp(expr))), size_arrays_as_pointers(c_type(expr))
    addr_instrs = add(  # calculate the loaded structured members address
        load_stack_pointer(loc(expr)),
        push(struct_member_offset(c_type(left_exp(expr)), right_exp(expr)), loc(expr)),
        loc(expr)
    )
    return chain(  # copy the element then move it to the base of the structure and deallocate everything else
        set_instr(
            chain(  # load the value in question if its not an array (which is just an address ...)
                (addr_instrs if isinstance(c_type(expr), ArrayType) else load(addr_instrs, member_size, loc(expr))),
                add(load_stack_pointer(loc(expr)), push((struct_size + member_size), loc(expr)), loc(expr)),
            ),
            member_size,
            loc(expr)
        ),
        allocate(-(struct_size - member_size), loc(expr))  # deallocate structure and copied member (set leaves value)
    )
Example #6
0
def definition(dec, symbol_table):  # Global definition.
    assert not isinstance(c_type(dec), FunctionType)
    symbol_table[name(dec)] = bind_load_instructions(dec)
    symbol_table[name(dec)].symbol = Data(  # Add reference of symbol to definition to keep track of references
        # static binaries, (packed binaries since machine may require alignment ...)
        name(dec), static_def_binaries(dec), size(c_type(dec)), dec.storage_class, loc(dec),
    )
    return symbol_table[name(dec)].symbol
Example #7
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))
Example #8
0
def statement(stmnt, symbol_table):
    is_expression = isinstance(stmnt, expressions.Expression)

    # Set entry point to False if its an expression or use statement function if present otherwise None.
    instrs = rules(statement)[type(stmnt)](stmnt, symbol_table)
    # Almost all Expression statements leave a value on the stack, so we must remove it.
    if stmnt and is_expression:
        instrs = chain(instrs, allocate(-size(c_type(stmnt), overrides={VoidType: 0}), loc(stmnt)))
    return instrs
Example #9
0
def executable(symbols,
               symbol_table=None,
               entry_point=default_entry_point,
               libraries=(),
               linker=static):
    location = '__SOP__'  # Start of Program
    symbol_table = SymbolTable() if symbol_table is None else symbol_table
    __end__ = Word(0, location)
    libs = tuple(imap(Library, libraries))

    symbols = chain(
        symbols,  # add heap pointer(s) ...
        (
            object_file.Data('__base_heap_ptr__',
                             (Address(__end__, location), ),
                             size(void_pointer_type), None, location),
            object_file.Data('__heap_ptr__', (Address(__end__, location), ),
                             size(void_pointer_type), None, location),
        ))

    def declarations(symbol_table):
        # iterate over all symbols withing symbol_table that do not have binaries (they should be declarations)
        for v in chain.from_iterable(
                imap(
                    set_binaries,
                    ifilterfalse(lambda s: s.binaries,
                                 symbol_table.itervalues()))):
            yield v  # emit default binaries for declarations ...

    # inject declaration into temp symbol_table to generate entry point function call instructions ...
    st = {'__ expression __': expression}
    _ = declaration(entry_point, st)
    instr_seq = chain(
        statement(  # call entry point ...
            FunctionCallExpression(
                IdentifierExpression(name(entry_point),
                                     c_type(entry_point), location), (),
                c_type(c_type(entry_point)), location), st),
        halt(location),  # Halt machine on return ...
        chain.from_iterable(
            starmap(binaries, izip(symbols, repeat(symbol_table)))),
    )  # link all foreign symbols and emit binaries for declarations ...
    return chain(linker(instr_seq, symbol_table, libs),
                 declarations(symbol_table), (__end__, ))
Example #10
0
def __return__(value,
               cpu,
               mem,
               os,
               func_signature=FunctionType(IntegerType(SysCallLocation), (),
                                           SysCallLocation)):
    cpu.instr_pointer = mem[cpu.base_pointer +
                            word_size]  # get return instruction ...
    assert size(c_type(c_type(func_signature))) == word_size
    mem[cpu.base_pointer + 2 * word_size] = value
Example #11
0
def inc_dec(expr, symbol_table):
    assert not isinstance(c_type(expr), ArrayType) and isinstance(
        c_type(expr), IntegralType)
    value = rules(inc_dec)[type(expr)]
    if isinstance(c_type(expr), PointerType):
        value *= size_extended(c_type(c_type(expr)))

    return get_postfix_update(size(c_type(expr)))(all_but_last(
        symbol_table['__ expression __'](exp(expr), symbol_table), Loads,
        loc(expr)), value, loc(expr))
Example #12
0
def subtract(l_instrs, r_instrs, location, operand_types):
    exp_c_type, left_exp_c_type, right_exp_c_type = operand_types
    if all(imap(isinstance, operand_types[1:], repeat(PointerType))):  # subtracting two pointers ...
        return divide(
            subtract.rules[base_c_type(void_pointer_type)][size(void_pointer_type)](l_instrs, r_instrs, location),
            push(size_extended(c_type(c_type(left_exp_c_type))), location),
            location,
            operand_types
        )

    return pointer_arithmetic(l_instrs, r_instrs, location, operand_types)
Example #13
0
def inc_dec(expr, symbol_table):
    assert not isinstance(c_type(expr), ArrayType) and isinstance(c_type(expr), IntegralType)
    value = rules(inc_dec)[type(expr)]
    if isinstance(c_type(expr), PointerType):
        value *= size_extended(c_type(c_type(expr)))

    return get_postfix_update(size(c_type(expr)))(
        all_but_last(symbol_table['__ expression __'](exp(expr), symbol_table), Loads, loc(expr)),
        value,
        loc(expr)
    )
Example #14
0
def pop_frame(location=LocationNotSet,
              total_size_of_arguments=0,
              omit_pointer_for_return_value=False):
    # return pop_frame_instr(location)  # method 1 requires special instruction that has to manage blocks

    # method 2 (5 instructions LoadBaseStackPtr, Push, Add, SetStackPtr, SetBaseStackPtr)
    # method 2 seems to be faster even though it has an extra instruction compare to method 3,
    # not really sure why ... probably because the optimizer is removing some of them

    return set_base_stack_pointer(
        set_stack_pointer(
            add(
                # remove parameters and ret addr ...
                load_base_stack_pointer(location),
                push(  # remove parameters, ret address pointer, and ptr for ret value if it was emitted ...
                    sum((total_size_of_arguments, size(void_pointer_type),
                         (not omit_pointer_for_return_value) *
                         size(void_pointer_type))), location),
                location),
            location),
        location)
Example #15
0
def executable(symbols, symbol_table=None, entry_point=default_entry_point, libraries=(), linker=static):
    location = '__SOP__'  # Start of Program
    symbol_table = SymbolTable() if symbol_table is None else symbol_table
    __end__ = Word(0, location)
    libs = tuple(imap(Library, libraries))

    symbols = chain(
        symbols,  # add heap pointer(s) ...
        (
            object_file.Data(
                '__base_heap_ptr__', (Address(__end__, location),), size(void_pointer_type), None, location
            ),
            object_file.Data(
                '__heap_ptr__', (Address(__end__, location),), size(void_pointer_type), None, location
            ),
        )
    )

    def declarations(symbol_table):
        # iterate over all symbols withing symbol_table that do not have binaries (they should be declarations)
        for v in chain.from_iterable(imap(set_binaries, ifilterfalse(lambda s: s.binaries, symbol_table.itervalues()))):
            yield v   # emit default binaries for declarations ...

    # inject declaration into temp symbol_table to generate entry point function call instructions ...
    st = {'__ expression __': expression}
    _ = declaration(entry_point, st)
    instr_seq = chain(
        statement(  # call entry point ...
            FunctionCallExpression(
                IdentifierExpression(name(entry_point), c_type(entry_point), location),
                (),
                c_type(c_type(entry_point)),
                location
            ),
            st
        ),
        halt(location),  # Halt machine on return ...
        chain.from_iterable(starmap(binaries, izip(symbols, repeat(symbol_table)))),
    )            # link all foreign symbols and emit binaries for declarations ...
    return chain(linker(instr_seq, symbol_table, libs), declarations(symbol_table), (__end__,))
Example #16
0
def return_statement(stmnt, symbol_table):
    # TODO: check if we can omit the setting the return value if if it is immediately removed ...
    return_type = c_type(c_type(symbol_table['__ CURRENT FUNCTION __']))
    assert not isinstance(c_type(return_type), ArrayType)
    if isinstance(return_type, VoidType) or not exp(stmnt):
     # just return if void type or expr is empty or size of expression is zero.
        return return_instrs(loc(stmnt))

    return chain(
        cast(symbol_table['__ expression __'](exp(stmnt), symbol_table), c_type(exp(stmnt)), return_type, loc(stmnt)),
        set_instr(
            load(
                add(load_base_stack_pointer(loc(stmnt)), push(size(void_pointer_type), loc(stmnt)), loc(stmnt)),
                size(void_pointer_type),
                loc(stmnt)
            ),
            size(return_type),
            loc(stmnt)
        ),
        # TODO: see if we can remove the following instr, since pop_frame will reset the base and stack pointers
        # allocate(-size(return_type), loc(stmnt)),  # Set leaves the value on the stack
        return_instrs(loc(stmnt))
    )
Example #17
0
def push_frame(
        arguments_instrs=(),
        location=LocationNotSet,
        total_size_of_arguments=0,
        omit_pointer_for_return_value=False,
):
    return chain(
        load_base_stack_pointer(location),  # save previous base stack pointer ...
        arguments_instrs,
        # Pointer to where to store return values, if applicable (ie non-zero return size)...
        () if omit_pointer_for_return_value else
        # calculate pointer for ret value, excluding base pointer ...
        add(load_stack_pointer(location), push((total_size_of_arguments + size(void_pointer_type)), location), location)
    )
Example #18
0
def definition(dec, symbol_table):  # Global definition.
    assert not isinstance(c_type(dec), FunctionType)
    symbol_table[name(dec)] = bind_load_instructions(dec)
    symbol_table[name(
        dec
    )].symbol = Data(  # Add reference of symbol to definition to keep track of references
        # static binaries, (packed binaries since machine may require alignment ...)
        name(dec),
        static_def_binaries(dec),
        size(c_type(dec)),
        dec.storage_class,
        loc(dec),
    )
    return symbol_table[name(dec)].symbol
Example #19
0
    def test_printf_union(self):
        code = """
            #include <stdio.h>

            union {unsigned long long a; double b; char c[20]; int d[0];} foo = {.a=10, .b=10.5};

            int main()
            {
                printf("%llu %f %lu", foo.a, foo.b, sizeof(foo));
                return foo.b == 10.5;
            }
        """
        self.evaluate(code)
        self.assertEqual("4622100592565682176 10.5 {s}".format(s=size(ArrayType(CharType(), 20))), self.stdout.read())
Example #20
0
def pop_frame(location=LocationNotSet, total_size_of_arguments=0, omit_pointer_for_return_value=False):
    # return pop_frame_instr(location)  # method 1 requires special instruction that has to manage blocks

    # method 2 (5 instructions LoadBaseStackPtr, Push, Add, SetStackPtr, SetBaseStackPtr)
    # method 2 seems to be faster even though it has an extra instruction compare to method 3,
    # not really sure why ... probably because the optimizer is removing some of them

    return set_base_stack_pointer(
        set_stack_pointer(
            add(
                # remove parameters and ret addr ...
                load_base_stack_pointer(location),
                push(    # remove parameters, ret address pointer, and ptr for ret value if it was emitted ...
                    sum((
                        total_size_of_arguments, size(void_pointer_type),
                        (not omit_pointer_for_return_value) * size(void_pointer_type))),
                    location
                ),
                location
            ),
            location
        ),
        location
    )
Example #21
0
def call_function(function_call_expr, symbol_table):
    l, expr = loc(function_call_expr), left_exp(function_call_expr)
    return chain(  # if expression is a simple identifier of function type, no need for AbsoluteJump, use RelativeJump
        set_base_stack_pointer(load_stack_pointer(l), l),
        relative_jump(Offset(symbol_table[name(expr)].get_address_obj(l).obj, l), l),
    ) if isinstance(expr, IdentifierExpression) and isinstance(c_type(expr), FunctionType) else absolute_jump(
        chain(
            symbol_table['__ expression __'](expr, symbol_table),   # load callee address
            # calculate new base stack pointer excluding the callees address ...
            # give the callee a new frame... if we where to reset the base stack ptr before evaluating the left_expr
            # we run the risk of failing to properly load function address if it was store as a local function pointer
            set_base_stack_pointer(add(load_stack_pointer(l), push(size(void_pointer_type), l), l), l)
        ),
        l
    )
Example #22
0
    def test_printf_union(self):
        code = """
            #include <stdio.h>

            union {unsigned long long a; double b; char c[20]; int d[0];} foo = {.a=10, .b=10.5};

            int main()
            {
                printf("%llu %f %lu", foo.a, foo.b, sizeof(foo));
                return foo.b == 10.5;
            }
        """
        self.evaluate(code)
        self.assertEqual(
            "4622100592565682176 10.5 {s}".format(
                s=size(ArrayType(CharType(), 20))), self.stdout.read())
Example #23
0
def array_subscript(expr, symbol_table):
    assert isinstance(c_type(left_exp(expr)), PointerType) and isinstance(
        c_type(right_exp(expr)), IntegralType)
    expression = symbol_table['__ expression __']
    l = loc(expr)
    addr_instrs = add(
        expression(left_exp(expr), symbol_table),
        multiply(
            cast(  # convert right expression to address type in order to properly multiply ...
                expression(right_exp(expr), symbol_table),
                c_type(right_exp(expr)), void_pointer_type, l),
            push(size(c_type(expr)), l),
            l),
        l,
    )  # Load value unless the return type is also an ArrayTyp
    return addr_instrs if isinstance(c_type(expr), ArrayType) \
        else load(addr_instrs, size_arrays_as_pointers(c_type(expr)), l)
Example #24
0
def push_frame(
    arguments_instrs=(),
    location=LocationNotSet,
    total_size_of_arguments=0,
    omit_pointer_for_return_value=False,
):
    return chain(
        load_base_stack_pointer(
            location),  # save previous base stack pointer ...
        arguments_instrs,
        # Pointer to where to store return values, if applicable (ie non-zero return size)...
        () if omit_pointer_for_return_value else
        # calculate pointer for ret value, excluding base pointer ...
        add(
            load_stack_pointer(location),
            push((total_size_of_arguments +
                  size(void_pointer_type)), location), location))
Example #25
0
def call_function(function_call_expr, symbol_table):
    l, expr = loc(function_call_expr), left_exp(function_call_expr)
    return chain(  # if expression is a simple identifier of function type, no need for AbsoluteJump, use RelativeJump
        set_base_stack_pointer(load_stack_pointer(l), l),
        relative_jump(
            Offset(symbol_table[name(expr)].get_address_obj(l).obj, l), l),
    ) if isinstance(expr, IdentifierExpression) and isinstance(
        c_type(expr), FunctionType
    ) else absolute_jump(
        chain(
            symbol_table['__ expression __'](
                expr, symbol_table),  # load callee address
            # calculate new base stack pointer excluding the callees address ...
            # give the callee a new frame... if we where to reset the base stack ptr before evaluating the left_expr
            # we run the risk of failing to properly load function address if it was store as a local function pointer
            set_base_stack_pointer(
                add(load_stack_pointer(l), push(size(void_pointer_type), l),
                    l), l)),
        l)
Example #26
0
def simple_numeric_assignment_no_casting(expr, symbol_table, operation):
    expression = symbol_table['__ expression __']
    # used when the left operand is an identifier so we can re-emit binaries instead of using expensive Dup instr
    return set_instr(
        chain(
            operation(
                expression(left_exp(expr), symbol_table),
                expression(right_exp(expr), symbol_table),
                loc(expr),
                tuple(imap(c_type, (expr, left_exp(expr), right_exp(expr))))
            ),
            expression(
                AddressOfExpression(left_exp(expr), PointerType(c_type(right_exp(expr)), loc(expr)), loc(expr)),
                symbol_table,
            )
        ),
        size(c_type(expr)),
        loc(expr),
    )
Example #27
0
def array_subscript(expr, symbol_table):
    assert isinstance(c_type(left_exp(expr)), PointerType) and isinstance(c_type(right_exp(expr)), IntegralType)
    expression = symbol_table['__ expression __']
    l = loc(expr)
    addr_instrs = add(
        expression(left_exp(expr), symbol_table),
        multiply(
            cast(  # convert right expression to address type in order to properly multiply ...
                expression(right_exp(expr), symbol_table),
                c_type(right_exp(expr)),
                void_pointer_type,
                l
            ),
            push(size(c_type(expr)), l),
            l
        ),
        l,
    )   # Load value unless the return type is also an ArrayTyp
    return addr_instrs if isinstance(c_type(expr), ArrayType) \
        else load(addr_instrs, size_arrays_as_pointers(c_type(expr)), l)
Example #28
0
def __exit__(
        cpu,
        mem,
        kernel,
        func_signature=FunctionType(
            VoidType(SysCallLocation),
            (AbstractDeclarator(IntegerType(SysCallLocation), SysCallLocation),),
            SysCallLocation
        )):

    # void exit(int return_value);
    value, = args(func_signature, cpu, mem)
    # Flush and close all opened files except stdio
    for file_id in ifilter(lambda file_id: file_id not in dict(std_files), kernel.opened_files):
        kernel.opened_files[file_id].flush()
        kernel.opened_files[file_id].close()

    mem[-size(IntegerType())] = value  # Set the return status on top of the stack
    cpu.base_pointer = cpu.stack_pointer = push_integral.core_type(-word_size)  # reset stack/base pointers ...

    mem[cpu.instr_pointer + word_size] = Halt(SysCallLocation)  # Halt machine ...
Example #29
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
        )
    )
Example #30
0
def __exit__(
    cpu,
    mem,
    kernel,
    func_signature=FunctionType(VoidType(SysCallLocation), (AbstractDeclarator(
        IntegerType(SysCallLocation), SysCallLocation), ), SysCallLocation)):

    # void exit(int return_value);
    value, = args(func_signature, cpu, mem)
    # Flush and close all opened files except stdio
    for file_id in ifilter(lambda file_id: file_id not in dict(std_files),
                           kernel.opened_files):
        kernel.opened_files[file_id].flush()
        kernel.opened_files[file_id].close()

    mem[-size(IntegerType()
              )] = value  # Set the return status on top of the stack
    cpu.base_pointer = cpu.stack_pointer = push_integral.core_type(
        -word_size)  # reset stack/base pointers ...

    mem[cpu.instr_pointer + word_size] = Halt(
        SysCallLocation)  # Halt machine ...
Example #31
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))
Example #32
0
def patch_comp_left_instrs(instrs, location, value_size):
    return load(                                     # duplicate address ...
        chain(all_but_last(instrs, Loads, location), dup(size(void_pointer_type), location)),
        value_size,
        location
    )
Example #33
0
def const_float_expr(expr):
    return get_push(size(c_type(expr)))(DoubleHalf(exp(expr), loc(expr)),
                                        loc(expr))
Example #34
0
def patch_comp_assignment(instrs, expr_type, location):
    # At this point the stack contains the Address followed by the calculated value ...
    # we need to swap them and call set, but we mut be careful that both have the same size before calling swap
    # or we could corrupt the value ...
    if size(expr_type) == size(void_pointer_type):  # result type and pointer type (address) equal no alignment required
        return chain(instrs, set_instr(swap(size(void_pointer_type), location), size(void_pointer_type), location))

    if size(expr_type) < size(void_pointer_type):  # size of result type is less than address we need to align
        if isinstance(expr_type, DoubleType):  # since we are using cast to the alignment we need too interpret
            assert size(double_type) == size(long_type)   # result type as integral type for casting may change value
            expr_type = LongType(location, unsigned=True)
        elif isinstance(expr_type, FloatType):
            assert size(float_type) == size(integer_type)
            expr_type = IntegerType(location, unsigned=True)

        return cast(  # convert the value back to its original size removing any alignment added bytes after set ...
            set_instr(  # set values assuming little endian architecture  TODO: check on that assertion!
                chain(cast(instrs, expr_type, void_pointer_type, location), swap(size(void_pointer_type), location)),
                size(expr_type),  # if sizes differ, cast value to pointer type extending bytes, and swap
                location
            ),
            void_pointer_type,
            expr_type,
            location
        )
    else:
        raise ValueError('{l} unable to patch compound assignment value size {s} exceeds address size {a}'.format(
            l=location, s=size(expr_type), a=size(void_pointer_type)
        ))
Example #35
0
def args(func_type, cpu, mem):
    for address, arg in izip(argument_address(func_type, cpu, mem), func_type):
        yield mem[address] \
            if size(c_type(arg)) == word_size \
            else (mem[offset] for offset in xrange(address, address + size(c_type(arg)), word_size))
Example #36
0
def const_double_expr(expr):
    return get_push(size(c_type(expr)))(Double(exp(expr), loc(expr)), loc(expr))
Example #37
0
def stack_allocation(stack, obj):
    obj_type = obj if isinstance(obj, CType) else c_type(obj)
    stack.allocate(size(obj_type))
    return bind_instructions(obj, stack.stack_pointer) if isinstance(
        obj, (Declaration, Declarator)) else obj
Example #38
0
def static_integral_ctype(ctype, value=0, location=LocationNotSet):
    yield machine_integral_types[size(ctype)](value, location or loc(ctype))
Example #39
0
def static_real_ctype(ctype, value=0.0, location=LocationNotSet):
    yield machine_floating_types[size(ctype)](value, location or loc(ctype))
Example #40
0
def static_union_exp(expr):
    return chain(
        imap(binaries, exp(expr)[0]), imap(Byte, repeat(0, size(c_type(expr)) - size(c_type(exp(expr)[0]))))
    )
Example #41
0
            chain(
                expression(e, symbol_table),
                allocate(-size_arrays_as_pointers(c_type(e), overrides={VoidType: 0}), loc(e))
            ) for e in exp(expr)[:-1]
        ),
        expression(exp(expr)[-1], symbol_table)
    )


# Entry point to all expression or expression statements
def expression(expr, symbol_table):
    return rules(expression)[type(expr)](expr, symbol_table)
expression_funcs = unary_expression, postfix_expression, ternary_expression, initializer_expression
set_rules(
    expression,
    chain(
        (
            (EmptyExpression, lambda expr, *_: allocate(size(c_type(expr), overrides={VoidType: 0}), loc(expr))),
            (ConstantExpression, constant_expression),
            (CastExpression, cast_expression),
            (IdentifierExpression, identifier_expression),
            (CommaExpression, comma_expression),

            (BinaryExpression, binary_expression),
            (AssignmentExpression, binary_expression),
            (CompoundAssignmentExpression, binary_expression),
        ),
        chain.from_iterable(imap(izip, imap(rules, expression_funcs), imap(repeat, expression_funcs)))
    )
)
Example #42
0
            chain(
                expression(e, symbol_table),
                allocate(
                    -size_arrays_as_pointers(c_type(e),
                                             overrides={VoidType: 0}), loc(e)))
            for e in exp(expr)[:-1]), expression(exp(expr)[-1], symbol_table))


# Entry point to all expression or expression statements
def expression(expr, symbol_table):
    return rules(expression)[type(expr)](expr, symbol_table)


expression_funcs = unary_expression, postfix_expression, ternary_expression, initializer_expression
set_rules(
    expression,
    chain((
        (EmptyExpression, lambda expr, *_: allocate(
            size(c_type(expr), overrides={VoidType: 0}), loc(expr))),
        (ConstantExpression, constant_expression),
        (CastExpression, cast_expression),
        (IdentifierExpression, identifier_expression),
        (CommaExpression, comma_expression),
        (BinaryExpression, binary_expression),
        (AssignmentExpression, binary_expression),
        (CompoundAssignmentExpression, binary_expression),
    ),
          chain.from_iterable(
              imap(izip, imap(rules, expression_funcs),
                   imap(repeat, expression_funcs)))))
Example #43
0
def union_initializer(expr, symbol_table):
    return chain(
        allocate(size(c_type(expr)) - size(c_type(expr[0])), loc(expr)), numeric_initializer(expr, symbol_table)
    )
Example #44
0
def const_integral_expr(expr):
    return get_push(size(c_type(expr)))(exp(expr), loc(expr))
Example #45
0
def size_of(expr, symbol_table):
    ctype = exp(expr) if isinstance(exp(expr), CType) else c_type(exp(expr))
    return symbol_table['__ expression __'](ConstantExpression(size(ctype), c_type(expr), loc(expr)), symbol_table)
Example #46
0
def const_union_expr(expr):
    assert len(exp(expr)) <= 1
    return chain(  # allocate rest ...
        allocate(
            size(c_type(expr)) - sum(imap(size, imap(c_type, exp(expr)))),
            loc(expr)), const_struct_expr(exp(expr)))
Example #47
0
def stack_de_allocation(stack, obj):
    obj_type = obj if isinstance(obj, CType) else c_type(obj)
    stack.de_allocate(size(obj))
    return unbind_instructions(stack, obj) if isinstance(
        obj, (Declaration, Declarator)) else obj
Example #48
0
def declaration(dec, symbol_table):
    symbol_table[name(dec)] = bind_load_instructions(dec)
    symbol_table[name(dec)].symbol = Code(name(dec), (), None, dec.storage_class, loc(dec)) \
        if isinstance(c_type(dec), FunctionType) \
        else Data(name(dec), (), size(c_type(dec)), dec.storage_class, loc(dec))
    return symbol_table[name(dec)].symbol
Example #49
0
def const_union_expr(expr):
    assert len(exp(expr)) <= 1
    return chain(                   # allocate rest ...
        allocate(size(c_type(expr)) - sum(imap(size, imap(c_type, exp(expr)))), loc(expr)),
        const_struct_expr(exp(expr))
    )
Example #50
0
def const_double_expr(expr):
    return get_push(size(c_type(expr)))(Double(exp(expr), loc(expr)),
                                        loc(expr))
Example #51
0
def args(func_type, cpu, mem):
    for address, arg in izip(argument_address(func_type, cpu, mem), func_type):
        yield mem[address] \
            if size(c_type(arg)) == word_size \
            else (mem[offset] for offset in xrange(address, address + size(c_type(arg)), word_size))
Example #52
0
def __return__(value, cpu, mem, os, func_signature=FunctionType(IntegerType(SysCallLocation), (), SysCallLocation)):
    cpu.instr_pointer = mem[cpu.base_pointer + word_size]  # get return instruction ...
    assert size(c_type(c_type(func_signature))) == word_size
    mem[cpu.base_pointer + 2 * word_size] = value