async def compile(self, ctx: CompileContext) -> Register: lhs, rhs = await self.compile_meta(ctx) res = ctx.get_register(lhs.size, self.sign) op = {"+": "add", "-": "sub"}[self.op] if isinstance(await self.type, Pointer): # adding a pointer with an integer multiplies the integer side by the pointed to type (ptr_type, non_ptr) = ((self.left_type, rhs) if isinstance( self.left_type, Pointer) else (self.right_type, lhs)) if isinstance(ptr_type.to, Void): raise self.error("Cannot perform pointer arithmetic on pointer to void.") ctx.emit(Binary.mul(non_ptr, Immediate(ptr_type.to.size, non_ptr.size))) elif (op == "sub" and isinstance(self.left_type, Pointer) and isinstance(self.right_type, Pointer)): if isinstance(self.left_type.to, Void): raise self.error("Cannot perform pointer arithmetic on pointer to void.") if self.left_type != self.right_type: raise self.error("Both sides of pointer subtraction must be the same type.") # subtracting two pointers of equal type yields the number of elements between them ctx.emit(Binary(lhs, rhs, op, res)) ctx.emit(Binary.udiv(res, Immediate(self.left_type.to.size, res.size))) return res ctx.emit(Binary(lhs, rhs, op, res)) return res
async def compile(self, ctx: CompileContext) -> Register: op = {"|": "or", "^": "xor", "&": "and"}[self.op] lhs, rhs = await self.compile_meta(ctx) res = ctx.get_register(lhs.size, self.sign) ctx.emit(Binary(lhs, rhs, op, res)) return res
async def compile(self, ctx: CompileContext) -> Register: my_type = await self.type ptr: Register = await self.load_lvalue(ctx) tmp = ctx.get_register(my_type.size, my_type.signed) increment = 1 # in the case of pointer increments, increment by the size of the pointer's underlying type if isinstance(my_type, Pointer): increment = my_type.to.size ctx.emit(Mov(tmp, Dereference(ptr, tmp.size))) ctx.emit(Binary(tmp, Immediate(increment, tmp.size), self.op)) ctx.emit(Mov(Dereference(ptr, tmp.size), tmp)) return tmp
async def compile(self, ctx: CompileContext) -> Register: my_type = await self.type ptr: Register = await self.arg.load_lvalue(ctx) size = my_type.size res, temp = (ctx.get_register(size, my_type.signed), ctx.get_register(size)) increment = 1 if isinstance(my_type, Pointer): increment = my_type.to.size ctx.emit(Mov(res, Dereference(ptr, res.size))) ctx.emit(Binary(res, Immediate(increment, size), self.op, temp)) ctx.emit(Mov(Dereference(ptr, temp.size), temp)) return res
async def compile(self, ctx: CompileContext) -> Register: lhs, rhs = await self.compile_meta(ctx) if rhs.sign: raise self.right.error( "RHS operand to a binary shift op must be unsigned.") res = ctx.get_register(lhs.size, self.sign) if self.op == "<<": op = "shl" elif self.op == ">>" and lhs.sign: op = "sar" else: op = "shr" ctx.emit(Binary(lhs, rhs, op, res)) return res
async def compile(self, ctx: CompileContext) -> Register: lhs, rhs = await self.compile_meta(ctx) res = ctx.get_register(lhs.size, self.sign) if self.op == "*": op = "mul" elif self.op == "%": if self.sign: op = "imod" else: op = "umod" elif self.op == "/" and self.sign: op = "idiv" else: op = "udiv" ctx.emit(Binary(lhs, rhs, op, res)) return res