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) )
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) )
def compound_statement(stmnt, symbol_table): stack, statement = utils.symbol_table.get_symbols(symbol_table, '__ stack __', '__ statement __') stack_pointer, symbol_table = stack.stack_pointer, utils.symbol_table.push(symbol_table) for instr in chain.from_iterable(imap(statement, chain.from_iterable(stmnt), repeat(symbol_table))): yield instr for instr in allocate(stack.stack_pointer - stack_pointer, loc(stmnt)): # deallocate any definitions that may occur yield instr stack.stack_pointer = (utils.symbol_table.pop(symbol_table) or True) and stack_pointer # reset stack pointer ...
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
def comma_expression(expr, symbol_table): expression = symbol_table['__ expression __'] return chain( chain.from_iterable( 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))
def comma_expression(expr, symbol_table): expression = symbol_table['__ expression __'] return chain( chain.from_iterable( 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) )
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 ) )
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))
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) )
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)))))
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))) ) )
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)))
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)) )
def update_stack(source_stack_pointer, target_stack_pointer, location): return allocate(source_stack_pointer - target_stack_pointer, location)