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
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)
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
def visit_CONST(self, node): if chk.is_number(node.expr) or chk.is_const(node.expr): yield node.expr else: yield node
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)