Example #1
0
    def make_node(cls, lineno, s, lower, upper):
        """ Creates a node for a string slice. S is the string expression Tree.
        Lower and upper are the bounds, if lower & upper are constants, and
        s is also constant, then a string constant is returned.

        If lower > upper, an empty string is returned.
        """
        if lower is None or upper is None or s is None:
            return None

        if not check_type(lineno, Type.string, s):
            return None

        lo = up = None
        base = NUMBER(api.config.OPTIONS.string_base.value, lineno=lineno)
        lower = TYPECAST.make_node(
            gl.SYMBOL_TABLE.basic_types[gl.STR_INDEX_TYPE],
            BINARY.make_node('MINUS',
                             lower,
                             base,
                             lineno=lineno,
                             func=lambda x, y: x - y), lineno)
        upper = TYPECAST.make_node(
            gl.SYMBOL_TABLE.basic_types[gl.STR_INDEX_TYPE],
            BINARY.make_node('MINUS',
                             upper,
                             base,
                             lineno=lineno,
                             func=lambda x, y: x - y), lineno)

        if lower is None or upper is None:
            return None

        if is_number(lower):
            lo = lower.value
            if lo < gl.MIN_STRSLICE_IDX:
                lower.value = lo = gl.MIN_STRSLICE_IDX

        if is_number(upper):
            up = upper.value
            if up > gl.MAX_STRSLICE_IDX:
                upper.value = up = gl.MAX_STRSLICE_IDX

        if is_number(lower, upper):
            if lo > up:
                return STRING('', lineno)

            if s.token == 'STRING':  # A constant string? Recalculate it now
                up += 1
                st = s.value.ljust(up)  # Procrustean filled (right)
                return STRING(st[lo:up], lineno)

            # a$(0 TO INF.) = a$
            if lo == gl.MIN_STRSLICE_IDX and up == gl.MAX_STRSLICE_IDX:
                return s

        return cls(s, lower, upper, lineno)
Example #2
0
    def make_node(cls, lineno, operator, operand, func=None, type_=None):
        """ Creates a node for a unary operation. E.g. -x or LEN(a$)

        Parameters:
            -func: lambda function used on constant folding when possible
            -type_: the resulting type (by default, the same as the argument).
                For example, for LEN (str$), result type is 'u16'
                and arg type is 'string'
        """
        assert type_ is None or isinstance(type_, SymbolTYPE)

        if func is not None:  # Try constant-folding
            if is_number(operand):  # e.g. ABS(-5)
                return SymbolNUMBER(func(operand.value), lineno=lineno)
            elif is_string(operand):  # e.g. LEN("a")
                return SymbolSTRING(func(operand.text), lineno=lineno)

        if type_ is None:
            type_ = operand.type_

        if operator == 'MINUS':
            if not type_.is_signed:
                type_ = type_.to_signed()
                operand = SymbolTYPECAST.make_node(type_, operand, lineno)
        elif operator == 'NOT':
            type_ = TYPE.ubyte

        return cls(operator, operand, lineno, type_)
Example #3
0
    def visit_IF(self, node):
        expr_ = (yield ToVisit(node.children[0]))
        then_ = (yield ToVisit(node.children[1]))
        else_ = (yield ToVisit(node.children[2])) if len(
            node.children) == 3 else self.NOP

        if self.O_LEVEL >= 1:
            if chk.is_null(then_, else_):
                api.errmsg.warning_empty_if(node.lineno)
                yield self.NOP
                return

            block_accessed = chk.is_block_accessed(
                then_) or chk.is_block_accessed(else_)
            if not block_accessed and chk.is_number(
                    expr_):  # constant condition
                if expr_.value:  # always true (then_)
                    yield then_
                else:  # always false (else_)
                    yield else_
                return

            if chk.is_null(else_) and len(node.children) == 3:
                node.children.pop()  # remove empty else
                yield node
                return

        for i in range(len(node.children)):
            node.children[i] = (expr_, then_, else_)[i]
        yield node
Example #4
0
    def make_node(cls, id_, arglist, lineno):
        """ 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 len(variable.bounds) != len(arglist):
            syntax_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
        for i, b in zip(arglist, variable.bounds):
            btype = gl.SYMBOL_TABLE.basic_types[gl.BOUND_TYPE]
            lower_bound = NUMBER(b.lower, type_=btype, lineno=lineno)
            i.value = BINARY.make_node('MINUS',
                                       TYPECAST.make_node(
                                           btype, i.value, lineno),
                                       lower_bound,
                                       lineno,
                                       func=lambda x, y: x - y,
                                       type_=btype)
            if is_number(i.value) or is_const(i.value):
                val = i.value.value
                if val < 0 or val > b.count:
                    warning(lineno, "Array '%s' subscript out of range" % id_)

        # Returns the variable entry and the node
        return cls(variable, arglist, lineno)
Example #5
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
        """
        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 is_number(tmp) or is_const(tmp):
                if offset is not None:
                    offset = offset * b.count + tmp.value
            else:
                offset = None
                break

        if offset is not None:
            offset = TYPE.size(gl.SIZE_TYPE) + TYPE.size(gl.BOUND_TYPE) * len(
                self.arglist) + offset * self.type_.size

        return offset
Example #6
0
    def visit_WHILE(self, node):
        expr_ = (yield node.children[0])
        body_ = (yield node.children[1])

        if self.O_LEVEL >= 1:
            if chk.is_number(
                    expr_
            ) and not expr_.value and not chk.is_block_accessed(body_):
                yield self.NOP
                return

        for i, child in enumerate((expr_, body_)):
            node.children[i] = child
        yield node
Example #7
0
    def make_node(cls, lineno, fname, func=None, type_=None, *operands):
        """ Creates a node for a unary operation. E.g. -x or LEN(a$)

        Parameters:
            -func: function used on constant folding when possible
            -type_: the resulting type (by default, the same as the argument).
                For example, for LEN (str$), result type is 'u16'
                and arg type is 'string'
        """
        if func is not None and len(operands) == 1:  # Try constant-folding
            if is_number(operands[0]) or is_string(
                    operands[0]):  # e.g. ABS(-5)
                return SymbolNUMBER(func(operands[0].value),
                                    type_=type_,
                                    lineno=lineno)

        return cls(lineno, fname, type_, *operands)
Example #8
0
    def visit_FOR(self, node):
        from_ = (yield node.children[1])
        to_ = (yield node.children[2])
        step_ = (yield node.children[3])
        body_ = (yield node.children[4])

        if self.O_LEVEL > 0 and chk.is_number(
                from_, to_, step_) and not chk.is_block_accessed(body_):
            if from_ > to_ and step_ > 0:
                yield self.NOP
                return
            if from_ < to_ and step_ < 0:
                yield self.NOP
                return

        for i, child in enumerate((from_, to_, step_, body_), start=1):
            node.children[i] = child
        yield node
Example #9
0
 def visit_CONST(self, node):
     if chk.is_number(node.expr) or chk.is_const(node.expr):
         yield node.expr
     else:
         yield node
Example #10
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

            syntax_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:
            syntax_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:
            syntax_error(
                lineno, 'Cannot convert value to string. '
                'Use STR() function')
            return None

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

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

        # It's a number. So let's convert it directly
        if 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
Example #11
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 = common_type(a, b)  # Resulting operation type or None
        if c_type:  # there must be a common type for a and b
            if is_numeric(a, b) and (is_const(a) or is_number(a)) and \
                    (is_const(b) or 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 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 is_numeric(a, b):
            syntax_error(lineno,
                         'Operator %s cannot be used with STRINGS' % operator)
            return None

        if 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)