Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ def check_call_arguments(lineno, id_, args):
return False

for arg, param in zip(args, entry.params):
if arg.class_ in (CLASS.var, CLASS.array) and param.class_ != arg.class_:
syntax_error(lineno, "Invalid argument '{}'".format(arg.value))
return None

if not arg.typecast(param.type_):
return False

Expand Down
7 changes: 7 additions & 0 deletions api/errmsg.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,10 @@ def syntax_error_cannot_assign_not_a_var(lineno, id_):
# ----------------------------------------
def syntax_error_address_must_be_constant(lineno):
syntax_error(lineno, 'Address must be a numeric constant expression')


# ----------------------------------------
# Cannot pass an array by value
# ----------------------------------------
def syntax_error_cannot_pass_array_by_value(lineno, id_):
syntax_error(lineno, "Array parameter '%s' must be passed ByRef" % id_)
5 changes: 5 additions & 0 deletions api/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,8 @@ def __init__(self, symbol):
class InvalidBuiltinFunctionError(Error):
def __init__(self, fname):
self.msg = "Invalid BUILTIN function '%s'" % fname


class InternalError:
def __init__(self, msg):
self.msg = msg
11 changes: 9 additions & 2 deletions api/symboltable.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,17 +685,24 @@ def declare_label(self, id_, lineno):
entry.type_ = self.basic_types[global_.PTR_TYPE]
return entry

def declare_param(self, id_, lineno, type_=None):
def declare_param(self, id_, lineno, type_=None, is_array=False):
""" Declares a parameter
Check if entry.declared is False. Otherwise raises an error.
"""
if not self.check_is_undeclared(id_, lineno, classname='parameter',
scope=self.current_scope, show_error=True):
return None

entry = self.declare(id_, lineno, symbols.PARAMDECL(id_, lineno, type_))
if is_array:
entry = self.declare(id_, lineno, symbols.VARARRAY(id_, symbols.BOUNDLIST(), lineno, None, type_))
entry.callable = True
entry.scope = SCOPE.parameter
else:
entry = self.declare(id_, lineno, symbols.PARAMDECL(id_, lineno, type_))

if entry is None:
return

entry.declared = True
if entry.type_.implicit:
warning_implicit_type(lineno, id_, type_)
Expand Down
12 changes: 7 additions & 5 deletions arch/zx48k/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from api.errors import InvalidLoopError
from api.errors import InvalidOperatorError
from api.errors import InvalidBuiltinFunctionError
from api.errors import InternalError

from . import backend
from .backend.__float import _float
Expand Down Expand Up @@ -300,17 +301,18 @@ def visit_LETARRAY(self, node):
if scope == SCOPE.global_:
self.ic_astore(arr.type_, arr.entry.mangled, node.children[1].t)
elif scope == SCOPE.parameter:
self.ic_pastore(arr.type_, arr.entry.offset, node.children[1].t)
# HINT: Arrays are always passed ByREF
self.ic_pastore(arr.type_, '*{}'.format(arr.entry.offset), node.children[1].t)
elif scope == SCOPE.local:
self.ic_pastore(arr.type_, -arr.entry.offset, node.children[1].t)
else:
name = arr.entry.data_label
if scope == SCOPE.global_:
self.ic_store(arr.type_, '%s + %i' % (name, arr.offset), node.children[1].t)
elif scope == SCOPE.parameter:
self.ic_pstore(arr.type_, arr.entry.offset - arr.offset, node.children[1].t)
elif scope == SCOPE.local:
self.ic_pstore(arr.type_, -(arr.entry.offset - arr.offset), node.children[1].t)
else:
raise InternalError("Invalid scope {} for variable '{}'".format(scope, arr.entry.name))

def visit_LETSUBSTR(self, node):
yield node.children[3]
Expand Down Expand Up @@ -1345,12 +1347,12 @@ def visit_FUNCTION(self, node):
# if self.O_LEVEL > 1:
# return

if local_var.class_ == CLASS.array and local_var.scope != SCOPE.global_:
if local_var.class_ == CLASS.array and local_var.scope == SCOPE.local:
l = [len(local_var.bounds) - 1] + [x.count for x in local_var.bounds[1:]] # TODO Check this
q = []
for x in l:
q.append('%02X' % (x & 0xFF))
q.append('%02X' % (x >> 8))
q.append('%02X' % ((x & 0xFF) >> 8))

q.append('%02X' % local_var.type_.size)
r = []
Expand Down
3 changes: 2 additions & 1 deletion symbols/argument.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .var import SymbolVAR
from api.config import OPTIONS
from api.constants import SCOPE
from api.constants import CLASS


class SymbolARGUMENT(Symbol):
Expand Down Expand Up @@ -56,7 +57,7 @@ def type_(self):

@property
def class_(self):
return self.value.class_
return getattr(self.value, 'class_', CLASS.unknown)

@property
def byref(self):
Expand Down
44 changes: 25 additions & 19 deletions symbols/arrayaccess.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from api.errmsg import warning
from api.check import is_number
from api.check import is_const
from api.constants import SCOPE

from .call import SymbolCALL
from .number import SymbolNUMBER as NUMBER
Expand All @@ -33,11 +34,12 @@ class SymbolARRAYACCESS(SymbolCALL):
it only returns the pointer address to the element).

Parameters:
entry will be the symboltable entry.
entry will be the symbol table entry.
Arglist a SymbolARGLIST instance.
"""
def __init__(self, entry, arglist, lineno):
super(SymbolARRAYACCESS, self).__init__(entry, arglist, lineno)
assert all(gl.BOUND_TYPE == x.type_.type_ for x in arglist), "Invalid type for array index"

@property
def entry(self):
Expand Down Expand Up @@ -77,6 +79,9 @@ def offset(self):
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
Expand All @@ -103,24 +108,25 @@ def make_node(cls, id_, arglist, 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_)
if variable.scope != SCOPE.parameter:
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)
4 changes: 3 additions & 1 deletion symbols/call.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from .symbol_ import Symbol
from .function import SymbolFUNCTION
from .arglist import SymbolARGLIST
from .argument import SymbolARGUMENT
from .var import SymbolVAR
from .type_ import Type

Expand All @@ -28,13 +29,14 @@ class SymbolCALL(Symbol):

Parameters:
id_: The symbol table entry
arglist: a SymbolArglist instance
arglist: a SymbolARGLIST instance
lineno: source code line where this call was made
"""

def __init__(self, entry, arglist, lineno):
super(SymbolCALL, self).__init__()
assert isinstance(lineno, int)
assert all(isinstance(x, SymbolARGUMENT) for x in arglist)
self.entry = entry
self.args = arglist # Func. call / array access
self.lineno = lineno
Expand Down
2 changes: 1 addition & 1 deletion symbols/paramlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def make_node(cls, node, *params):
(declared in a function declaration)
Parameters:
-node: A SymbolPARAMLIST instance or None
-params: SymbolPARAMDECL insances
-params: SymbolPARAMDECL instances
"""
if node is None:
node = cls()
Expand Down
9 changes: 9 additions & 0 deletions symbols/typecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .type_ import SymbolTYPE
from .type_ import Type as TYPE
from .number import SymbolNUMBER
from .vararray import SymbolVARARRAY

from api.errmsg import syntax_error
from api import errmsg
Expand Down Expand Up @@ -60,6 +61,14 @@ def make_node(cls, new_type, node, lineno):
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:
Expand Down
3 changes: 2 additions & 1 deletion symbols/vararray.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import api.global_ as gl
from api.constants import TYPE
from api.constants import CLASS
from api.constants import SCOPE
from .var import SymbolVAR
from .boundlist import SymbolBOUNDLIST

Expand Down Expand Up @@ -42,7 +43,7 @@ def count(self):

@property
def size(self):
return self.count * self.type_.size
return self.count * self.type_.size if self.scope != SCOPE.parameter else TYPE.size(gl.PTR_TYPE)

@property
def memsize(self):
Expand Down
Loading