Skip to content

Commit cfa09e7

Browse files
authored
Merge pull request #340 from boriel/feature/update_bound
Feature/update bound
2 parents 2f44c43 + 78a7fb6 commit cfa09e7

71 files changed

Lines changed: 8907 additions & 367 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/symboltable.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,6 @@ def declare_array(self, id_, lineno, type_, bounds, default_value=None, addr=Non
762762
entry.default_value = default_value
763763
entry.callable = True
764764
entry.class_ = CLASS.array
765-
entry.lbound_used = entry.ubound_used = False # Flag to true when LBOUND/UBOUND used somewhere in the code
766765
entry.addr = addr
767766

768767
__DEBUG__('Entry %s declared with class %s at scope %i' % (id_, CLASS.to_string(entry.class_),

arch/zx48k/backend/__init__.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -498,9 +498,9 @@ def _varx(ins):
498498

499499
def _vard(ins):
500500
""" Defines a memory space with a default set of bytes/words in hexadecimal
501-
(starting with a number) or literals (starting with #).
501+
(starting with an hex number) or literals (starting with #).
502502
Numeric values with more than 2 digits represents a WORD (2 bytes) value.
503-
E.g. '01' => 0, '001' => 1, 0 bytes
503+
E.g. '01' => 01h, '001' => 1, 0 bytes (0001h)
504504
Literal values starts with # (1 byte) or ## (2 bytes)
505505
E.g. '#label + 1' => (label + 1) & 0xFF
506506
'##(label + 1)' => (label + 1) & 0xFFFF
@@ -584,16 +584,29 @@ def _larrd(ins):
584584
- 1st param is offset of the local variable.
585585
- 2nd param is a list of bytes in hexadecimal corresponding to the index table
586586
- 3rd param is the size of elements in byte
587-
- 4rd param a list (might be empty) of byte to initialize the array with
587+
- 4th param is a list (might be empty) of byte to initialize the array with
588+
- 5th param is a list (might be empty or 2 elements) of [lbound, ubound] labels.
588589
"""
589590
output = []
590591

591592
label = tmp_label()
592593
offset = int(ins.quad[1])
593594
elements_size = ins.quad[3]
594595
AT_END.extend(_vard(Quad('vard', label, ins.quad[2])))
595-
must_initialize = ins.quad[4] != '[]'
596596

597+
bounds = eval(ins.quad[5])
598+
if not isinstance(bounds, list) or len(bounds) not in (0, 2):
599+
raise InvalidIC(ins.quad, 'Bounds list length must be 0 or 2, not %s' % ins.quad[5])
600+
601+
if bounds:
602+
output.extend([
603+
'ld hl, %s' % bounds[1],
604+
'push hl',
605+
'ld hl, %s' % bounds[0],
606+
'push hl',
607+
])
608+
609+
must_initialize = ins.quad[4] != '[]'
597610
if must_initialize:
598611
label2 = tmp_label()
599612
AT_END.extend(_vard(Quad('vard', label2, ins.quad[4])))
@@ -608,10 +621,11 @@ def _larrd(ins):
608621
'ld bc, %s' % elements_size,
609622
])
610623

624+
suffix = '_WITH_BOUNDS' if bounds else ''
611625
if must_initialize:
612-
output.append('call __ALLOC_INITIALIZED_LOCAL_ARRAY')
626+
output.append('call __ALLOC_INITIALIZED_LOCAL_ARRAY' + suffix)
613627
else:
614-
output.append('call __ALLOC_LOCAL_ARRAY')
628+
output.append('call __ALLOC_LOCAL_ARRAY' + suffix)
615629

616630
REQUIRES.add('arrayalloc.asm')
617631
return output
@@ -2137,7 +2151,7 @@ def __str__(self):
21372151
'vard': [2, _vard], # Like the above but with a list of items (chars, bytes or words, hex)
21382152
'lvarx': [3, _lvarx], # Initializes a local variable. lvard X, (list of bytes): Initializes variable at offset X
21392153
'lvard': [2, _lvard], # Initializes a local variable. lvard X, (list of bytes): Initializes variable at offset X
2140-
'larrd': [4, _larrd], # Initializes a local array
2154+
'larrd': [5, _larrd], # Initializes a local array
21412155
'memcopy': [3, _memcopy], # Copies a block of param 3 bytes of memory from param 2 addr to param 1 addr.
21422156

21432157
'bandu8': [3, _band8], # x = A & B

arch/zx48k/translator.py

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from api.errors import InvalidOperatorError
2222
from api.errors import InvalidBuiltinFunctionError
2323
from api.errors import InternalError
24+
from zxbpp import zxbpp
2425

2526
from . import backend
2627
from .backend.__float import _float
@@ -36,6 +37,7 @@
3637
'FunctionTranslator']
3738

3839
JumpTable = namedtuple('JumpTable', ('label', 'addresses'))
40+
LabelledData = namedtuple('LabelledData', ('label', 'data'))
3941

4042

4143
class Translator(TranslatorVisitor):
@@ -1092,6 +1094,17 @@ def visit_ARRAYDECL(self, node):
10921094
if self.O_LEVEL > 1:
10931095
return
10941096

1097+
bound_ptrs = [] # Bound tables pointers (empty if not used)
1098+
lbound_label = entry.mangled + '.__LBOUND__'
1099+
ubound_label = entry.mangled + '.__UBOUND__'
1100+
1101+
if entry.lbound_used or entry.ubound_used:
1102+
bound_ptrs = ['0', '0'] # NULL by default
1103+
if entry.lbound_used:
1104+
bound_ptrs[0] = lbound_label
1105+
if entry.ubound_used:
1106+
bound_ptrs[1] = ubound_label
1107+
10951108
data_label = entry.data_label
10961109
idx_table_label = backend.tmp_label()
10971110
l = ['%04X' % (len(node.bounds) - 1)] # Number of dimensions - 1
@@ -1118,21 +1131,23 @@ def visit_ARRAYDECL(self, node):
11181131

11191132
if entry.addr:
11201133
self.ic_varx(entry.data_ptr_label, gl.PTR_TYPE, [self.traverse_const(entry.addr)])
1134+
if bound_ptrs:
1135+
self.ic_data(gl.PTR_TYPE, bound_ptrs)
11211136
else:
11221137
self.ic_varx(entry.data_ptr_label, gl.PTR_TYPE, [data_label])
1138+
if bound_ptrs:
1139+
self.ic_data(gl.PTR_TYPE, bound_ptrs)
11231140
self.ic_vard(data_label, arr_data)
11241141

11251142
self.ic_vard(idx_table_label, l)
11261143

11271144
if entry.lbound_used:
1128-
l = ['%04X' % len(node.bounds)] + \
1129-
['%04X' % bound.lower for bound in node.bounds]
1130-
self.ic_vard('__LBOUND__.' + entry.mangled, l)
1145+
l = ['%04X' % bound.lower for bound in node.bounds]
1146+
self.ic_vard(lbound_label, l)
11311147

11321148
if entry.ubound_used:
1133-
l = ['%04X' % len(node.bounds)] + \
1134-
['%04X' % bound.upper for bound in node.bounds]
1135-
self.ic_vard('__UBOUND__.' + entry.mangled, l)
1149+
l = ['%04X' % bound.upper for bound in node.bounds]
1150+
self.ic_vard(ubound_label, l)
11361151

11371152

11381153
class UnaryOpTranslator(TranslatorVisitor):
@@ -1284,19 +1299,33 @@ def visit_SQR(self, node):
12841299
# endregion
12851300

12861301
def visit_LBOUND(self, node):
1287-
entry = node.operands[0]
1288-
self.ic_param(gl.BOUND_TYPE, '#__LBOUND__.' + entry.mangled)
12891302
yield node.operands[1]
1290-
self.ic_fparam(gl.BOUND_TYPE, optemps.new_t())
1291-
self.ic_call('__BOUND', self.TYPE(gl.BOUND_TYPE).size)
1303+
self.ic_param(gl.BOUND_TYPE, node.operands[1].t)
1304+
entry = node.operands[0]
1305+
if entry.scope == SCOPE.global_:
1306+
self.ic_fparam(gl.PTR_TYPE, '#{}'.format(entry.mangled))
1307+
elif entry.scope == SCOPE.parameter:
1308+
self.ic_fparam(entry.t, entry.offset)
1309+
elif entry.scope == SCOPE.local:
1310+
self.ic_paddr(-entry.offset, entry.t)
1311+
t1 = optemps.new_t()
1312+
self.ic_fparam(gl.PTR_TYPE, t1)
1313+
self.ic_call('__LBOUND', self.TYPE(gl.BOUND_TYPE).size)
12921314
backend.REQUIRES.add('bound.asm')
12931315

12941316
def visit_UBOUND(self, node):
1295-
entry = node.operands[0]
1296-
self.ic_param(gl.BOUND_TYPE, '#__UBOUND__.' + entry.mangled)
12971317
yield node.operands[1]
1298-
self.ic_fparam(gl.BOUND_TYPE, optemps.new_t())
1299-
self.ic_call('__BOUND', self.TYPE(gl.BOUND_TYPE).size)
1318+
self.ic_param(gl.BOUND_TYPE, node.operands[1].t)
1319+
entry = node.operands[0]
1320+
if entry.scope == SCOPE.global_:
1321+
self.ic_fparam(gl.PTR_TYPE, '#{}'.format(entry.mangled))
1322+
elif entry.scope == SCOPE.parameter:
1323+
self.ic_fparam(entry.t, entry.offset)
1324+
elif entry.scope == SCOPE.local:
1325+
self.ic_paddr(-entry.offset, entry.t)
1326+
t1 = optemps.new_t()
1327+
self.ic_fparam(gl.PTR_TYPE, t1)
1328+
self.ic_call('__UBOUND', self.TYPE(gl.BOUND_TYPE).size)
13001329
backend.REQUIRES.add('bound.asm')
13011330

13021331
def visit_USR_STR(self, node):
@@ -1341,6 +1370,8 @@ def start(self):
13411370
self.visit(f)
13421371

13431372
def visit_FUNCTION(self, node):
1373+
bound_tables = []
1374+
13441375
self.ic_label(node.mangled)
13451376
if node.convention == CONVENTION.fastcall:
13461377
self.ic_enter('__fastcall__')
@@ -1355,6 +1386,28 @@ def visit_FUNCTION(self, node):
13551386
# return
13561387

13571388
if local_var.class_ == CLASS.array and local_var.scope == SCOPE.local:
1389+
bound_ptrs = [] # Bound tables pointers (empty if not used)
1390+
lbound_label = local_var.mangled + '.__LBOUND__'
1391+
ubound_label = local_var.mangled + '.__UBOUND__'
1392+
1393+
if local_var.lbound_used or local_var.ubound_used:
1394+
bound_ptrs = ['0', '0'] # NULL by default
1395+
if local_var.lbound_used:
1396+
bound_ptrs[0] = lbound_label
1397+
if local_var.ubound_used:
1398+
bound_ptrs[1] = ubound_label
1399+
1400+
if bound_ptrs:
1401+
zxbpp.ID_TABLE.define('__ZXB_USE_LOCAL_ARRAY_WITH_BOUNDS__', lineno=0)
1402+
1403+
if local_var.lbound_used:
1404+
l = ['%04X' % bound.lower for bound in local_var.bounds]
1405+
bound_tables.append(LabelledData(lbound_label, l))
1406+
1407+
if local_var.ubound_used:
1408+
l = ['%04X' % bound.upper for bound in local_var.bounds]
1409+
bound_tables.append(LabelledData(ubound_label, l))
1410+
13581411
l = [len(local_var.bounds) - 1] + [x.count for x in local_var.bounds[1:]] # TODO Check this
13591412
q = []
13601413
for x in l:
@@ -1365,7 +1418,7 @@ def visit_FUNCTION(self, node):
13651418
r = []
13661419
if local_var.default_value is not None:
13671420
r.extend(self.array_default_value(local_var.type_, local_var.default_value))
1368-
self.ic_larrd(local_var.offset, q, local_var.size, r) # Initializes array bounds
1421+
self.ic_larrd(local_var.offset, q, local_var.size, r, bound_ptrs) # Initializes array bounds
13691422
elif local_var.class_ == CLASS.const:
13701423
continue
13711424
else: # Local vars always defaults to 0, so if 0 we do nothing
@@ -1428,6 +1481,9 @@ def visit_FUNCTION(self, node):
14281481
else:
14291482
self.ic_leave(node.params.size)
14301483

1484+
for bound_table in bound_tables:
1485+
self.ic_vard(bound_table.label, bound_table.data)
1486+
14311487
def visit_FUNCDECL(self, node):
14321488
""" Nested scope functions
14331489
"""

arch/zx48k/translatorinstvisitor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ def ic_jzero(self, type_, t, label: str):
127127
def ic_label(self, label: str):
128128
return self.emit('label', label)
129129

130-
def ic_larrd(self, offset, arg1, size, arg2):
131-
return self.emit('larrd', offset, arg1, size, arg2)
130+
def ic_larrd(self, offset, arg1, size, arg2, bound_ptrs):
131+
return self.emit('larrd', offset, arg1, size, arg2, bound_ptrs)
132132

133133
def ic_le(self, type_, t, t1, t2):
134134
return self.emit('le' + self.TSUFFIX(type_), t, t1, t2)

library-asm/arrayalloc.asm

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,92 @@ __ALLOC_LOCAL_ARRAY:
4545
; HL = Offset to be added to IX => HL = IX + HL
4646
; BC = Length of the element area = n.elements * size(element)
4747
; DE = PTR to the index table
48-
; TOP of the stack = PTR to the element area
48+
; [SP + 2] = PTR to the element area
49+
;
4950
; Returns:
50-
; Nothing
51+
; HL = (IX + HL) + 4
5152
; ---------------------------------------------------------------------
5253

5354
__ALLOC_INITIALIZED_LOCAL_ARRAY:
5455
push bc
5556
call __ALLOC_LOCAL_ARRAY
5657
pop bc
57-
pop hl
58-
ex (sp), hl
58+
;; Swaps [SP], [SP + 2]
59+
exx
60+
pop hl ; HL <- RET address
61+
ex (sp), hl ; HL <- Data table, [SP] <- RET address
62+
push hl ; [SP] <- Data table
63+
exx
64+
ex (sp), hl ; HL = Data table, (SP) = (IX + HL + 4) - start of array address lbound
5965
; HL = data table
6066
; BC = length
6167
; DE = new data area
6268
ldir
69+
pop hl ; HL = addr of LBound area if used
70+
ret
71+
72+
73+
#ifdef __ZXB_USE_LOCAL_ARRAY_WITH_BOUNDS__
74+
75+
; ---------------------------------------------------------------------
76+
; __ALLOC_LOCAL_ARRAY_WITH_BOUNDS
77+
; Allocates an array element area in the heap, and clears it filling it
78+
; with 0 bytes. Then sets LBOUND and UBOUND ptrs
79+
;
80+
; Parameters
81+
; HL = Offset to be added to IX => HL = IX + HL
82+
; BC = Length of the element area = n.elements * size(element)
83+
; DE = PTR to the index table
84+
; [SP + 2] PTR to the lbound element area
85+
; [SP + 4] PTR to the ubound element area
86+
;
87+
; Returns:
88+
; HL = (IX + HL) + 8
89+
; ---------------------------------------------------------------------
90+
__ALLOC_LOCAL_ARRAY_WITH_BOUNDS:
91+
call __ALLOC_LOCAL_ARRAY
92+
93+
__ALLOC_LOCAL_ARRAY_WITH_BOUNDS2:
94+
pop bc ;; ret address
95+
pop de ;; lbound
96+
inc hl
97+
ld (hl), e
98+
inc hl
99+
ld (hl), d
100+
pop de
101+
inc hl
102+
ld (hl), e
103+
inc hl
104+
ld (hl), d
105+
push bc
63106
ret
107+
108+
109+
; ---------------------------------------------------------------------
110+
; __ALLOC_INITIALIZED_LOCAL_ARRAY_WITH_BOUNDS
111+
; Allocates an array element area in the heap, and clears it filling it
112+
; with 0 bytes
113+
;
114+
; Parameters
115+
; HL = Offset to be added to IX => HL = IX + HL
116+
; BC = Length of the element area = n.elements * size(element)
117+
; DE = PTR to the index table
118+
; TOP of the stack = PTR to the element area
119+
; [SP + 2] = PTR to the element area
120+
; [SP + 4] = PTR to the lbound element area
121+
; [SP + 6] = PTR to the ubound element area
122+
;
123+
; Returns:
124+
; HL = (IX + HL) + 8
125+
; ---------------------------------------------------------------------
126+
__ALLOC_INITIALIZED_LOCAL_ARRAY_WITH_BOUNDS:
127+
;; Swaps [SP] and [SP + 2]
128+
exx
129+
pop hl ;; Ret address
130+
ex (sp), hl ;; HL <- PTR to Element area, (sp) = Ret address
131+
push hl ;; [SP] = PTR to element area, [SP + 2] = Ret address
132+
exx
133+
call __ALLOC_INITIALIZED_LOCAL_ARRAY
134+
jp __ALLOC_LOCAL_ARRAY_WITH_BOUNDS2
135+
136+
#endif

0 commit comments

Comments
 (0)