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 logical_operators(expr, symbol_table): expression = symbol_table['__ expression __'] return rules(logical_operators)[oper(expr)]( expression(left_exp(expr), symbol_table), expression(right_exp(expr), symbol_table), loc(expr), tuple(imap(size_arrays_as_pointers, imap(c_type, (expr, left_exp(expr), right_exp(expr))))) )
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 binary_exp(expr): if not all(imap(isinstance, (left_exp(expr), right_exp(expr)), repeat(ConstantExpression))): return expr exp_type = max(imap(c_type, (left_exp(expr), right_exp(expr))))(loc(expr)) l_exp, r_exp, location = exp(left_exp(expr)), exp(right_exp(expr)), loc(expr) # noinspection PyUnresolvedReferences '1 + 2 - 3 * 7 / 4' return binary_exp.rules[oper(expr)]( expr=expr, left_exp=l_exp, right_exp=r_exp, location=location, exp_type=exp_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 binary_exp(expr): if not all( imap(isinstance, (left_exp(expr), right_exp(expr)), repeat(ConstantExpression))): return expr exp_type = max(imap(c_type, (left_exp(expr), right_exp(expr))))(loc(expr)) l_exp, r_exp, location = exp(left_exp(expr)), exp( right_exp(expr)), loc(expr) # noinspection PyUnresolvedReferences '1 + 2 - 3 * 7 / 4' return binary_exp.rules[oper(expr)](expr=expr, left_exp=l_exp, right_exp=r_exp, location=location, exp_type=exp_type)
def element_section_pointer(expr, symbol_table): return element_instrs( c_type(c_type(left_exp(expr))), right_exp(expr), loc(expr), load_instrs=symbol_table['__ expression __'](left_exp(expr), symbol_table) )
def subtraction_expression(_exp): if is_binary_pointer_expression(_exp): # if subtracting two pointers, then the return type is a LongType return BinaryExpression( left_exp(_exp), oper(_exp), right_exp(_exp), LongType(LongType(location=loc(_exp)), unsigned=True, location=loc(_exp)), location=loc(_exp) ) return _exp
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 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 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), )
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 subtraction_expression(_exp): if is_binary_pointer_expression( _exp ): # if subtracting two pointers, then the return type is a LongType return BinaryExpression(left_exp(_exp), oper(_exp), right_exp(_exp), LongType(LongType(location=loc(_exp)), unsigned=True, location=loc(_exp)), location=loc(_exp)) return _exp
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 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, ), )
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,), )
def is_binary_pointer_expression(_exp): return all( imap( isinstance, imap(c_type, (left_exp(_exp, None), right_exp(_exp, None)), repeat(None)), repeat(PointerType)))
def is_binary_pointer_expression(_exp): return all(imap( isinstance, imap(c_type, (left_exp(_exp, None), right_exp(_exp, None)), repeat(None)), repeat(PointerType) ))
def integral_type(tokens, symbol_table, l_exp): exp = get_binary_expression(tokens, symbol_table, l_exp, assignment_expression, IntegralType) return CompoundAssignmentExpression(left_exp(exp), oper(exp), right_exp(exp), c_type(l_exp)(loc(exp)), loc(exp))
def element_section_pointer(expr, symbol_table): return element_instrs(c_type(c_type(left_exp(expr))), right_exp(expr), loc(expr), load_instrs=symbol_table['__ expression __']( left_exp(expr), symbol_table))
def integral_type(tokens, symbol_table, l_exp): exp = get_binary_expression(tokens, symbol_table, l_exp, assignment_expression, IntegralType) return CompoundAssignmentExpression(left_exp(exp), oper(exp), right_exp(exp), c_type(l_exp)(loc(exp)), loc(exp))