def _arith(self, left, right, il_code): """Return the result of this operation on given arithmetic operands. Promotions and conversions are done by caller, so the implementation of this function need not convert operands. A default implementation is provided, but this can be overriden by derived classes. left - ILValue for left operand right - ILValue for right operand """ out = ILValue(left.ctype) il_code.add(self.default_il_cmd(out, left, right)) return out
def make_il(self, il_code, symbol_table, c): """Make code for a literal number. This function does not actually make any code in the IL, it just returns a LiteralILValue that can be used in IL code by the caller. """ v = int(str(self.number)) if ctypes.int_min <= v <= ctypes.int_max: il_value = ILValue(ctypes.integer) elif ctypes.long_min <= v <= ctypes.long_max: il_value = ILValue(ctypes.longint) else: err = "integer literal too large to be represented by any " \ "integer type" raise CompilerError(err, self.number.r) il_code.register_literal_var(il_value, v) # Literal integer 0 is a null pointer constant if v == 0: il_value.null_ptr_const = True return il_value
def set_type(il_value, ctype, il_code, output=None): """If necessary, emit code to cast given il_value to the given ctype. This function does no type checking and will never produce a warning or error. """ if not output and il_value.ctype.compatible(ctype): return il_value elif output == il_value: return il_value else: if not output: output = ILValue(ctype) il_code.add(value_cmds.Set(output, il_value)) return output
def make_il(self, il_code, symbol_table, c): """Make code for this node.""" # This is of function pointer type, so func.arg is the function type. func = self.func.make_il(il_code, symbol_table, c) if not func.ctype.is_pointer() or not func.ctype.arg.is_function(): descrip = "called object is not a function pointer" raise CompilerError(descrip, self.func.r) if not func.ctype.arg.args: final_args = self._get_args_without_prototype( il_code, symbol_table, c) else: final_args = self._get_args_with_prototype( func.ctype.arg, il_code, symbol_table, c) ret = ILValue(func.ctype.arg.ret) il_code.add(control_cmds.Call(func, final_args, ret)) return ret
def make_il(self, il_code, symbol_table, c): """Make code for this node.""" expr = self.expr.make_il(il_code, symbol_table, c) if not self._check_type(expr): err = f"{self.descrip} requires {self.opnd_descrip} type operand" raise CompilerError(err, self.expr.r) # perform integer promotion if expr.ctype.size < 4: expr = set_type(expr, ctypes.integer, il_code) if self.cmd: out = ILValue(expr.ctype) # perform constant folding if expr.literal: val = self._arith_const(expr.literal.val, expr.ctype) val = shift_into_range(val, expr.ctype) il_code.register_literal_var(out, val) else: il_code.add(self.cmd(out, expr)) return out return expr
def _nonarith(self, left, right, il_code): """Make addition code if either operand is non-arithmetic type.""" # One operand should be pointer to complete object type, and the # other should be any integer type. if left.ctype.is_pointer() and right.ctype.is_integral(): arith, pointer = right, left elif right.ctype.is_pointer() and left.ctype.is_integral(): arith, pointer = left, right else: err = "invalid operand types for addition" raise CompilerError(err, self.op.r) if not pointer.ctype.arg.is_complete(): err = "invalid arithmetic on pointer to incomplete type" raise CompilerError(err, self.op.r) # Multiply by size of objects out = ILValue(pointer.ctype) shift = get_size(pointer.ctype.arg, arith, il_code) il_code.add(math_cmds.Add(out, pointer, shift)) return out
def do_body(self, il_code, symbol_table, c): """Create code for function body. Caller must check that this function has a body. """ is_main = self.identifier.content == "main" for param in self.param_names: if not param: err = "function definition missing parameter name" raise CompilerError(err, self.range) if is_main: self.check_main_type() c = c.set_return(self.ctype.ret) il_code.start_func(self.identifier.content) symbol_table.new_scope() num_params = len(self.ctype.args) iter = zip(self.ctype.args, self.param_names, range(num_params)) for ctype, param, i in iter: arg = symbol_table.add_variable( param, ctype, symbol_table.DEFINED, None, symbol_table.AUTOMATIC) il_code.add(value_cmds.LoadArg(arg, i)) self.body.make_il(il_code, symbol_table, c, no_scope=True) if not il_code.always_returns() and is_main: zero = ILValue(ctypes.integer) il_code.register_literal_var(zero, 0) il_code.add(control_cmds.Return(zero)) elif not il_code.always_returns(): il_code.add(control_cmds.Return(None)) symbol_table.end_scope()
def _nonarith(self, left, right, il_code): """Check equality of non-arithmetic expressions.""" # If either operand is a null pointer constant, cast it to the # other's pointer type. if (left.ctype.is_pointer() and getattr(right.literal, "val", None) == 0): right = set_type(right, left.ctype, il_code) elif (right.ctype.is_pointer() and getattr(left.literal, "val", None) == 0): left = set_type(left, right.ctype, il_code) # If both operands are not pointer types, quit now if not left.ctype.is_pointer() or not right.ctype.is_pointer(): with report_err(): err = "comparison between incomparable types" raise CompilerError(err, self.op.r) # If one side is pointer to void, cast the other to same. elif left.ctype.arg.is_void(): check_cast(right, left.ctype, self.op.r) right = set_type(right, left.ctype, il_code) elif right.ctype.arg.is_void(): check_cast(left, right.ctype, self.op.r) left = set_type(left, right.ctype, il_code) # If both types are still incompatible, warn! elif not left.ctype.compatible(right.ctype): with report_err(): err = "comparison between distinct pointer types" raise CompilerError(err, self.op.r) # Now, we can do comparison out = ILValue(ctypes.integer) il_code.add(self.eq_il_cmd(out, left, right)) return out
def _arith(self, left, right, il_code): """Compare arithmetic expressions.""" out = ILValue(ctypes.integer) il_code.add(self.comp_cmd(out, left, right)) return out
def _arith(self, left, right, il_code): """Check equality of arithmetic expressions.""" out = ILValue(ctypes.integer) il_code.add(self.eq_il_cmd(out, left, right)) return out
def _lvalue(self, il_code, symbol_table, c): il_value = ILValue(ArrayCType(ctypes.char, len(self.chars))) il_code.register_string_literal(il_value, self.chars) return DirectLValue(il_value)
def addr(self, il_code): # noqa D102 out = ILValue(PointerCType(self.il_value.ctype)) il_code.add(value_cmds.AddrOf(out, self.il_value)) return out
def val(self, il_code): self._fix_chunk_count(il_code) out = ILValue(self.ctype()) il_code.add(value_cmds.ReadRel( out, self.base, self.fixed_chunk, self.fixed_count)) return out
def addr(self, il_code): self._fix_chunk_count(il_code) out = ILValue(PointerCType(self.ctype())) il_code.add(value_cmds.AddrRel( out, self.base, self.fixed_chunk, self.fixed_count)) return out
def val(self, il_code): # noqa D102 out = ILValue(self.ctype()) il_code.add(value_cmds.ReadAt(out, self.addr_val)) return out
def _lvalue(self, il_code, symbol_table, c): il_value = ILValue(ASMCType(ctypes.integer, len(self.code))) il_code.register_asm_literal(il_value, self.code) return DirectLValue(il_value)