コード例 #1
0
 def decl_var(self, t):
     type = t.children[0]
     name = Location(t.children[1])
     lv = self._currentFunction.localVars
     if name in lv:
         raise SemanticError(Position.fromAny(t), f"Local variable {name} redifinition")
     lv[name] = type
コード例 #2
0
ファイル: value.py プロジェクト: imihajlow/ccpu
 def __init__(self, position, type, indirLevel, src, aligned):
     if indirLevel < 0:
         raise SemanticError(position, "Cannot take address")
     self._position = position
     self._type = type
     self._level = indirLevel
     self._src = Location(src)
     self._isAligned = aligned
コード例 #3
0
 def error(cls, error_code: ErrorCode, token: Token,
           var_name: str) -> NoReturn:
     raise SemanticError(
         error_code=error_code,
         token=token,
         message=
         f"{error_code.value} \n \t{token} \n \tIdentifier: '{var_name}'",
     )
コード例 #4
0
 def arrow(self, t):
     obj = t.children[0]
     fields = t.children[1:]
     if isinstance(obj, Value) and obj.getType().isPointer(
     ) and obj.getIndirLevel() == 0:
         try:
             offset, type = getField(obj.getType().deref(), fields)
         except ValueError as e:
             raise SemanticError(Position.fromAny(t), str(e))
         except AttributeError as e:
             raise SemanticError(Position.fromAny(t),
                                 f"{obj} is not a struct")
         return Value.withOffset(Position.fromAny(t), type,
                                 1 + type.getIndirectionOffset(),
                                 obj.getSource(), False, offset)
     else:
         return t
コード例 #5
0
 def function_definition(self, t):
     decl, body = t.children
     fn = self._addFunction(decl, True)
     if fn.isImported:
         raise SemanticError(Position.fromAny(decl), "Cannot define an imported function")
     self._currentFunction = fn
     self.visit(body)
     self._currentFunction = None
コード例 #6
0
ファイル: unary.py プロジェクト: imihajlow/ccpu
def genBNot(resultLoc, srcLoc):
    if resultLoc.getType().isUnknown():
        resultLoc = resultLoc.removeUnknown(srcLoc.getType())
    if resultLoc.getType() != srcLoc.getType():
        raise SemanticError(
            srcLoc.getPosition(),
            "Incompatible types: {} and {}".format(resultLoc.getType(),
                                                   srcLoc.getType()))
    assert (resultLoc.getIndirLevel() == 1)
    assert (srcLoc.getIndirLevel() == 1 or srcLoc.getIndirLevel() == 0)
    t = srcLoc.getType()
    result = '; {} = ~{}\n'.format(resultLoc, srcLoc)
    if srcLoc.getIndirLevel() == 0:
        # constant
        c = srcLoc.getSource()
        c = ~c
        return Value(srcLoc.getPosition(), t, 0, c, True), result
    # var
    s = srcLoc.getSource()
    rs = resultLoc.getSource()
    if t.getSize() == 1:
        result += loadByte('a', srcLoc, 0)
        result += 'not a\n'
        return Value.register(srcLoc.getPosition(), t), result
    else:  # size > 1
        for offset in range(0, t.getSize(), 2):
            rest = t.getSize() - offset
            result += f'''
                ldi pl, lo({s} + {offset})
                ldi ph, hi({s} + {offset})
                ld b
            '''
            if rest > 1:
                result += incP(srcLoc.isAligned())
                result += 'ld a\n'
            result += f'''
                ldi pl, lo({rs} + {offset})
                ldi ph, hi({rs} + {offset})
                not b
                st b
            '''
            if rest > 1:
                if resultLoc.isAligned:
                    result += '''
                        inc pl
                        not a
                        st a
                    '''
                else:
                    result += '''
                        mov b, a
                        inc pl
                        mov a, 0
                        adc ph, a
                        not b
                        st b
                    '''
        return resultLoc, result
コード例 #7
0
 def type_error(cls, *args, token: Token) -> NoReturn:
     formatted_variable_types = (" and ".join(args)
                                 if len(args) == 2 else ", ".join(args))
     raise SemanticError(
         error_code=ErrorCode.TYPE_ERROR,
         token=token,
         message=
         f"{ErrorCode.TYPE_ERROR.value}: {formatted_variable_types}\n \t{token}",
     )
コード例 #8
0
ファイル: value.py プロジェクト: imihajlow/ccpu
 def takeAddress(self, newPosition=None):
     if self._level > 0:
         return Value(
             self._position if newPosition is None else newPosition,
             PtrType(self._type), self._level - 1, self._src, True)
     else:
         raise SemanticError(
             self._position,
             "Cannot get address of this: {}".format(str(self)))
コード例 #9
0
ファイル: unary.py プロジェクト: imihajlow/ccpu
def genDeref(resultLoc, srcLoc, offset=0):
    if resultLoc.getType().isUnknown():
        resultLoc = resultLoc.removeUnknown(srcLoc.getType().deref())
    if srcLoc.getType().deref() != resultLoc.getType() and not srcLoc.getType(
    ).deref().isStruct():
        raise SemanticError(
            srcLoc.getPosition(),
            "Incompatible types for deref: {} and {}".format(
                srcLoc.getType().deref(), resultLoc.getType()))
    assert (srcLoc.getIndirLevel() <= 1)

    t = resultLoc.getType()

    if srcLoc.getIndirLevel() == 0:
        return Value.withOffset(srcLoc.getPosition(), resultLoc.getType(), 1,
                                srcLoc.getSource(), True, offset), ""

    result = '; {} = deref {} + {}\n'.format(resultLoc, srcLoc, offset)
    result += '; result is {}aligned, srcLoc is {}aligned'.format(
        "" if resultLoc.isAligned() else "not ",
        "" if srcLoc.isAligned() else "not ")
    rs = resultLoc.getSource()
    if t.getSize() == 1:
        result += loadP(srcLoc, offset)
        result += 'ld a\n'
        return Value.register(srcLoc.getPosition(), t), result
    else:  # t.getSize() > 1
        for byteOffset in reversed(range(0, t.getSize(), 2)):
            rest = min(2, t.getSize() - byteOffset)
            result += loadP(srcLoc, byteOffset + offset)
            result += 'ld b\n'
            if rest > 1:
                result += '''
                    mov a, 0
                    inc pl
                    adc ph, a
                    ld a
                '''
            result += f'''
                ldi pl, lo({rs} + {byteOffset})
                ldi ph, hi({rs} + {byteOffset})
                st b
            '''
            if rest > 1:
                if resultLoc.isAligned():
                    result += '''
                        inc pl
                        st a
                    '''
                else:
                    result += f'''
                        ldi pl, lo({rs} + {byteOffset + 1})
                        ldi ph, hi({rs} + {byteOffset + 1})
                        st a
                    '''
        return resultLoc, result
コード例 #10
0
 def function_definition(self, tree):
     decl, body = tree.children
     _, _, name, _ = decl.children
     self.visit(decl)
     try:
         self._enterFunction(str(name))
     except ValueError as e:
         raise SemanticError(Position.fromAny(tree), str(e))
     self.visit(body)
     self._leaveFunction()
コード例 #11
0
ファイル: value.py プロジェクト: imihajlow/ccpu
 def addr(self, t):
     val = t.children[0]
     if isinstance(val, Value):
         return val.takeAddress(Position.fromAny(t))
     elif val.data == "member_access":
         return Tree("member_address", val.children, t.meta)
     elif val.data == "arrow":
         return Tree("p_arrow", val.children, t.meta)
     else:
         raise SemanticError(Position.fromAny(t), "Cannot get address")
コード例 #12
0
ファイル: binary.py プロジェクト: imihajlow/ccpu
def genSub(resultLoc, src1Loc, src2Loc):
    if resultLoc.getType().isUnknown():
        resultLoc = resultLoc.removeUnknown(src1Loc.getType())
    if resultLoc.getType() != src1Loc.getType():
        raise SemanticError(resultLoc.getPosition(),
            "Incompatible result and source types: {} and {}".format(resultLoc.getType(), src1Loc.getType()))
    if src1Loc.getType().isPointer():
        return _genSubPtr(resultLoc, src1Loc, src2Loc)
    else:
        return _genIntBinary(resultLoc, src1Loc, src2Loc, "sub", "sbb", "({}) - ({})", operator.sub, False)
コード例 #13
0
 def member_address(self, t):
     obj = t.children[0]
     fields = t.children[1:]
     if isinstance(obj, Value):
         try:
             offset, type = getField(obj.getType(), fields)
         except ValueError as e:
             raise SemanticError(Position.fromAny(t), str(e))
         except AttributeError as e:
             raise SemanticError(Position.fromAny(t),
                                 f"{obj} is not a struct")
         if obj.getIndirLevel() != 1:
             raise RuntimeError("WTF is that")
         return Value.withOffset(Position.fromAny(t), PtrType(type),
                                 0 + type.getIndirectionOffset(),
                                 obj.getSource(), True, offset)
     elif obj.data == 'deref':
         return Tree("p_arrow", [obj.children[0]] + fields, t.meta)
     else:
         raise RuntimeError("Unhandled member_access case")
コード例 #14
0
 def struct_declaration(self, t):
     name = t.children[0]
     fields = []
     for c in t.children[1:]:
         ftype = c.children[0]
         fname = c.children[1]
         fields += [(fname, ftype)]
     if name in self._dict:
         raise SemanticError(Position.fromAny(t),
                             f"struct {name} redefinition")
     self._dict[name] = fields
     raise Discard
コード例 #15
0
 def type_cast(self, t):
     type, v = t.children
     from value import Value
     if isinstance(v, Value) and v.getIndirLevel() == 0:
         s = v.getSource()
         if type.getSize() > 2:
             raise SemanticError(Position.fromAny(t),
                                 f"{str(type)} has size > 2, cannot cast")
         if v.getType().getSize() > 2:
             raise SemanticError(
                 Position.fromAny(t),
                 f"{str(v.getType())} has size > 2, cannot cast")
         if type.getSize() > v.getType().getSize():
             # widening cast
             s = s.widen(v.getType().getSign())
         elif type.getSize() < v.getType().getSize():
             # narrowing cast
             s = s.lo()
         return Value(Position.fromAny(t), type, 0, s, True)
     else:
         return t
コード例 #16
0
 def array_field_declaration(self, t):
     type, name, size = t.children
     from value import Value
     if isinstance(size, Value):
         if size.getSource().isNumber():
             if size.getIndirLevel() == 0 and int(size.getSource()) > 0:
                 return Tree("field_declaration",
                             [ArrayType(type, size.getSource()), name],
                             t.meta)
     raise SemanticError(
         Position.fromAny(t),
         "Array size must be a positive constant expression")
コード例 #17
0
def genCmp(resultLoc, src1Loc, src2Loc, op, labelProvider):
    assert (op in {"gt", "ge", "lt", "le"})
    resultLoc = resultLoc.withType(BoolType())
    assert (resultLoc.getIndirLevel() == 1)
    if src1Loc.getType() != src2Loc.getType():
        raise SemanticError(
            src1Loc.getPosition(),
            "Incompatible types: {} and {}".format(src1Loc.getType(),
                                                   src2Loc.getType()))
    t = src1Loc.getType()
    if t.getSign():
        return _genCmpSigned(resultLoc, src1Loc, src2Loc, op, labelProvider)
    else:
        return _genCmpUnsigned(resultLoc, src1Loc, src2Loc, op, labelProvider)
コード例 #18
0
 def decl_array(self, t):
     type = t.children[0]
     size = t.children[2]
     from value import Value
     if isinstance(size, Value):
         if size.getSource().isNumber():
             if size.getIndirLevel() == 0 and int(size.getSource()) > 0:
                 return Tree(
                     "decl_var",
                     [ArrayType(type, size.getSource()), t.children[1]],
                     t.meta)
     raise SemanticError(
         Position.fromAny(t),
         "Array size must be a positive constant expression")
コード例 #19
0
def genShift(resultLoc, src1Loc, src2Loc, op, labelProvider):
    assert (resultLoc.getIndirLevel() == 1)
    t = src1Loc.getType()
    if not t.isInteger():
        raise SemanticError(src1Loc.getPosition(), "Can only shift integers")
    if not src2Loc.getType().isInteger() or src2Loc.getType().getSign():
        raise SemanticError(src2Loc.getPosition(),
                            "Can only shift by unsigned integers")
    resultLoc = resultLoc.withType(t)
    l1 = src1Loc.getIndirLevel()
    l2 = src2Loc.getIndirLevel()
    assert (l1 == 0 or l1 == 1)
    assert (l2 == 0 or l2 == 1)
    if l1 == 0 and l2 == 0:
        raise NatrixNotImplementedError(Position.fromAny(resultLoc),
                                        "Stop doing shit with pointers!")
    if l2 == 0:
        c = src2Loc.getSource()
        if c.isNumber():
            if op == 'shl':
                return genSHLVarByConst(resultLoc, src1Loc, int(c))
            elif op == 'shr':
                if t.getSign():
                    return _genSARVarByConst(resultLoc, src1Loc, int(c))
                else:
                    return _genSHRVarByConst(resultLoc, src1Loc, int(c))
        else:
            raise NatrixNotImplementedError(Position.fromAny(resultLoc),
                                            "Stop doing shit with pointers!")
    else:
        if op == 'shl':
            return _genSHLByVar(resultLoc, src1Loc, src2Loc, labelProvider)
        elif op == 'shr':
            if t.getSign():
                return _genSARByVar(resultLoc, src1Loc, src2Loc, labelProvider)
            else:
                return _genSHRByVar(resultLoc, src1Loc, src2Loc, labelProvider)
コード例 #20
0
def parse(input: str):
    """Takes in a string input and returns a graph"""
    var_definitions_map = OrderedDict()
    links = OrderedDict()

    lines = input.split('\n')
    for line_num, line in enumerate(lines):
        line = line.strip()
        if not line or line[0] == '#':
            continue
        declaration, dec_position, dec_err = parse_declaration(line, 0)
        if declaration is None:
            chain, chain_position, chain_err = parse_chain(line, 0)
            if chain is None:
                err = dec_err if dec_position > chain_position else chain_err
                err_col = max(dec_position, chain_position)
                raise SyntaxError(f'SYNTAX_ERROR<Line {line_num+1}, Col {err_col+1}>: {err}')
            else:
                nodes, link_types = chain

                node_vars = []
                for i, node in enumerate(nodes):
                    type = node['type']
                    var = node['value']
                    if type == 'string':
                        # Create a variable
                        var = str(string_hash(node['value'] + (node['enclosure'] or '')))
                        var_definitions_map[var] = node['value']
                        node_vars.append(f"{node['enclosure']}{var}")
                    else:
                        node_vars.append(f"{node['value'][1]}{node['value'][0]}")
                # Now nodes are ready, create links
                for (source, dest), link_type in zip(zip(node_vars, node_vars[1:]), link_types):
                    if link_type == '<-':
                        source, dest = dest, source
                    links[source] = [*links.get(source, []), dest]
        else:
            name, val = declaration

            present = var_definitions_map.get(name)
            if present is not None:
                raise SemanticError(f"ERROR<Line {line_num + 1}>: variable '{name}' already defined")
            else:
                var_definitions_map[name] = val

    return to_graph(var_definitions_map, links)
コード例 #21
0
def _genDMCommon(resultLoc, src1Loc, src2Loc):
    if src1Loc.getType() != src2Loc.getType():
        raise SemanticError(src1Loc.getPosition() - src2Loc.getPosition(),
                            "division types mismatch")
    t = src1Loc.getType()
    resultLoc = resultLoc.withType(t)
    assert (t.getSize() == 1 or t.getSize() == 2)
    l1 = src1Loc.getIndirLevel()
    l2 = src2Loc.getIndirLevel()
    isWord = t.getSize() == 2
    result = '; {} = {} / {}\n'.format(resultLoc, src1Loc, src2Loc)
    if l1 == 0 and l2 == 0:
        raise NotImplementedError("doing shit with pointers?")
    if isWord:
        if l1 == 0:
            result += storeConstW(src1Loc.getSource(), "__cc_r_a", False)
            result += copyW(src2Loc.getSource(), "__cc_r_b", False, True)
        elif l2 == 0:
            s = src2Loc.getSource()
            result += copyW(src1Loc.getSource(), "__cc_r_a", False, True)
            result += storeConstW(src2Loc.getSource(), "__cc_r_b", False)
        else:
            result += copyW(src1Loc.getSource(), "__cc_r_a", False, True)
            result += copyW(src2Loc.getSource(), "__cc_r_b", False, True)
    else:
        result += loadByte('b', src1Loc, 0)
        result += loadByte('a', src2Loc, 0)
        result += '''
            ldi pl, lo(__cc_r_a)
            ldi ph, hi(__cc_r_a)
            st b
            ldi pl, lo(__cc_r_b)
            st a
        '''
    if isWord:
        if t.getSign():
            result += call("__cc_div_word")
        else:
            result += call("__cc_udiv_word")
    else:
        if t.getSign():
            result += call("__cc_div_byte")
        else:
            result += call("__cc_udiv_byte")
    return resultLoc, result
コード例 #22
0
def genInvCondJump(condLoc, label):
    '''
    Jump if condLoc is 0
    '''
    if condLoc.getType() != BoolType():
        raise SemanticError(
            condLoc.getPosition(),
            "Should be a bool type (u8) for a condition, got {}".format(
                str(condLoc.getType())))
    l = condLoc.getIndirLevel()
    s = condLoc.getSource()
    assert (l == 0 or l == 1)
    result = '; jump if not {}\n'.format(condLoc)
    if l == 0:
        if s.isNumber():
            if not bool(s):
                result += '''
                    ldi pl, lo({0})
                    ldi ph, hi({0})
                    jmp
                '''.format(label)
        else:
            result += '''
                ldi a, lo({0})
                add a, 0
                ldi pl, lo({1})
                ldi ph, hi({1})
                jz
            '''.format(s, label)
    else:
        if not s.isRegister():
            result += f'''
                ldi pl, lo({s})
                ldi ph, hi({s})
                ld a
            '''
        result += f'''
            ldi pl, lo({label})
            ldi ph, hi({label})
            add a, 0
            jz
        '''
    return result
コード例 #23
0
 def generateAssignment(self, l, r, curFn):
     '''
     Assignment. Possible cases:
     1. var = expression
         simply generate the expression into var
     2. *(e1) = e2
         generate e1 into tmp0 (address)
         generate e2 into tmp1
         put indirect tmp1 at tmp0
     3. (*var).field = expression
     '''
     if isinstance(l, Value):
         # case 1: simple variable
         if not l.isLValue():
             raise SemanticError(l.getPosition(),
                                 "Cannot assign to an r-value")
         dest = l
         resultLoc, codeExpr = self.generateExpression(r, 0, dest, curFn)
         if resultLoc == dest:
             # already assigned where needed
             return codeExpr
         else:
             # need to copy
             _, codeMove = self.backend.genMove(dest, resultLoc, False)
             return codeExpr + codeMove
     elif l.data == 'deref':
         # case 2: dereferenced expression
         ptr = l.children[0]
         self.maxTempVarIndex = max(self.maxTempVarIndex, 1)
         rvPtr, codePtr = self.generateExpression(
             ptr, 0,
             Value.variable(Position.fromAny(ptr),
                            labelname.getTempName(0, curFn)), curFn)
         assert (not rvPtr.getSource().isRegister())
         rvR, codeR = self.generateExpression(
             r, 1,
             Value.variable(Position.fromAny(r),
                            labelname.getTempName(1, curFn)), curFn)
         codePutIndirect = self.backend.genPutIndirect(rvPtr, rvR)
         return codePtr + codeR + codePutIndirect
     elif l.data == 'arrow':
         # case 3: member of a derefed struct
         ptr = l.children[0]
         fields = l.children[1:]
         self.maxTempVarIndex = max(self.maxTempVarIndex, 1)
         rvPtr, codePtr = self.generateExpression(
             ptr, 0,
             Value.variable(Position.fromAny(ptr),
                            labelname.getTempName(0, curFn)), curFn)
         assert (not rvPtr.getSource().isRegister())
         try:
             offset, type = structure.getField(rvPtr.getType().deref(),
                                               fields)
         except LookupError as e:
             raise SemanticError(Position.fromAny(r), str(e))
         except ValueError as e:
             raise SemanticError(Position.fromAny(r), str(e))
         if type.getIndirectionOffset() < 0:
             raise SemanticError(Position.fromAny(l),
                                 "Cannot assign to an r-value")
         rvR, codeR = self.generateExpression(
             r, 1,
             Value.variable(Position.fromAny(r),
                            labelname.getTempName(1, curFn)), curFn)
         codePutIndirect = self.backend.genPutIndirect(
             rvPtr.withType(PtrType(type)), rvR, offset)
         return codePtr + codeR + codePutIndirect
     else:
         raise RuntimeError("Unknown assignment case")
コード例 #24
0
def genMove(resultLoc, srcLoc, avoidCopy):
    if srcLoc.getType().isUnknown():
        raise SemanticError(srcLoc.getPosition(), "Unknown source type")
    if resultLoc.getType().isUnknown():
        resultLoc = resultLoc.removeUnknown(srcLoc.getType())
    if resultLoc.getType() != srcLoc.getType():
        raise SemanticError(
            resultLoc.getPosition() - srcLoc.getPosition(),
            "Incompatible types to assign: {} and {}".format(
                resultLoc.getType(), srcLoc.getType()))
    if srcLoc == resultLoc:
        return resultLoc, ""
    else:
        if avoidCopy:
            return srcLoc, ""
        else:
            if resultLoc.getIndirLevel() != 1:
                raise RuntimeError(
                    "Compiler error: move destination level of indirection is not 1"
                )
            size = srcLoc.getType().getSize()
            if size == 1 and srcLoc.getSource().isRegister():
                assert (srcLoc.getIndirLevel() == 1)
                rs = resultLoc.getSource()
                result = f'''
                    ldi pl, lo({rs})
                    ldi ph, hi({rs})
                    st a
                '''
                return resultLoc, result
            elif size <= 2:
                loadCode = "; {} := {}\n".format(resultLoc, srcLoc)
                if srcLoc.getIndirLevel() == 0:
                    # var := const
                    c = srcLoc.getSource()
                    loadCode += _loadConst(size, c)
                else:
                    # var := var
                    loadCode += '''
                        ldi pl, lo({0})
                        ldi ph, hi({0})
                        ld b
                        '''.format(srcLoc.getSource())
                    if size > 1:
                        loadCode += 'inc pl\n'
                        if not srcLoc.isAligned():
                            loadCode += '''
                                mov a, 0
                                adc ph, a
                            '''.format(srcLoc.getSource())
                        loadCode += 'ld a\n'
                storeCode = '''
                    ldi pl, lo({0})
                    ldi ph, hi({0})
                    st b
                    '''.format(resultLoc.getSource())
                if size > 1:
                    if resultLoc.isAligned():
                        storeCode += 'inc pl\n'
                    else:
                        storeCode += '''
                            ldi pl, lo({0} + 1)
                            ldi ph, hi({0} + 1)
                            '''.format(resultLoc.getSource())
                    storeCode += 'st a\n'
                return resultLoc, loadCode + storeCode
            else:  # size > 2
                result = f"; {resultLoc} := {srcLoc} (large)\n"
                if srcLoc.getIndirLevel() == 0:
                    for offset in range(0, size, 2):
                        chunkSize = min(2, size - offset)
                        result += _loadConst(chunkSize, srcLoc.getSource(),
                                             offset)
                        result += f"""
                            ldi pl, lo({resultLoc.getSource()} + {offset})
                            ldi ph, hi({resultLoc.getSource()} + {offset})
                            st b
                        """
                        if chunkSize > 1:
                            if resultLoc.isAligned():
                                result += 'inc pl\n'
                            else:
                                result += f'''
                                    ldi pl, lo({resultLoc.getSource()} + {offset + 1})
                                    ldi ph, hi({resultLoc.getSource()} + {offset + 1})
                                '''
                            result += 'st a\n'
                    return resultLoc, result
                else:
                    # TODO loop on large objects
                    for offset in range(0, size, 2):
                        chunkSize = min(2, size - offset)
                        result += f'''
                            ldi pl, lo(({srcLoc.getSource()}) + {offset})
                            ldi ph, hi(({srcLoc.getSource()}) + {offset})
                            ld a
                        '''
                        if chunkSize > 1:
                            if srcLoc.isAligned():
                                result += f'''
                                    inc pl
                                '''
                            else:
                                result += f'''
                                    ldi pl, lo(({srcLoc.getSource()}) + {offset + 1})
                                    ldi ph, hi(({srcLoc.getSource()}) + {offset + 1})
                                '''
                            result += f'''
                                ld b
                                ldi pl, lo(({resultLoc.getSource()}) + {offset + 1})
                                ldi ph, hi(({resultLoc.getSource()}) + {offset + 1})
                                st b
                            '''

                            if resultLoc.isAligned():
                                result += '''
                                    dec pl
                                '''
                            else:
                                result += f'''
                                    ldi pl, lo(({resultLoc.getSource()}) + {offset})
                                    ldi ph, hi(({resultLoc.getSource()}) + {offset})
                                '''
                        else:
                            result += f'''
                                ldi pl, lo(({resultLoc.getSource()}) + {offset})
                                ldi ph, hi(({resultLoc.getSource()}) + {offset})
                            '''
                        result += '''
                            st a
                        '''
                    return resultLoc, result
コード例 #25
0
ファイル: binary.py プロジェクト: imihajlow/ccpu
def _genSubPtr(resultLoc, src1Loc, src2Loc):
    if not src2Loc.getType().isInteger():
        raise SemanticError(src2Loc.getPosition(),
            "Can only subtract ponters and integers, not pointers and other types")
    memberSize = src1Loc.getType().deref().getSize()
    s1 = src1Loc.getSource()
    s2 = src2Loc.getSource()
    rs = resultLoc.getSource()
    t = resultLoc.getType()
    result = '; {} = {} - {} * {}\n'.format(resultLoc, src1Loc, src2Loc, memberSize)
    isWord = src2Loc.getType().getSize() == 2
    if memberSize > 2:
        if src2Loc.getIndirLevel() == 0:
            pos = src1Loc.getPosition() - src2Loc.getPosition()
            offset = s2 * memberSize
            loc, code = _genIntBinary(resultLoc, src1Loc, Value(pos, t, 0, offset, True), "sub", "sbb", "({}) - ({})", operator.sub, False)
            return loc, result + code
        elif not isPowerOfTwo(memberSize):
            raise NatrixNotImplementedError(src2Loc.getPosition(), f"sizeof({src1Loc.getType().deref()}) = {memberSize} is not a power of two")
        elif src1Loc == resultLoc:
            shift = log(memberSize)
            loc, code = _genIncDecPtr(resultLoc, src2Loc, shift, "sub", "sbb")
            return loc, result + code
        else:
            shift = log(memberSize)
            shiftedLoc, shiftCode = genSHLVarByConst(resultLoc, src2Loc, shift)
            loc, subtractionCode = _genIntBinary(resultLoc, src1Loc, shiftedLoc, "sub", "sbb", "({}) - ({})", operator.sub, False)
            return loc, result + shiftCode + subtractionCode
    elif isWord:
        assert(not src2Loc.getSource().isRegister())
        if memberSize == 1:
            # no multiplication, just subtract
            loc, code = _genIntBinary(resultLoc, src1Loc, src2Loc.withType(t), "sub", "sbb", "({}) - ({})", operator.sub, False)
            return loc, result + code
        elif memberSize == 2:
            if src2Loc.getIndirLevel() == 0:
                pos = src1Loc.getPosition() - src2Loc.getPosition()
                offset = s2 * 2
                loc, code = _genIntBinary(resultLoc, src1Loc, Value(pos, t, 0, offset, True), "sub", "sbb", "({}) - ({})", operator.sub, False)
                return loc, result + code
            else:
                result += '''
                    ldi pl, lo({0})
                    ldi ph, hi({0})
                    ld b
                '''.format(s2)
                if src2Loc.isAligned():
                    result += 'inc pl\n'
                else:
                    result += '''
                        ldi pl, lo({0} + 1)
                        ldi ph, hi({0} + 1)
                    '''.format(s2)
                result += '''
                    ld a
                    shl a
                    shl b
                    adc a, 0
                '''
                if src1Loc.getIndirLevel() == 1:
                    result += '''
                        xor a, b
                        xor b, a
                        xor a, b
                        ldi pl, lo({0})
                        ldi ph, hi({0})
                        ld pl
                        sub pl, a
                        mov a, pl
                        ldi ph, hi({0} + 1)
                        ldi pl, lo({0} + 1)
                        ld pl
                        mov ph, a
                        mov a, pl
                        sbb a, b
                        mov b, a
                        mov a, ph
                    '''.format(s1)
                else:
                    # a:b - index
                    result += '''
                        mov ph, a
                        ldi a, lo({0})
                        sub b, a
                        ldi a, hi({0})
                        sbb ph, a
                        mov a, ph
                    '''.format(s1)
                result += '''
                    ldi pl, lo({0})
                    ldi ph, hi({0})
                    st a
                    inc pl
                '''.format(rs)
                if not resultLoc.isAligned():
                    result += '''
                        mov a, 0
                        adc ph, a
                    '''
                result += 'st b\n'
    else: # not isWord
        if src2Loc.getIndirLevel() == 0:
            pos = src1Loc.getPosition() - src2Loc.getPosition()
            s2 = s2.widen(src2Loc.getType().getSign())
            offset = s2 * memberSize
            loc, code = _genIntBinary(resultLoc, src1Loc, Value(pos, t, 0, offset, True), "sub", "sbb", "({}) - ({})", operator.sub, False)
            return loc, result + code
        if src2Loc.getType().getSign():
            raise SemanticError(src2Loc.getPosition(), "pointer arithmetic with s8 is not implemented")
        # s2.indirLevel == 1
        result += loadByte('b', src2Loc, 0)
        if memberSize == 1:
            if src1Loc.getIndirLevel() == 0:
                result += '''
                    ldi a, lo({0})
                    sub a, b
                    mov b, a
                    ldi a, hi({0})
                    sbb a, 0
                '''.format(src1Loc.getSource())
            else:
                result += '''
                    ldi pl, lo({0})
                    ldi ph, hi({0})
                    ld a
                    sub a, b
                    mov b, a
                    ldi pl, lo({0} + 1)
                    ldi ph, hi({0} + 1)
                    ld a
                    sbb a, 0
                '''.format(src1Loc.getSource())
        elif memberSize == 2:
            if src1Loc.getIndirLevel() == 0:
                result += '''
                    mov a, 0
                    mov pl, a
                    shl b
                    adc pl, a
                    ldi a, lo({0})
                    sub a, b
                    mov b, a
                    ldi a, hi({0})
                    sbb a, pl
                '''.format(src1Loc.getSource())
            else:
                result += '''
                    ldi pl, lo({0})
                    ldi ph, hi({0})
                    ld pl ; pl = p_l
                    mov a, 0
                    shl b ; b = i_l
                    adc a, 0
                    mov ph, a ; ph = i_h
                    mov a, pl ; a = p_l
                    sub a, b ; a = r_l
                    mov b, a ; b = r_l
                    mov a, 0
                    adc a, 0 ; a = c
                    add a, ph ; a = i_h + c
                    ldi pl, lo({0} + 1)
                    ldi ph, hi({0} + 1)
                    ld pl ; pl = p_h
                    sub pl, a
                    mov a, pl ; a = p_h - (i_h + c) = r_h
                '''.format(src1Loc.getSource())
        else:
            raise RuntimeError("Other sizes than 1 and 2 are not supported for pointer indexing")
        result += '''
            ldi pl, lo({0})
            ldi ph, hi({0})
            st b
        '''.format(resultLoc.getSource())
        if resultLoc.isAligned():
            result += 'inc pl\n'
        else:
            result += '''
                ldi pl, lo({0} + 1)
                ldi ph, hi({0} + 1)
            '''.format(resultLoc.getSource())
        result += 'st a\n'
    return resultLoc, result
コード例 #26
0
 def int_type(self, s):
     try:
         return IntType.parse(s)
     except ValueError as e:
         raise SemanticError(Position.fromAny(t), str(e))
コード例 #27
0
ファイル: binary.py プロジェクト: imihajlow/ccpu
def _genIntBinary(resultLoc, src1Loc, src2Loc, opLo, opHi, pyPattern, constLambda, carryIrrelevant):
    if resultLoc.getType().isUnknown():
        resultLoc = resultLoc.removeUnknown(src1Loc.getType())
    if resultLoc.getType() != src1Loc.getType():
        raise SemanticError(resultLoc.getPosition(),
            "Incompatible result and source types: {} and {}".format(resultLoc.getType(), src1Loc.getType()))
    if src1Loc.getType() != src2Loc.getType():
        raise SemanticError(resultLoc.getPosition(),
            "Incompatible source types: {} and {}".format(src1Loc.getType(), src2Loc.getType()))
    assert(resultLoc.getIndirLevel() == 1)
    l1 = src1Loc.getIndirLevel()
    l2 = src2Loc.getIndirLevel()
    assert(l1 == 0 or l1 == 1)
    assert(l2 == 0 or l2 == 1)
    if l1 == 0 and l2 == 0:
        raise RuntimeError("Case unhandled by ConstTransformer")
    t = resultLoc.getType()
    rs = resultLoc.getSource()
    s1 = src1Loc.getSource()
    s2 = src2Loc.getSource()
    result = "; {} = {} {}, {}\n".format(resultLoc, opLo, src1Loc, src2Loc)
    if t.getSize() <= 2:
        isWord = t.getSize() == 2
        if not isWord:
            assert(not s1.isRegister() or not s2.isRegister())
            result += loadByte('b', src1Loc, 0)
            result += loadByte('a', src2Loc, 0)
            result += f'''
                {opLo} b, a
                mov a, b
            '''
            return Value.register(resultLoc.getPosition(), t), result
        # now it's a word
        if l2 == 0:
            # var + const
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                ld b
            '''.format(src1Loc.getSource())
            result += incP(src1Loc.isAligned())
            c = src2Loc.getSource()
            result += loadByte('a', src2Loc, 0)
            result += f'''
                {opLo} b, a
                ld a
            '''
            result += loadByte('pl', src2Loc, 1)
            result += f'{opHi} a, pl\n'
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                st b
            '''.format(rs)
            if resultLoc.isAligned():
                result += '''
                    inc pl
                    st a
                '''
            else:
                result += f'''
                    ldi pl, lo({rs} + 1)
                    ldi ph, hi({rs} + 1)
                    st a
                '''
        elif l1 == 0:
            # const + var
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                ld a
            '''.format(src2Loc.getSource())
            if src2Loc.isAligned():
                result += 'inc pl\n'
            else:
                result += '''
                    ldi pl, lo({0} + 1)
                    ldi ph, hi({0} + 1)
                '''.format(src2Loc.getSource())
            result += loadByte('b', src1Loc, 0)
            result += f'''
                {opLo} b, a
                ld pl
            '''
            result += loadByte('a', src1Loc, 1)
            result += f'''
                {opHi} a, pl
                ldi pl, lo({rs})
                ldi ph, hi({rs})
                st b
            '''.format(rs)
            if resultLoc.isAligned():
                result += '''
                    inc pl
                    st a
                '''
            else:
                result += f'''
                    ldi pl, lo({rs} + 1)
                    ldi ph, hi({rs} + 1)
                    st a
                '''
        else:
            # var + var
            s1 = src1Loc.getSource()
            s2 = src2Loc.getSource()
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                ld b
                ldi pl, lo({1})
                ldi ph, hi({1})
                ld a
                {2} b, a
            '''.format(s1, s2, opLo)
            if isWord:
                result += '''
                    ldi pl, lo({0} + 1)
                    ldi ph, hi({0} + 1)
                    ld a
                    ldi pl, lo({1} + 1)
                    ldi ph, hi({1} + 1)
                    ld pl
                    {2} a, pl
                '''.format(s1, s2, opHi)
            result += '''
                ldi pl, lo({0})
                ldi ph, hi({0})
                st b
            '''.format(rs)
            if isWord:
                if resultLoc.isAligned():
                    result += '''
                        inc pl
                        st a
                    '''
                else:
                    result += '''
                        ldi pl, lo({0} + 1)
                        ldi ph, hi({0} + 1)
                        st a
                    '''.format(rs)
    else:
        # size > 2
        # This produces less size-efficient code than above, that's why it's not a general case.
        for offset in range(0, t.getSize(), 2):
            rest = t.getSize() - offset
            result += loadByte('a', src1Loc, offset)
            if rest > 1:
                if l1 == 0:
                    result += loadByte('b', src1Loc, offset + 1)
                else:
                    if (offset == 0 or carryIrrelevant) and src1Loc.isAligned():
                        # can trash flags if it's the first pair of bytes or if op is like and, or, xor
                        result += '''
                            inc pl
                            ld b
                        '''
                    else:
                        # must preserve flags
                        if src1Loc.isAligned():
                            result += f'''
                                ldi pl, lo({s1} + {offset + 1})
                                ld b
                            '''
                        else:
                            result += loadByte('b', src1Loc, offset + 1)
            result += loadByte('pl', src2Loc, offset)
            if offset == 0:
                result += f'{opLo} a, pl\n'
            else:
                result += f'{opHi} a, pl\n'
            result += f'''
                ldi pl, lo({rs} + {offset})
                ldi ph, hi({rs} + {offset})
                st a
            '''
            if rest > 1:
                result += loadByte('a', src2Loc, offset + 1)
                result += f'''
                    {opHi} b, a
                    ldi pl, lo({rs} + {offset + 1})
                    ldi ph, hi({rs} + {offset + 1})
                    st b
                '''
    return resultLoc, result
コード例 #28
0
 def generateStatement(self, t, curFn):
     pos = Position.fromAny(t)
     f, l = self.lineInfo.translatePosition(pos)
     result = self.backend.sourceFilename(f)
     result += self.backend.lineNumber(l)
     if t.data == 'assignment':
         l, r = t.children
         result += self.generateAssignment(l, r, curFn)
     elif t.data == 'decl_var':
         result += ""
     elif t.data == 'block':
         result += "".join(
             self.generateStatement(child, curFn) for child in t.children)
     elif t.data == 'conditional':
         result += self.generateConditional(
             t.children[0], t.children[1],
             t.children[2] if len(t.children) == 3 else None, curFn)
     elif t.data == 'while_loop':
         result += self.generateWhile(t.children[0], t.children[1], curFn)
     elif t.data == 'for_loop':
         result += self.generateFor(t.children[0], t.children[1],
                                    t.children[2], t.children[3], curFn)
     elif t.data == 'break_statement':
         if len(self.breakLabel) == 0:
             raise SemanticError(t.line, "Not in a loop")
         result += self.backend.genJump(self.breakLabel[0])
     elif t.data == 'continue_statement':
         if len(self.continueLabel) == 0:
             raise SemanticError(t.line, "Not in a loop")
         result += self.backend.genJump(self.continueLabel[0])
     elif t.data == 'function_call':
         result += self.generateFunctionCall(Position.fromAny(t),
                                             str(t.children[0]),
                                             t.children[1:], curFn)
     elif t.data == 'assignment_function':
         call = t.children[1]
         result += self.generateFunctionAssignment(
             Position.fromAny(t.children[0]), Position.fromAny(call),
             t.children[0], str(call.children[0]), call.children[1:], curFn)
     elif t.data == 'return_statement':
         dest = Value.variable(Position.fromAny(t),
                               labelname.getReturnName(curFn, False),
                               self.nameInfo.functions[curFn].retType)
         result += self.generateAssignment(dest, t.children[0],
                                           curFn) + self.backend.genReturn(
                                               curFn, self.useStack)
     elif t.data == 'empty_return_statement':
         result += self.backend.genReturn(curFn, self.useStack)
     elif t.data == 'return_fc_statement':
         call = t.children[0]
         dest = Value.variable(Position.fromAny(t),
                               labelname.getReturnName(curFn, False),
                               self.nameInfo.functions[curFn].retType)
         callCode = self.generateFunctionAssignment(Position.fromAny(t),
                                                    Position.fromAny(call),
                                                    dest,
                                                    str(call.children[0]),
                                                    call.children[1:],
                                                    curFn)
         retCode = self.backend.genReturn(curFn, self.useStack)
         result += callCode + retCode
     return result
コード例 #29
0
    def generateExpression(self, t, minTempVarIndex, resultLoc, curFn):
        '''
        Generate code to compute the expression.
        :param t: the expression tree
        :param minTempVarIndex: minimum index of a temp variable to use
        :param resultLoc: where to place the result. The result can be placed somewhere else (TODO).
        :param curFn: name of the current function.
        :return: the actual location of the result
        '''
        try:
            if isinstance(t, Value):
                return self.backend.genMove(resultLoc, t, True)
            else:
                ch = t.children
                if len(ch) == 1:
                    if isinstance(ch[0], Value):
                        argCode = ""
                        rv = ch[0]
                    else:
                        self.maxTempVarIndex = max(self.maxTempVarIndex,
                                                   minTempVarIndex)
                        rv, argCode = self.generateExpression(
                            ch[0], minTempVarIndex,
                            Value.variable(
                                Position.fromAny(ch[0]),
                                labelname.getTempName(minTempVarIndex, curFn)),
                            curFn)
                    resultLoc, myCode = self.backend.genUnary(
                        t.data, resultLoc, rv)
                    return resultLoc, argCode + myCode
                elif t.data == "type_cast":
                    if isinstance(ch[1], Value):
                        argCode = ""
                        rv = ch[1]
                    else:
                        self.maxTempVarIndex = max(self.maxTempVarIndex,
                                                   minTempVarIndex)
                        rv, argCode = self.generateExpression(
                            ch[1], minTempVarIndex,
                            Value.variable(
                                Position.fromAny(ch[1]),
                                labelname.getTempName(minTempVarIndex, curFn)),
                            curFn)
                    resultLoc, myCode = self.backend.genCast(
                        resultLoc, ch[0], rv)
                    return resultLoc, argCode + myCode
                elif t.data == "arrow":
                    ptr = ch[0]
                    fields = ch[1:]
                    self.maxTempVarIndex = max(self.maxTempVarIndex,
                                               minTempVarIndex)
                    rv, argCode = self.generateExpression(
                        ptr, minTempVarIndex,
                        Value.variable(
                            Position.fromAny(ptr),
                            labelname.getTempName(minTempVarIndex, curFn)),
                        curFn)
                    offset, type = structure.getField(rv.getType().deref(),
                                                      fields)
                    if type.getIndirectionOffset() == 0:
                        resultLoc, derefCode = self.backend.genDeref(
                            resultLoc.withType(type), rv, offset)
                        return resultLoc, argCode + derefCode
                    elif type.getIndirectionOffset() == -1:
                        rv, offsetCode = self.backend.genAddPointerOffset(
                            resultLoc.withType(type), rv.withType(type),
                            offset)
                        return rv, argCode + offsetCode
                    else:
                        raise RuntimeError("Wrong indirection offset")
                elif t.data == "p_arrow":
                    ptr = ch[0]
                    fields = ch[1:]
                    self.maxTempVarIndex = max(self.maxTempVarIndex,
                                               minTempVarIndex)
                    rv, argCode = self.generateExpression(
                        ptr, minTempVarIndex,
                        resultLoc.withType(UnknownType()), curFn)
                    offset, type = structure.getField(rv.getType().deref(),
                                                      fields)
                    if type.getIndirectionOffset() < 0:
                        raise SemanticError(Position.fromAny(t),
                                            "Cannot get address")
                    rv, offsetCode = self.backend.genAddPointerOffset(
                        resultLoc.withType(PtrType(type)),
                        rv.withType(PtrType(type)), offset)
                    return rv, argCode + offsetCode
                elif len(ch) == 2:
                    hasFirstArg = False
                    if isinstance(ch[0], Value):
                        rv1 = ch[0]
                        argCode1 = ""
                    else:
                        self.maxTempVarIndex = max(self.maxTempVarIndex,
                                                   minTempVarIndex)
                        tmp0 = Value.variable(
                            Position.fromAny(ch[0]),
                            labelname.getTempName(minTempVarIndex, curFn))
                        rv1, argCode1 = self.generateExpression(
                            ch[0], minTempVarIndex, tmp0, curFn)
                        hasFirstArg = True

                    if isinstance(ch[1], Value):
                        rv2 = ch[1]
                        argCode2 = ""
                    else:
                        indexIncrement = 1 if hasFirstArg else 0
                        self.maxTempVarIndex = max(
                            self.maxTempVarIndex,
                            minTempVarIndex + indexIncrement)
                        tmp1 = Value.variable(
                            Position.fromAny(ch[1]),
                            labelname.getTempName(
                                minTempVarIndex + indexIncrement, curFn))
                        rv2, argCode2 = self.generateExpression(
                            ch[1], minTempVarIndex + indexIncrement, tmp1,
                            curFn)
                        if rv1.getSource().isRegister():
                            rv1, moveCode = self.backend.genMove(
                                tmp0, rv1, False)
                            argCode1 += moveCode

                    try:
                        resultLoc, myCode = self.backend.genBinary(
                            t.data, resultLoc, rv1, rv2, self)
                    except RegisterNotSupportedError as e:
                        if e.argNumber == 0:
                            rv1, moveCode = self.backend.genMove(
                                tmp0, rv1, False)
                            argCode1 += moveCode
                        elif e.argNumber == 1:
                            rv2, moveCode = self.backend.genMove(
                                tmp1, rv2, False)
                            argCode2 += moveCode
                        else:
                            raise
                        resultLoc, myCode = self.backend.genBinary(
                            t.data, resultLoc, rv1, rv2, self)
                    return resultLoc, argCode1 + argCode2 + myCode
                else:
                    raise RuntimeError("Too many children")
        except LookupError as e:
            raise SemanticError(Position.fromAny(t), str(e))
        except ValueError as e:
            raise SemanticError(Position.fromAny(t), str(e))
コード例 #30
0
ファイル: mul.py プロジェクト: imihajlow/ccpu
def genMul(resultLoc, src1Loc, src2Loc):
    if src1Loc.getType() != src2Loc.getType():
        raise SemanticError(src1Loc.getPosition() - src2Loc.getPosition(),
                            "multiplication types mismatch")
    t = src1Loc.getType()
    resultLoc = resultLoc.withType(t)
    if t.getSize() not in {1, 2, 4}:
        raise NatrixNotImplementedError(
            src1Loc.getPosition(),
            f"multiplication of {t.getSize() * 8}-bit integers is not implemented"
        )
    l1 = src1Loc.getIndirLevel()
    l2 = src2Loc.getIndirLevel()
    if l1 == 0 and l2 == 0:
        raise NotImplementedError("doing shit with pointers?")
    elif l1 == 0:
        s = src1Loc.getSource()
        if s.isNumber():
            return _genMulVC(resultLoc, src2Loc, int(s))
        else:
            raise NotImplementedError("doing shit with pointers?")
    elif l2 == 0:
        s = src2Loc.getSource()
        if s.isNumber():
            return _genMulVC(resultLoc, src1Loc, int(s))
        else:
            raise NotImplementedError("doing shit with pointers?")
    else:
        result = '; {} = {} * {}\n'.format(resultLoc, src1Loc, src2Loc)
        if t.getSize() == 2:
            result += copyW(src1Loc.getSource(), "__cc_r_a",
                            src1Loc.isAligned(), True)
            result += copyW(src2Loc.getSource(), "__cc_r_b",
                            src2Loc.isAligned(), True)
            result += call("__cc_mul_word")
            result += copyW("__cc_r_r", resultLoc.getSource(), True,
                            resultLoc.isAligned())
            return resultLoc, result
        elif t.getSize() == 1:
            result += loadByte('b', src1Loc, 0)
            result += loadByte('a', src2Loc, 0)
            result += '''
                ldi pl, lo(__cc_r_a)
                ldi ph, hi(__cc_r_a)
                st b
                ldi pl, lo(__cc_r_b)
                st a
            '''
            result += call("__cc_mul_byte")
            result += '''
                ldi pl, lo(__cc_r_r)
                ldi ph, hi(__cc_r_r)
                ld a
            '''
            return Value.register(
                src1Loc.getPosition() - src2Loc.getPosition(), t), result
        elif t.getSize() == 4:
            result += copyW(src1Loc.getSource(), "__cc_r_a",
                            src1Loc.isAligned(), True, 0)
            result += copyW(src1Loc.getSource(), "__cc_r_a",
                            src1Loc.isAligned(), True, 2)
            result += copyW(src2Loc.getSource(), "__cc_r_b",
                            src1Loc.isAligned(), True, 0)
            result += copyW(src2Loc.getSource(), "__cc_r_b",
                            src1Loc.isAligned(), True, 2)
            result += call("__cc_mul_dword")
            result += copyW("__cc_r_r", resultLoc.getSource(), True,
                            resultLoc.isAligned(), 0)
            result += copyW("__cc_r_r", resultLoc.getSource(), True,
                            resultLoc.isAligned(), 2)
            return resultLoc, result