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 expr.ctype.is_scalar(): err = "'!' operator requires scalar operand" raise CompilerError(err, self.r) # ILValue for storing the output out = ILValue(ctypes.integer) # ILValue for zero. zero = ILValue(ctypes.integer) il_code.register_literal_var(zero, "0") # ILValue for one. one = ILValue(ctypes.integer) il_code.register_literal_var(one, "1") # Label which skips the line which sets out to 0. end = il_code.get_label() il_code.add(value_cmds.Set(out, one)) il_code.add(control_cmds.JumpZero(expr, end)) il_code.add(value_cmds.Set(out, zero)) il_code.add(control_cmds.Label(end)) return out
def make_il(self, il_code, symbol_table, c): # ILValue for storing the output of this boolean operation out = ILValue(ctypes.integer) # ILValue for initial value of output variable. init = ILValue(ctypes.integer) il_code.register_literal_var(init, self.initial_value) # ILValue for other value of output variable. other = ILValue(ctypes.integer) il_code.register_literal_var(other, 1 - self.initial_value) # Label which immediately precedes the line which sets out to 0 or 1. set_out = il_code.get_label() # Label which skips the line which sets out to 0 or 1. end = il_code.get_label() err = "'{}' operator requires scalar operands".format(str(self.op)) left = self.left.make_il(il_code, symbol_table, c) if not left.ctype.is_scalar(): raise CompilerError(err, self.left.r) il_code.add(value_cmds.Set(out, init)) il_code.add(self.jump_cmd(left, set_out)) right = self.right.make_il(il_code, symbol_table, c) if not right.ctype.is_scalar(): raise CompilerError(err, self.right.r) il_code.add(self.jump_cmd(right, set_out)) il_code.add(control_cmds.Jump(end)) il_code.add(control_cmds.Label(set_out)) il_code.add(value_cmds.Set(out, other)) il_code.add(control_cmds.Label(end)) return out
def make_il(self, il_code, symbol_table, c): """Make code for this node.""" lval = self.expr.lvalue(il_code, symbol_table, c) if not lval or not lval.modable(): err = "operand of {} operator not a modifiable lvalue" raise CompilerError(err.format(self.descrip), self.expr.r) val = self.expr.make_il(il_code, symbol_table, c) one = ILValue(val.ctype) if val.ctype.is_arith(): il_code.register_literal_var(one, 1) elif val.ctype.is_pointer() and val.ctype.arg.is_complete(): il_code.register_literal_var(one, val.ctype.arg.size) elif val.ctype.is_pointer() and not val.ctype.arg.is_complete(): err = "invalid arithmetic on pointer to incomplete type" raise CompilerError(err, self.op.r) else: err = "invalid type for {} operator" raise CompilerError(err.format(self.descrip), self.expr.r) new_val = ILValue(val.ctype) if self.return_new: il_code.add(self.cmd(new_val, val, one)) lval.set_to(new_val, il_code, self.expr.r) return new_val else: old_val = ILValue(val.ctype) il_code.add(value_cmds.Set(old_val, val)) il_code.add(self.cmd(new_val, val, one)) lval.set_to(new_val, il_code, self.expr.r) return old_val
def set_type(il_value, ctype, il_code, output=None): """If necessary, emit code to cast given il_value to the given ctype. If `output` is given, then this function expects output.ctype to be the same as ctype, sets `output` to the casted value, and returns output. If `output` is not given, this function returns an IL value with type ctype. If `il_value.ctype` matches given ctype, this function may return `il_value` directly. So, the return value should never have its value changed because this may affect the value in the given `il_value`. 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 elif not output and il_value.literal: output = ILValue(ctype) if ctype.is_integral(): val = shift_into_range(il_value.literal.val, ctype) else: val = il_value.literal.val il_code.register_literal_var(output, val) return output 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.""" lval = self.expr.lvalue(il_code, symbol_table, c) if not lval or not lval.modable(): err = f"operand of {self.descrip} operator not a modifiable lvalue" raise CompilerError(err, self.expr.r) val = self.expr.make_il(il_code, symbol_table, c) one = ILValue(val.ctype) if val.ctype.is_arith(): il_code.register_literal_var(one, 1) elif val.ctype.is_pointer() and val.ctype.arg.is_complete(): il_code.register_literal_var(one, val.ctype.arg.size) elif val.ctype.is_pointer(): # technically, this message is not quite right because for # non-object types, a type can be neither complete nor incomplete err = "invalid arithmetic on pointer to incomplete type" raise CompilerError(err, self.expr.r) else: err = f"invalid type for {self.descrip} operator" raise CompilerError(err, self.expr.r) new_val = ILValue(val.ctype) if self.return_new: il_code.add(self.cmd(new_val, val, one)) lval.set_to(new_val, il_code, self.expr.r) return new_val else: old_val = ILValue(val.ctype) il_code.add(value_cmds.Set(old_val, val)) il_code.add(self.cmd(new_val, val, one)) lval.set_to(new_val, il_code, self.expr.r) return old_val
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