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), )
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) ))
def relational_operators(expr, symbol_table): max_type = max(imap(c_type, (left_exp(expr), right_exp(expr)))) expression = symbol_table['__ expression __'] if isinstance(max_type, ArrayType): max_type = PointerType(c_type(max_type), loc(max_type)) left_instrs = expression(left_exp(expr), symbol_table) right_instrs = expression(right_exp(expr), symbol_table) return rules(relational_operators)[oper(expr)]( cast(left_instrs, c_type(left_exp(expr)), max_type, loc(expr)), cast(right_instrs, c_type(right_exp(expr)), max_type, loc(expr)), loc(expr), (c_type(expr), c_type(left_exp(expr)), c_type(right_exp(expr))), )
def arithmetic_and_bitwise_operators(expr, symbol_table): expression = symbol_table['__ expression __'] left_instrs = expression(left_exp(expr), symbol_table) right_instrs = expression(right_exp(expr), symbol_table) to_type = c_type(expr) if isinstance(to_type, ArrayType): to_type = PointerType(c_type(to_type), loc(c_type(expr))) return rules(arithmetic_and_bitwise_operators)[oper(expr)]( cast(left_instrs, c_type(left_exp(expr)), to_type, loc(expr)), cast(right_instrs, c_type(right_exp(expr)), to_type, loc(expr)), loc(expr), (to_type, c_type(left_exp(expr)), c_type(right_exp(expr))), )
def non_static_pointer_typed_definition_initialized_by_array_type(stmnt, symbol_table): stack, expression = utils.symbol_table.get_symbols(symbol_table, '__ stack __', '__ expression __') expr = declarations.initialization(stmnt) assert not isinstance(expr, (expressions.Initializer, expressions.CompoundLiteral)) return chain( # evaluate stack expression, which will push values on the stack and initialized pointer with sp cast(expression(expr, symbol_table), c_type(expr), c_type(stmnt), loc(stmnt)), load_stack_pointer(loc(stmnt)) )
def non_static_default_typed_definition(stmnt, symbol_table): return cast( symbol_table['__ expression __'](declarations.initialization(stmnt), symbol_table), c_type(declarations.initialization(stmnt)), c_type(stmnt), loc(stmnt) )
def assign(expr, symbol_table): expression = symbol_table['__ expression __'] return set_instr( chain( cast(expression(right_exp(expr), symbol_table), c_type(right_exp(expr)), c_type(expr), loc(expr)), # remove default Load instruction, emit Set instruction ... all_but_last(expression(left_exp(expr), symbol_table), Loads, loc(expr)), ), size_arrays_as_pointers(c_type(expr)), # get the size exp returns an array make sure its treated as pointer ... loc(expr), )
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)
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)
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)) )