def pointer_subsc(self, point, arith, il_code): """Return the LValue for this node. This function is called in the case where one operand is a pointer and the other operand is an integer. """ if not point.ctype.arg.is_complete(): err = "cannot subscript pointer to incomplete type" raise CompilerError(err, self.op.r) shift = get_size(point.ctype.arg, arith, il_code) out = ILValue(point.ctype) il_code.add(math_cmds.Add(out, point, shift)) return IndirectLValue(out)
def pointer_subsc(self, point, arith, il_code): """Return the LValue for this node. This function is called in the case where one operand is a pointer and the other operand is an integer. """ if not point.ctype.arg.is_complete(): err = "cannot subscript pointer to incomplete type" raise CompilerError(err, self.r) shift = get_size(point.ctype.arg, arith, il_code) out = ILValue(point.ctype) il_code.add(math_cmds.Add(out, point, shift)) return IndirectLValue(out)
def make_il(self, il_code, symbol_table, c): """Make code for this node.""" right = self.right.make_il(il_code, symbol_table, c) lvalue = self.left.lvalue(il_code, symbol_table, c) if not lvalue or not lvalue.modable(): err = "expression on left of '{}' is not assignable" raise CompilerError(err.format(str(self.op)), self.left.r) if (lvalue.ctype().is_pointer() and right.ctype.is_integral() and self.accept_pointer): if not lvalue.ctype().arg.is_complete(): err = "invalid arithmetic on pointer to incomplete type" raise CompilerError(err, self.op.r) # Because of caching requirement of make_il and lvalue functions, # we know this call won't regenerate code for the left expression # beyond just what's needed to get the value stored at the lvalue. # This is important in cases like ``*func() += 10`` where func() # may have side effects if called twice. left = self.left.make_il(il_code, symbol_table, c) out = ILValue(left.ctype) shift = get_size(left.ctype.arg, right, il_code) il_code.add(self.command(out, left, shift)) lvalue.set_to(out, il_code, self.op.r) return out elif lvalue.ctype().is_arith() and right.ctype.is_arith(): left = self.left.make_il(il_code, symbol_table, c) out = ILValue(left.ctype) left, right = arith_convert(left, right, il_code) il_code.add(self.command(out, left, right)) lvalue.set_to(out, il_code, self.op.r) return out else: err = "invalid types for '{}' operator".format(str(self.op)) raise CompilerError(err, self.op.r)
def make_il(self, il_code, symbol_table, c): """Make code for this node.""" right = self.right.make_il(il_code, symbol_table, c) lvalue = self.left.lvalue(il_code, symbol_table, c) if not lvalue or not lvalue.modable(): err = f"expression on left of '{str(self.op)}' is not assignable" raise CompilerError(err, self.left.r) if (lvalue.ctype().is_pointer() and right.ctype.is_integral() and self.accept_pointer): if not lvalue.ctype().arg.is_complete(): err = "invalid arithmetic on pointer to incomplete type" raise CompilerError(err, self.op.r) # Because of caching requirement of make_il and lvalue functions, # we know this call won't regenerate code for the left expression # beyond just what's needed to get the value stored at the lvalue. # This is important in cases like ``*func() += 10`` where func() # may have side effects if called twice. left = self.left.make_il(il_code, symbol_table, c) out = ILValue(left.ctype) shift = get_size(left.ctype.arg, right, il_code) il_code.add(self.command(out, left, shift)) lvalue.set_to(out, il_code, self.op.r) return out elif lvalue.ctype().is_arith() and right.ctype.is_arith(): left = self.left.make_il(il_code, symbol_table, c) out = ILValue(left.ctype) left, right = arith_convert(left, right, il_code) il_code.add(self.command(out, left, right)) lvalue.set_to(out, il_code, self.op.r) return out else: err = f"invalid types for '{str(self.op)}' operator" raise CompilerError(err, self.op.r)
def _nonarith(self, left, right, il_code): """Make subtraction code if both operands are non-arithmetic type.""" # TODO: this isn't quite right when we allow qualifiers if (left.ctype.is_pointer() and right.ctype.is_pointer() and left.ctype.compatible(right.ctype)): if not (left.ctype.arg.is_complete() and right.ctype.arg.is_complete()): err = "invalid arithmetic on pointers to incomplete types" raise CompilerError(err, self.op.r) # Get raw difference in pointer values raw = ILValue(ctypes.longint) il_code.add(math_cmds.Subtr(raw, left, right)) # Divide by size of object out = ILValue(ctypes.longint) size = ILValue(ctypes.longint) il_code.register_literal_var(size, str(left.ctype.arg.size)) il_code.add(math_cmds.Div(out, raw, size)) return out # Left operand is pointer to complete object type, and right operand # is integer. elif left.ctype.is_pointer() and right.ctype.is_integral(): if not left.ctype.arg.is_complete(): err = "invalid arithmetic on pointer to incomplete type" raise CompilerError(err, self.op.r) out = ILValue(left.ctype) shift = get_size(left.ctype.arg, right, il_code) il_code.add(math_cmds.Subtr(out, left, shift)) return out else: descrip = "invalid operand types for subtraction" raise CompilerError(descrip, self.op.r)
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 _nonarith(self, left, right, il_code): """Make subtraction code if both operands are non-arithmetic type.""" # TODO: this isn't quite right when we allow qualifiers if (left.ctype.is_pointer() and right.ctype.is_pointer() and left.ctype.compatible(right.ctype)): if (not left.ctype.arg.is_complete() or not right.ctype.arg.is_complete()): err = "invalid arithmetic on pointers to incomplete types" raise CompilerError(err, self.op.r) # Get raw difference in pointer values raw = ILValue(ctypes.longint) il_code.add(math_cmds.Subtr(raw, left, right)) # Divide by size of object out = ILValue(ctypes.longint) size = ILValue(ctypes.longint) il_code.register_literal_var(size, str(left.ctype.arg.size)) il_code.add(math_cmds.Div(out, raw, size)) return out # Left operand is pointer to complete object type, and right operand # is integer. elif left.ctype.is_pointer() and right.ctype.is_integral(): if not left.ctype.arg.is_complete(): err = "invalid arithmetic on pointer to incomplete type" raise CompilerError(err, self.op.r) out = ILValue(left.ctype) shift = get_size(left.ctype.arg, right, il_code) il_code.add(math_cmds.Subtr(out, left, shift)) return out else: descrip = "invalid operand types for subtraction" raise CompilerError(descrip, self.op.r)