Skip to content

Commit 5a41efb

Browse files
authored
Merge pull request #219 from boriel/feature/array_addr
Feature/array addr
2 parents d1a8f14 + 5fdef76 commit 5a41efb

File tree

147 files changed

+24164
-8998
lines changed

Some content is hidden

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

147 files changed

+24164
-8998
lines changed

api/errmsg.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,5 +185,12 @@ def syntax_error_undeclared_type(lineno, id_):
185185
# ----------------------------------------
186186
# Cannot assign a value to 'var'. It's not a variable
187187
# ----------------------------------------
188-
def syntax_error_cannot_assing_not_a_var(lineno, id_):
188+
def syntax_error_cannot_assign_not_a_var(lineno, id_):
189189
syntax_error(lineno, "Cannot assign a value to '%s'. It's not a variable" % id_)
190+
191+
192+
# ----------------------------------------
193+
# Cannot assign a value to 'var'. It's not a variable
194+
# ----------------------------------------
195+
def syntax_error_address_must_be_constant(lineno):
196+
syntax_error(lineno, 'Address must be a numeric constant expression')

api/global_.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@
132132
# ----------------------------------------------------------------------
133133
MANGLE_CHR = '_'
134134

135+
# ----------------------------------------------------------------------
136+
# Prefix used in labels to mark the beginning of array data
137+
# ----------------------------------------------------------------------
138+
ARRAY_DATA_PREFIX = '__DATA__'
139+
135140
# ----------------------------------------------------------------------
136141
# Default optimization level
137142
# ----------------------------------------------------------------------

api/optimize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def TYPE(type_):
4141
return gl.SYMBOL_TABLE.basic_types[type_]
4242

4343
def visit(self, node):
44-
if self.O_LEVEL < 0: # Optimize only if O1 or above
44+
if self.O_LEVEL < 1: # Optimize only if O1 or above
4545
return node
4646

4747
stack = [ToVisit(node)]

api/symboltable.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,6 @@ def declare_variable(self, id_, lineno, type_, default_value=None):
567567
"declared as '%s'" %
568568
(id_, entry.type_, type_))
569569
return None
570-
# type_ = entry.type_ # TODO: Unused??
571570

572571
entry.scope = SCOPE.global_ if self.current_scope == self.global_scope else SCOPE.local
573572
entry.callable = False
@@ -701,9 +700,11 @@ def declare_param(self, id_, lineno, type_=None):
701700
warning_implicit_type(lineno, id_, type_)
702701
return entry
703702

704-
def declare_array(self, id_, lineno, type_, bounds, default_value=None):
703+
def declare_array(self, id_, lineno, type_, bounds, default_value=None, addr=None):
705704
""" Declares an array in the symbol table (VARARRAY). Error if already
706705
exists.
706+
The optional parameter addr specifies if the array elements must be placed at an specific
707+
(constant) memory address.
707708
"""
708709
assert isinstance(type_, symbols.TYPEREF)
709710
assert isinstance(bounds, symbols.BOUNDLIST)
@@ -754,6 +755,7 @@ def declare_array(self, id_, lineno, type_, bounds, default_value=None):
754755
entry.callable = True
755756
entry.class_ = CLASS.array
756757
entry.lbound_used = entry.ubound_used = False # Flag to true when LBOUND/UBOUND used somewhere in the code
758+
entry.addr = addr
757759

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

arch/zx48k/backend/__init__.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,44 @@ def _lvard(ins):
579579
return output
580580

581581

582+
def _larrd(ins):
583+
""" Defines a local array.
584+
- 1st param is offset of the local variable.
585+
- 2nd param is a list of bytes in hexadecimal corresponding to the index table
586+
- 3rd param is the size of elements in byte
587+
- 4rd param a list (might be empty) of byte to initialize the array with
588+
"""
589+
output = []
590+
591+
label = tmp_label()
592+
offset = int(ins.quad[1])
593+
elements_size = ins.quad[3]
594+
AT_END.extend(_vard(Quad('vard', label, ins.quad[2])))
595+
must_initialize = ins.quad[4] != '[]'
596+
597+
if must_initialize:
598+
label2 = tmp_label()
599+
AT_END.extend(_vard(Quad('vard', label2, ins.quad[4])))
600+
output.extend([
601+
'ld hl, %s' % label2,
602+
'push hl'
603+
])
604+
605+
output.extend([
606+
'ld hl, %i' % -offset,
607+
'ld de, %s' % label,
608+
'ld bc, %s' % elements_size,
609+
])
610+
611+
if must_initialize:
612+
output.append('call __ALLOC_INITIALIZED_LOCAL_ARRAY')
613+
else:
614+
output.append('call __ALLOC_LOCAL_ARRAY')
615+
616+
REQUIRES.add('arrayalloc.asm')
617+
return output
618+
619+
582620
def _out(ins):
583621
""" Translates OUT to asm.
584622
"""
@@ -2099,7 +2137,7 @@ def __str__(self):
20992137
'vard': [2, _vard], # Like the above but with a list of items (chars, bytes or words, hex)
21002138
'lvarx': [3, _lvarx], # Initializes a local variable. lvard X, (list of bytes): Initializes variable at offset X
21012139
'lvard': [2, _lvard], # Initializes a local variable. lvard X, (list of bytes): Initializes variable at offset X
2102-
2140+
'larrd': [4, _larrd], # Initializes a local array
21032141
'memcopy': [3, _memcopy], # Copies a block of param 3 bytes of memory from param 2 addr to param 1 addr.
21042142

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

arch/zx48k/backend/__parray.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616

1717

1818
def _paddr(offset):
19-
''' Generic array address parameter loading.
20-
Emmits output code for setting IX at the right location.
19+
""" Generic element array-address stack-ptr loading.
20+
Emits output code for setting IX at the right location.
2121
bytes = Number of bytes to load:
2222
1 => 8 bit value
2323
2 => 16 bit value / string
2424
4 => 32 bit value / f16 value
2525
5 => 40 bit value
26-
'''
26+
"""
2727
output = []
2828

2929
indirect = offset[0] == '*'
@@ -40,12 +40,9 @@ def _paddr(offset):
4040
output.append('add hl, de')
4141

4242
if indirect:
43-
output.append('ld c, (hl)')
44-
output.append('inc hl')
45-
output.append('ld h, (hl)')
46-
output.append('ld l, c')
47-
48-
output.append('call __ARRAY')
43+
output.append('call __ARRAY_PTR')
44+
else:
45+
output.append('call __ARRAY')
4946
REQUIRES.add('array.asm')
5047
return output
5148

arch/zx48k/backend/__str.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def _str_oper(op1, op2=None, reversed=False, no_exaf=False):
6565

6666
if val[0] == '_': # Direct
6767
output.append('ld hl, (%s)' % val)
68-
elif val[0] == '#': # Inmmediate
68+
elif val[0] == '#': # Immediate
6969
output.append('ld hl, %s' % val[1:])
7070
elif val[0] == '$': # Direct in the stack
7171
output.append('pop hl')
@@ -74,7 +74,6 @@ def _str_oper(op1, op2=None, reversed=False, no_exaf=False):
7474
tmp1 = True
7575

7676
if indirect:
77-
output.append('ld hl, %s' % val[1:])
7877
output.append('ld c, (hl)')
7978
output.append('inc hl')
8079
output.append('ld h, (hl)')

arch/zx48k/translator.py

Lines changed: 79 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
import functools
54
from collections import OrderedDict
65
from collections import namedtuple
76

@@ -281,15 +280,18 @@ def traverse_const(node):
281280
syntax_error_cant_convert_to_type(node.lineno, str(node.operand), node.type_)
282281
return
283282

284-
if node.token in ('VAR', 'VARARRAY', 'LABEL', 'FUNCTION'):
283+
if node.token == 'VARARRAY':
284+
return node.data_label
285+
286+
if node.token in ('VAR', 'LABEL', 'FUNCTION'):
285287
# TODO: Check what happens with local vars and params
286288
return node.t
287289

288290
if node.token == 'CONST':
289291
return Translator.traverse_const(node.expr)
290292

291293
if node.token == 'ARRAYACCESS':
292-
return '({} + {})'.format(node.entry.mangled, node.offset)
294+
return '({} + {})'.format(node.entry.data_label, node.offset)
293295

294296
raise InvalidCONSTexpr(node)
295297

@@ -404,7 +406,7 @@ def visit_CONST(self, node):
404406
yield node.t
405407

406408
def visit_VARARRAY(self, node):
407-
self.visit_VAR(node)
409+
pass
408410

409411
def visit_PARAMDECL(self, node):
410412
assert node.scope == SCOPE.parameter
@@ -516,36 +518,40 @@ def visit_ARRAYLOAD(self, node):
516518
else:
517519
offset = node.offset
518520
if scope == SCOPE.global_:
519-
self.emit('load' + self.TSUFFIX(node.type_), node.entry.t, '%s + %i' % (node.entry.mangled, offset))
521+
self.emit('load' + self.TSUFFIX(node.type_), node.entry.t, '%s + %i' % (node.entry.t, offset))
520522
elif scope == SCOPE.parameter:
521523
self.emit('pload' + self.TSUFFIX(node.type_), node.t, node.entry.offset - offset)
522524
elif scope == SCOPE.local:
523-
self.emit('pload' + self.TSUFFIX(node.type_), node.t, -(node.entry.offset - offset))
525+
t1 = optemps.new_t()
526+
t2 = optemps.new_t()
527+
t3 = optemps.new_t()
528+
self.emit('pload' + self.TSUFFIX(gl.PTR_TYPE), t1,
529+
-(node.entry.offset - self.TYPE(gl.PTR_TYPE).size))
530+
self.emit('add' + self.TSUFFIX(gl.PTR_TYPE), t2, t1, node.offset)
531+
self.emit('load' + self.TSUFFIX(node.type_), t3, '*$%s' % t2)
524532

525533
def visit_ARRAYCOPY(self, node):
526534
tr = node.children[0]
527535
scope = tr.scope
528-
offset = self.TYPE(gl.SIZE_TYPE).size + self.TYPE(gl.BOUND_TYPE).size * len(tr.bounds)
529536
if scope == SCOPE.global_:
530-
t1 = "#%s + %i" % (tr.mangled, offset)
537+
t1 = "#%s" % tr.data_label
531538
elif scope == SCOPE.parameter:
532-
self.emit('paddr', '%i' % (tr.offset - offset), tr.t)
533-
t1 = tr.t
539+
t1 = optemps.new_t()
540+
self.emit('pload%s' % self.TSUFFIX(gl.PTR_TYPE), t1, '%i' % (tr.offset - self.TYPE(gl.PTR_TYPE).size))
534541
elif scope == SCOPE.local:
535-
self.emit('paddr', '%i' % -(tr.offset - offset), tr.t)
536-
t1 = tr.t
542+
t1 = optemps.new_t()
543+
self.emit('pload%s' % self.TSUFFIX(gl.PTR_TYPE), t1, '%i' % -(tr.offset - self.TYPE(gl.PTR_TYPE).size))
537544

538545
tr = node.children[1]
539546
scope = tr.scope
540-
offset = self.TYPE(gl.SIZE_TYPE).size + self.TYPE(gl.BOUND_TYPE).size * len(tr.bounds)
541547
if scope == SCOPE.global_:
542-
t2 = "#%s + %i" % (tr.mangled, offset)
548+
t2 = "#%s" % tr.data_label
543549
elif scope == SCOPE.parameter:
544-
self.emit('paddr', '%i' % (tr.offset - offset), tr.t)
545-
t2 = tr.t
550+
t2 = optemps.new_t()
551+
self.emit('pload%s' % self.TSUFFIX(gl.PTR_TYPE), t2, '%i' % (tr.offset - self.TYPE(gl.PTR_TYPE).size))
546552
elif scope == SCOPE.local:
547-
self.emit('paddr', '%i' % -(tr.offset - offset), tr.t)
548-
t2 = tr.t
553+
t2 = optemps.new_t()
554+
self.emit('pload%s' % self.TSUFFIX(gl.PTR_TYPE), t2, '%i' % -(tr.offset - self.TYPE(gl.PTR_TYPE).size))
549555

550556
t = optemps.new_t()
551557
if tr.type_ != Type.string:
@@ -575,7 +581,7 @@ def visit_LETARRAY(self, node):
575581
elif scope == SCOPE.local:
576582
self.emit('pastore' + suf, -arr.entry.offset, node.children[1].t)
577583
else:
578-
name = arr.entry.mangled
584+
name = arr.entry.data_label
579585
if scope == SCOPE.global_:
580586
self.emit('store' + suf, '%s + %i' % (name, arr.offset), node.children[1].t)
581587
elif scope == SCOPE.parameter:
@@ -1352,28 +1358,44 @@ def visit_VARDECL(self, node):
13521358

13531359
def visit_ARRAYDECL(self, node):
13541360
entry = node.entry
1361+
assert entry.default_value is None or entry.addr is None, "Cannot use address and default_value at once"
1362+
13551363
if not entry.accessed:
13561364
api.errmsg.warning_not_used(entry.lineno, entry.name)
13571365
if self.O_LEVEL > 1:
13581366
return
13591367

1368+
data_label = entry.data_label
1369+
idx_table_label = backend.tmp_label()
13601370
l = ['%04X' % (len(node.bounds) - 1)] # Number of dimensions - 1
13611371

13621372
for bound in node.bounds[1:]:
13631373
l.append('%04X' % (bound.upper - bound.lower + 1))
13641374

13651375
l.append('%02X' % node.type_.size)
1376+
arr_data = []
13661377

1367-
if entry.default_value is not None:
1368-
l.extend(Translator.array_default_value(node.type_, entry.default_value))
1378+
if entry.addr:
1379+
self.emit('deflabel', data_label, "%s" % entry.addr)
13691380
else:
1370-
l.extend(['00'] * node.size)
1381+
if entry.default_value is not None:
1382+
arr_data = Translator.array_default_value(node.type_, entry.default_value)
1383+
else:
1384+
arr_data = ['00'] * node.size
13711385

13721386
for alias in entry.aliased_by:
13731387
offset = 1 + 2 * entry.count + alias.offset # TODO: Generalize for multi-arch
13741388
self.emit('deflabel', alias.mangled, '%s + %i' % (entry.mangled, offset))
13751389

1376-
self.emit('vard', node.mangled, l)
1390+
self.emit('varx', node.mangled, self.TSUFFIX(gl.PTR_TYPE), [idx_table_label])
1391+
1392+
if entry.addr:
1393+
self.emit('varx', entry.data_ptr_label, self.TSUFFIX(gl.PTR_TYPE), [self.traverse_const(entry.addr)])
1394+
else:
1395+
self.emit('varx', entry.data_ptr_label, self.TSUFFIX(gl.PTR_TYPE), [data_label])
1396+
self.emit('vard', data_label, arr_data)
1397+
1398+
self.emit('vard', idx_table_label, l)
13771399

13781400
if entry.lbound_used:
13791401
l = ['%04X' % len(node.bounds)] + \
@@ -1597,17 +1619,18 @@ def visit_FUNCTION(self, node):
15971619
# if self.O_LEVEL > 1:
15981620
# return
15991621

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

16071629
q.append('%02X' % local_var.type_.size)
1630+
r = []
16081631
if local_var.default_value is not None:
1609-
q.extend(self.array_default_value(local_var.type_, local_var.default_value))
1610-
self.emit('lvard', local_var.offset, q) # Initializes array bounds
1632+
r.extend(self.array_default_value(local_var.type_, local_var.default_value))
1633+
self.emit('larrd', local_var.offset, q, local_var.size, r) # Initializes array bounds
16111634
elif local_var.class_ == CLASS.const:
16121635
continue
16131636
else: # Local vars always defaults to 0, so if 0 we do nothing
@@ -1628,8 +1651,8 @@ def visit_FUNCTION(self, node):
16281651
# Now free any local string from memory.
16291652
preserve_hl = False
16301653
for local_var in node.local_symbol_table.values():
1654+
scope = local_var.scope
16311655
if local_var.type_ == self.TYPE(TYPE.string): # Only if it's string we free it
1632-
scope = local_var.scope
16331656
if local_var.class_ != CLASS.array: # Ok just free it
16341657
if scope == SCOPE.local or (scope == SCOPE.parameter and not local_var.byref):
16351658
if not preserve_hl:
@@ -1648,13 +1671,35 @@ def visit_FUNCTION(self, node):
16481671
preserve_hl = True
16491672
self.emit('exchg')
16501673

1651-
offset = -local_var.offset if scope == SCOPE.local else local_var.offset
1652-
elems = functools.reduce(lambda x, y: x * y, [x.count for x in local_var.bounds])
1653-
self.emit('param' + self.TSUFFIX(gl.BOUND_TYPE), elems)
1654-
self.emit('paddr', offset, local_var.t)
1655-
self.emit('fparamu16', local_var.t)
1656-
self.emit('call', '__ARRAY_FREE', 0)
1657-
self.REQUIRES.add('arrayfree.asm')
1674+
self.emit('param' + self.TSUFFIX(gl.BOUND_TYPE), local_var.count)
1675+
t2 = optemps.new_t()
1676+
if scope == SCOPE.parameter:
1677+
self.emit('pload%s' % self.TSUFFIX(gl.PTR_TYPE), t2,
1678+
'%i' % (local_var.offset - self.TYPE(gl.PTR_TYPE).size))
1679+
elif scope == SCOPE.local:
1680+
self.emit('pload%s' % self.TSUFFIX(gl.PTR_TYPE), t2,
1681+
'%i' % -(local_var.offset - self.TYPE(gl.PTR_TYPE).size))
1682+
self.emit('fparam' + self.TSUFFIX(gl.PTR_TYPE), t2)
1683+
self.emit('call', '__ARRAYSTR_FREE_MEM', 0) # frees all the strings and the array itself
1684+
self.REQUIRES.add('arraystrfree.asm')
1685+
1686+
if local_var.class_ == CLASS.array and local_var.type_ != self.TYPE(TYPE.string) and \
1687+
(scope == SCOPE.local or (scope == SCOPE.parameter and not local_var.byref)):
1688+
if not preserve_hl:
1689+
preserve_hl = True
1690+
self.emit('exchg')
1691+
1692+
t2 = optemps.new_t()
1693+
if scope == SCOPE.parameter:
1694+
self.emit('pload%s' % self.TSUFFIX(gl.PTR_TYPE), t2, '%i'
1695+
% (local_var.offset - self.TYPE(gl.PTR_TYPE).size))
1696+
elif scope == SCOPE.local:
1697+
self.emit('pload%s' % self.TSUFFIX(gl.PTR_TYPE), t2, '%i'
1698+
% -(local_var.offset - self.TYPE(gl.PTR_TYPE).size))
1699+
1700+
self.emit('fparam' + self.TSUFFIX(gl.PTR_TYPE), t2)
1701+
self.emit('call', '__MEM_FREE', 0)
1702+
self.REQUIRES.add('free.asm')
16581703

16591704
if preserve_hl:
16601705
self.emit('exchg')

0 commit comments

Comments
 (0)