Skip to content

Commit 3210892

Browse files
authored
Merge pull request #275 from boriel/feature/array_as_param
Feature/array as param
2 parents 6f49ec1 + 4503da1 commit 3210892

27 files changed

Lines changed: 1471 additions & 77 deletions

api/check.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ def check_call_arguments(lineno, id_, args):
105105
return False
106106

107107
for arg, param in zip(args, entry.params):
108+
if arg.class_ in (CLASS.var, CLASS.array) and param.class_ != arg.class_:
109+
syntax_error(lineno, "Invalid argument '{}'".format(arg.value))
110+
return None
111+
108112
if not arg.typecast(param.type_):
109113
return False
110114

api/errmsg.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,10 @@ def syntax_error_cannot_assign_not_a_var(lineno, id_):
194194
# ----------------------------------------
195195
def syntax_error_address_must_be_constant(lineno):
196196
syntax_error(lineno, 'Address must be a numeric constant expression')
197+
198+
199+
# ----------------------------------------
200+
# Cannot pass an array by value
201+
# ----------------------------------------
202+
def syntax_error_cannot_pass_array_by_value(lineno, id_):
203+
syntax_error(lineno, "Array parameter '%s' must be passed ByRef" % id_)

api/errors.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,8 @@ def __init__(self, symbol):
4343
class InvalidBuiltinFunctionError(Error):
4444
def __init__(self, fname):
4545
self.msg = "Invalid BUILTIN function '%s'" % fname
46+
47+
48+
class InternalError:
49+
def __init__(self, msg):
50+
self.msg = msg

api/symboltable.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -685,17 +685,24 @@ def declare_label(self, id_, lineno):
685685
entry.type_ = self.basic_types[global_.PTR_TYPE]
686686
return entry
687687

688-
def declare_param(self, id_, lineno, type_=None):
688+
def declare_param(self, id_, lineno, type_=None, is_array=False):
689689
""" Declares a parameter
690690
Check if entry.declared is False. Otherwise raises an error.
691691
"""
692692
if not self.check_is_undeclared(id_, lineno, classname='parameter',
693693
scope=self.current_scope, show_error=True):
694694
return None
695695

696-
entry = self.declare(id_, lineno, symbols.PARAMDECL(id_, lineno, type_))
696+
if is_array:
697+
entry = self.declare(id_, lineno, symbols.VARARRAY(id_, symbols.BOUNDLIST(), lineno, None, type_))
698+
entry.callable = True
699+
entry.scope = SCOPE.parameter
700+
else:
701+
entry = self.declare(id_, lineno, symbols.PARAMDECL(id_, lineno, type_))
702+
697703
if entry is None:
698704
return
705+
699706
entry.declared = True
700707
if entry.type_.implicit:
701708
warning_implicit_type(lineno, id_, type_)

arch/zx48k/translator.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from api.errors import InvalidLoopError
2121
from api.errors import InvalidOperatorError
2222
from api.errors import InvalidBuiltinFunctionError
23+
from api.errors import InternalError
2324

2425
from . import backend
2526
from .backend.__float import _float
@@ -300,17 +301,18 @@ def visit_LETARRAY(self, node):
300301
if scope == SCOPE.global_:
301302
self.ic_astore(arr.type_, arr.entry.mangled, node.children[1].t)
302303
elif scope == SCOPE.parameter:
303-
self.ic_pastore(arr.type_, arr.entry.offset, node.children[1].t)
304+
# HINT: Arrays are always passed ByREF
305+
self.ic_pastore(arr.type_, '*{}'.format(arr.entry.offset), node.children[1].t)
304306
elif scope == SCOPE.local:
305307
self.ic_pastore(arr.type_, -arr.entry.offset, node.children[1].t)
306308
else:
307309
name = arr.entry.data_label
308310
if scope == SCOPE.global_:
309311
self.ic_store(arr.type_, '%s + %i' % (name, arr.offset), node.children[1].t)
310-
elif scope == SCOPE.parameter:
311-
self.ic_pstore(arr.type_, arr.entry.offset - arr.offset, node.children[1].t)
312312
elif scope == SCOPE.local:
313313
self.ic_pstore(arr.type_, -(arr.entry.offset - arr.offset), node.children[1].t)
314+
else:
315+
raise InternalError("Invalid scope {} for variable '{}'".format(scope, arr.entry.name))
314316

315317
def visit_LETSUBSTR(self, node):
316318
yield node.children[3]
@@ -1345,12 +1347,12 @@ def visit_FUNCTION(self, node):
13451347
# if self.O_LEVEL > 1:
13461348
# return
13471349

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

13551357
q.append('%02X' % local_var.type_.size)
13561358
r = []

symbols/argument.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from .var import SymbolVAR
1616
from api.config import OPTIONS
1717
from api.constants import SCOPE
18+
from api.constants import CLASS
1819

1920

2021
class SymbolARGUMENT(Symbol):
@@ -56,7 +57,7 @@ def type_(self):
5657

5758
@property
5859
def class_(self):
59-
return self.value.class_
60+
return getattr(self.value, 'class_', CLASS.unknown)
6061

6162
@property
6263
def byref(self):

symbols/arrayaccess.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from api.errmsg import warning
1515
from api.check import is_number
1616
from api.check import is_const
17+
from api.constants import SCOPE
1718

1819
from .call import SymbolCALL
1920
from .number import SymbolNUMBER as NUMBER
@@ -33,11 +34,12 @@ class SymbolARRAYACCESS(SymbolCALL):
3334
it only returns the pointer address to the element).
3435
3536
Parameters:
36-
entry will be the symboltable entry.
37+
entry will be the symbol table entry.
3738
Arglist a SymbolARGLIST instance.
3839
"""
3940
def __init__(self, entry, arglist, lineno):
4041
super(SymbolARRAYACCESS, self).__init__(entry, arglist, lineno)
42+
assert all(gl.BOUND_TYPE == x.type_.type_ for x in arglist), "Invalid type for array index"
4143

4244
@property
4345
def entry(self):
@@ -77,6 +79,9 @@ def offset(self):
7779
Otherwise, if it's not constant (e.g. A(i))
7880
returns None
7981
"""
82+
if self.scope == SCOPE.parameter:
83+
return None
84+
8085
offset = 0
8186
# Now we must typecast each argument to a u16 (POINTER) type
8287
# i is the dimension ith index, b is the bound
@@ -103,24 +108,25 @@ def make_node(cls, id_, arglist, lineno):
103108
if variable is None:
104109
return None
105110

106-
if len(variable.bounds) != len(arglist):
107-
syntax_error(lineno, "Array '%s' has %i dimensions, not %i" %
108-
(variable.name, len(variable.bounds), len(arglist)))
109-
return None
110-
111-
# Checks for array subscript range if the subscript is constant
112-
# e.g. A(1) is a constant subscript access
113-
for i, b in zip(arglist, variable.bounds):
114-
btype = gl.SYMBOL_TABLE.basic_types[gl.BOUND_TYPE]
115-
lower_bound = NUMBER(b.lower, type_=btype, lineno=lineno)
116-
i.value = BINARY.make_node('MINUS',
117-
TYPECAST.make_node(btype, i.value, lineno),
118-
lower_bound, lineno, func=lambda x, y: x - y,
119-
type_=btype)
120-
if is_number(i.value) or is_const(i.value):
121-
val = i.value.value
122-
if val < 0 or val > b.count:
123-
warning(lineno, "Array '%s' subscript out of range" % id_)
111+
if variable.scope != SCOPE.parameter:
112+
if len(variable.bounds) != len(arglist):
113+
syntax_error(lineno, "Array '%s' has %i dimensions, not %i" %
114+
(variable.name, len(variable.bounds), len(arglist)))
115+
return None
116+
117+
# Checks for array subscript range if the subscript is constant
118+
# e.g. A(1) is a constant subscript access
119+
for i, b in zip(arglist, variable.bounds):
120+
btype = gl.SYMBOL_TABLE.basic_types[gl.BOUND_TYPE]
121+
lower_bound = NUMBER(b.lower, type_=btype, lineno=lineno)
122+
i.value = BINARY.make_node('MINUS',
123+
TYPECAST.make_node(btype, i.value, lineno),
124+
lower_bound, lineno, func=lambda x, y: x - y,
125+
type_=btype)
126+
if is_number(i.value) or is_const(i.value):
127+
val = i.value.value
128+
if val < 0 or val > b.count:
129+
warning(lineno, "Array '%s' subscript out of range" % id_)
124130

125131
# Returns the variable entry and the node
126132
return cls(variable, arglist, lineno)

symbols/call.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from .symbol_ import Symbol
1818
from .function import SymbolFUNCTION
1919
from .arglist import SymbolARGLIST
20+
from .argument import SymbolARGUMENT
2021
from .var import SymbolVAR
2122
from .type_ import Type
2223

@@ -28,13 +29,14 @@ class SymbolCALL(Symbol):
2829
2930
Parameters:
3031
id_: The symbol table entry
31-
arglist: a SymbolArglist instance
32+
arglist: a SymbolARGLIST instance
3233
lineno: source code line where this call was made
3334
"""
3435

3536
def __init__(self, entry, arglist, lineno):
3637
super(SymbolCALL, self).__init__()
3738
assert isinstance(lineno, int)
39+
assert all(isinstance(x, SymbolARGUMENT) for x in arglist)
3840
self.entry = entry
3941
self.args = arglist # Func. call / array access
4042
self.lineno = lineno

symbols/paramlist.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def make_node(cls, node, *params):
3434
(declared in a function declaration)
3535
Parameters:
3636
-node: A SymbolPARAMLIST instance or None
37-
-params: SymbolPARAMDECL insances
37+
-params: SymbolPARAMDECL instances
3838
"""
3939
if node is None:
4040
node = cls()

symbols/typecast.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .type_ import SymbolTYPE
1414
from .type_ import Type as TYPE
1515
from .number import SymbolNUMBER
16+
from .vararray import SymbolVARARRAY
1617

1718
from api.errmsg import syntax_error
1819
from api import errmsg
@@ -60,6 +61,14 @@ def make_node(cls, new_type, node, lineno):
6061
if new_type == node.type_:
6162
return node # Do nothing. Return as is
6263

64+
# TODO: Create a base scalar type
65+
if isinstance(node, SymbolVARARRAY):
66+
if new_type.size == node.type_.size and TYPE.string not in (new_type, node.type_):
67+
return node
68+
69+
syntax_error(lineno, "Array {} type does not match parameter type".format(node.name))
70+
return None
71+
6372
STRTYPE = TYPE.string
6473
# Typecasting, at the moment, only for number
6574
if node.type_ == STRTYPE:

0 commit comments

Comments
 (0)