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_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 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 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 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 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 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 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 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 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 )
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 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)
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))