示例#1
0
    def offset(self):
        """ If this is a constant access (e.g. A(1))
        return the offset in bytes from the beginning of the
        variable in memory.

        Otherwise, if it's not constant (e.g. A(i))
        returns None
        """
        if self.scope == SCOPE.parameter:
            return None

        offset = 0
        # Now we must typecast each argument to a u16 (POINTER) type
        # i is the dimension ith index, b is the bound
        for i, b in zip(self.arglist, self.entry.bounds):
            tmp = i.children[0]
            if check.is_number(tmp) or check.is_const(tmp):
                if offset is not None:
                    offset = offset * b.count + tmp.value
            else:
                offset = None
                break

        if offset is not None:
            offset *= self.type_.size

        return offset
示例#2
0
    def make_node(cls, id_: str, arglist: SymbolARGLIST, lineno: int, filename: str) -> Optional['SymbolARRAYACCESS']:
        """ Creates an array access. A(x1, x2, ..., xn)
        """
        assert isinstance(arglist, SymbolARGLIST)
        variable = gl.SYMBOL_TABLE.access_array(id_, lineno)
        if variable is None:
            return None

        if variable.scope != SCOPE.parameter:
            if len(variable.bounds) != len(arglist):
                errmsg.error(lineno, "Array '%s' has %i dimensions, not %i" %
                             (variable.name, len(variable.bounds), len(arglist)))
                return None

            # Checks for array subscript range if the subscript is constant
            # e.g. A(1) is a constant subscript access
            btype = gl.SYMBOL_TABLE.basic_types[gl.BOUND_TYPE]
            for i, b in zip(arglist, variable.bounds):
                lower_bound = NUMBER(b.lower, type_=btype, lineno=lineno)

                if check.is_number(i.value) or check.is_const(i.value):
                    val = i.value.value
                    if val < b.lower or val > b.upper:
                        errmsg.warning(lineno, "Array '%s' subscript out of range" % id_)

                i.value = BINARY.make_node('MINUS',
                                           TYPECAST.make_node(btype, i.value, lineno),
                                           lower_bound, lineno, func=lambda x, y: x - y,
                                           type_=btype)
        else:
            btype = gl.SYMBOL_TABLE.basic_types[gl.BOUND_TYPE]
            for arg in arglist:
                arg.value = TYPECAST.make_node(btype, arg.value, arg.value.lineno)

        # Returns the variable entry and the node
        return cls(variable, arglist, lineno, filename)
示例#3
0
    def make_node(cls, new_type, node, lineno):
        """ Creates a node containing the type cast of
        the given one. If new_type == node.type, then
        nothing is done, and the same node is
        returned.

        Returns None on failure (and calls syntax_error)
        """
        assert isinstance(new_type, SymbolTYPE)

        # None (null) means the given AST node is empty (usually an error)
        if node is None:
            return None  # Do nothing. Return None

        assert isinstance(node, Symbol), '<%s> is not a Symbol' % node
        # The source and dest types are the same
        if new_type == node.type_:
            return node  # Do nothing. Return as is

        # TODO: Create a base scalar type
        if isinstance(node, SymbolVARARRAY):
            if new_type.size == node.type_.size and TYPE.string not in (new_type, node.type_):
                return node

            error(lineno, "Array {} type does not match parameter type".format(node.name))
            return None

        STRTYPE = TYPE.string
        # Typecasting, at the moment, only for number
        if node.type_ == STRTYPE:
            error(lineno, 'Cannot convert string to a value. Use VAL() function')
            return None

        # Converting from string to number is done by STR
        if new_type == STRTYPE:
            error(lineno, 'Cannot convert value to string. Use STR() function')
            return None

        # If the given operand is a constant, perform a static typecast
        if check.is_CONST(node):
            node.expr = cls(new_type, node.expr, lineno)
            return node

        if not check.is_number(node) and not check.is_const(node):
            return cls(new_type, node, lineno)

        # It's a number. So let's convert it directly
        if check.is_const(node):
            node = SymbolNUMBER(node.value, node.lineno, node.type_)

        if new_type.is_basic and not TYPE.is_integral(new_type):  # not an integer
            node.value = float(node.value)
        else:  # It's an integer
            new_val = (int(node.value) & ((1 << (8 * new_type.size)) - 1))  # Mask it

            if node.value >= 0 and node.value != new_val:
                errmsg.warning_conversion_lose_digits(node.lineno)
                node.value = new_val
            elif node.value < 0 and (1 << (new_type.size * 8)) + \
                    node.value != new_val:  # Test for positive to negative coercion
                errmsg.warning_conversion_lose_digits(node.lineno)
                node.value = new_val - (1 << (new_type.size * 8))

        node.type_ = new_type
        return node
示例#4
0
 def visit_CONST(self, node):
     if chk.is_number(node.expr) or chk.is_const(node.expr):
         yield node.expr
     else:
         yield node
示例#5
0
    def make_node(cls, operator, left, right, lineno, func=None,
                  type_=None):
        """ Creates a binary node for a binary operation,
            e.g. A + 6 => '+' (A, 6) in prefix notation.

            Parameters:
            -operator: the binary operation token. e.g. 'PLUS' for A + 6
            -left: left operand
            -right: right operand
            -func: is a lambda function used when constant folding is applied
            -type_: resulting type (to enforce it).

            If no type_ is specified the resulting one will be guessed.
        """
        if left is None or right is None:
            return None

        a, b = left, right  # short form names
        # Check for constant non-numeric operations
        c_type = check.common_type(a, b)  # Resulting operation type or None
        if c_type:  # there must be a common type for a and b
            if check.is_numeric(a, b) and (check.is_const(a) or check.is_number(a)) and \
                    (check.is_const(b) or check.is_number(b)):
                if func is not None:
                    a = SymbolTYPECAST.make_node(c_type, a, lineno)  # ensure type
                    b = SymbolTYPECAST.make_node(c_type, b, lineno)  # ensure type
                    return SymbolNUMBER(func(a.value, b.value), type_=type_, lineno=lineno)

            if check.is_static(a, b):
                a = SymbolTYPECAST.make_node(c_type, a, lineno)  # ensure type
                b = SymbolTYPECAST.make_node(c_type, b, lineno)  # ensure type
                return SymbolCONST(cls(operator, a, b, lineno, type_=type_, func=func), lineno=lineno)

        if operator in {'BNOT', 'BAND', 'BOR', 'BXOR', 'NOT', 'AND', 'OR',
                        'XOR', 'MINUS', 'MULT', 'DIV', 'SHL', 'SHR'} and \
                not check.is_numeric(a, b):
            errmsg.error(lineno, 'Operator %s cannot be used with STRINGS' % operator)
            return None

        if check.is_string(a, b) and func is not None:  # Are they STRING Constants?
            if operator == 'PLUS':
                return SymbolSTRING(func(a.value, b.value), lineno)

            return SymbolNUMBER(int(func(a.text, b.text)), type_=TYPE.ubyte,
                                lineno=lineno)  # Convert to u8 (boolean)

        if operator in ('BNOT', 'BAND', 'BOR', 'BXOR'):
            if TYPE.is_decimal(c_type):
                c_type = TYPE.long_

        if a.type_ != b.type_ and TYPE.string in (a.type_, b.type_):
            c_type = a.type_  # Will give an error based on the fist operand

        if operator not in ('SHR', 'SHL'):
            a = SymbolTYPECAST.make_node(c_type, a, lineno)
            b = SymbolTYPECAST.make_node(c_type, b, lineno)

        if a is None or b is None:
            return None

        if type_ is None:
            if operator in ('LT', 'GT', 'EQ', 'LE', 'GE', 'NE', 'AND', 'OR',
                            'XOR', 'NOT'):
                type_ = TYPE.ubyte  # Boolean type
            else:
                type_ = c_type

        return cls(operator, a, b, type_=type_, lineno=lineno)