Beispiel #1
0
    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
Beispiel #2
0
    async def compile_as_arr(self, ctx: CompileContext) -> Register:
        """Compile an array literal but inline the inner values."""

        if (isinstance((await self.type).to, types.Array)
                and (not isinstance(self.first_elem, ArrayLiteral))):
            # Maybe just cast the internal type to a pointer.
            raise self.error(
                "Internal type is of array type but is not a literal.")

        if self.var is None:
            self.var = ctx.declare_unique_variable(await self.type)
            self.var.lvalue_is_rvalue = True

        base = ctx.get_register(types.Pointer.size)
        index = ctx.get_register(types.Pointer.size)

        ctx.emit(LoadVar(self.var, base))
        ctx.emit(Mov(index, base))

        elem_size = (await self.type).to.size

        for i in self.exprs:
            await i.compile_as_arr_helper(ctx, index)

        # NOTE: will we ever hit this?
        if self.float_size:
            ctx.emit(Binary.add(index, Immediate(elem_size * self.float_size)))

        return base
Beispiel #3
0
    async def compile(self, ctx: CompileContext) -> Register:

        lhs_type, rhs_type = await self.left.type, await self.right.type

        if not rhs_type.implicitly_casts_to(lhs_type):
            raise self.error(
                f"Right argument to boolean operator: '{self.right.matched_region}'\n"
                f"of type: {rhs_type} cannot be casted to left argument: '{self.left.matched_region}'\n"
                f"of type {lhs_type}")

        if isinstance(lhs_type, Void):
            raise self.left.error("Void type argument to boolean operator")
        if isinstance(rhs_type, Void):
            raise self.right.error("Void type argument to boolean operator")

        r1: Register = await self.left.compile(ctx)
        ctx.emit(Compare(r1, Immediate(0, r1.size)))
        target = JumpTarget()
        op = {'or': CompType.neq, 'and': CompType.eq}[self.op]

        cond = ctx.get_register(1)
        ctx.emit(SetCmp(cond, op))

        ctx.emit(Jump(target, cond))
        r2: Register = (await self.right.compile(ctx))
        if r2.size != r1.size:
            r2_ = r2.resize(r1.size, r1.sign)
            ctx.emit(Resize(r2, r2_))
            r2 = r2_
        ctx.emit(Mov(r1, r2))
        ctx.emit(target)
        return r1
Beispiel #4
0
    async def compile_as_ref(self, ctx: CompileContext) -> Register:
        """Compile to the array literal and return a reference to the start.

        This function is for when an array of references is the wanted outcome.
        This function will not work on array types.
        """

        if self.var is None:
            self.var = ctx.declare_unique_variable(await self.type)
            self.var.lvalue_is_rvalue = True

        if (isinstance(self.first_elem, ArrayLiteral) and (not isinstance(
            (await self.type).to, types.Pointer))):
            raise self.error(
                "Cannot compile to references if internal array type is an array and not a pointer"
            )

        base = ctx.get_register(types.Pointer.size)
        index = ctx.get_register(types.Pointer.size)

        ctx.emit(LoadVar(self.var, base))
        ctx.emit(Mov(index, base))

        elem_type = (await self.type).to

        for i in self.exprs:
            r = await i.compile(ctx)

            if r.size != elem_type.size:
                r0 = r.resize(elem_type.size, elem_type.signed)
                ctx.emit(Resize(r, r0))
                r = r0

            ctx.emit(Mov(Dereference(index, r.size), r))
            ctx.emit(Binary.add(index, Immediate(r.size, types.Pointer.size)))

        if self.float_size:
            # fill in missing values
            ctx.emit(
                Binary.add(
                    index,
                    Immediate(elem_type.size * self.float_size, index.size)))

        return base
Beispiel #5
0
 def p_res(i):
     if i.operation is ASMExprType.index_register:
         r = AllocatedRegister(i.size, i.val)
     elif i.operation is ASMExprType.int_immediate:
         r = Immediate(i.val, i.size)
     elif i.operation is ASMExprType.expr_index:
         if i.val not in range(len(expr_registers)):
             raise InternalCompileException(f"Missing expression index for asm instruction {i.val}. regs: {expr_registers}")
         r = expr_registers[i.val].copy()  # make sure to copy the register object
     if i.deref:
         r = Dereference(r, i.size)
     return r
Beispiel #6
0
    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
Beispiel #7
0
 async def compile_as_arr_helper(self, ctx: CompileContext, base: Register):
     if isinstance(self.first_elem, ArrayLiteral) and isinstance(
             await self.type, types.Array):
         for i in self.exprs:
             await i.compile_as_arr_helper(ctx, base)
     else:
         elem_type = (await self.type).to
         for i in self.exprs:
             r = await i.compile(ctx)
             if r.size != elem_type.size:
                 r0 = r.resize(elem_type.size, elem_type.signed)
                 ctx.emit(Resize(r, r0))
                 r = r0
             ctx.emit(Mov(Dereference(base, r.size), r))
             ctx.emit(
                 Binary.add(base, Immediate(r.size, types.Pointer.size)))
Beispiel #8
0
    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
Beispiel #9
0
    async def load_lvalue(self, ctx: CompileContext) -> Register:
        atype = await self.arg.type

        if not isinstance(atype, (Pointer, Array)):
            raise self.error(f"Incompatible type to array index base {atype}")

        # don't allow void pointer arithmetic
        # This 'would' fail later with an error about requesting a register of size 0
        # But that would be less informative than catching the error now.
        if isinstance(atype.to, Void):
            raise self.error("Cannot perform pointer arithemetic on void pointers.")

        argument = await self.arg.compile(ctx)
        offset = await self.offset.compile(ctx)

        # get the size of the inner type if type.to is an array,
        # this will be the size of the internal array
        size = await self.size

        # make sure both the offset and the arguments are the correct size (size of a pointer)
        if argument.size != Pointer.size:
            argument0 = argument.resize(Pointer.size)
            ctx.emit(Resize(argument, argument0))
            argument = argument0

        if offset.size != Pointer.size:
            offset0 = offset.resize(Pointer.size)
            ctx.emit(Resize(offset, offset0))
            offset = offset0

        result = ctx.get_register(Pointer.size)
        # multiply to the size of the inner type of the pointer/ array
        ctx.emit(Binary.mul(offset, Immediate(size, offset.size)))
        ctx.emit(Binary.add(argument, offset, result))

        return result
Beispiel #10
0
 async def compile(self, ctx: CompileContext) -> Register:
     reg = ctx.get_register(self._type.size, self._type.signed)
     ctx.emit(Mov(reg, Immediate(self.lit, self._type.size)))
     return reg