Skip to content

Commit 700cc31

Browse files
authored
Merge pull request #1028 from boriel-basic/fix/lbound
Fix/lbound
2 parents 4988d47 + cdc264f commit 700cc31

File tree

18 files changed

+692
-78
lines changed

18 files changed

+692
-78
lines changed

src/arch/z80/visitor/function_translator.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ def visit_FUNCTION(self, node):
6868
if local_var.class_ == CLASS.array and local_var.scope == SCOPE.local:
6969
lbound_label = local_var.mangled + ".__LBOUND__"
7070
ubound_label = local_var.mangled + ".__UBOUND__"
71-
lbound_needed = not local_var.is_zero_based and local_var.is_dynamically_accessed
71+
lbound_needed = not local_var.is_zero_based and (
72+
local_var.is_dynamically_accessed or local_var.lbound_used
73+
)
7274

7375
bound_ptrs = [lbound_label if lbound_needed else "0", "0"]
7476
if local_var.ubound_used:

src/arch/z80/visitor/var_translator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def visit_ARRAYDECL(self, node):
5555
ubound_label = entry.mangled + ".__UBOUND__"
5656
bound_ptrs = ["0", "0"] # NULL by default
5757

58-
if not entry.is_zero_based and entry.is_dynamically_accessed:
58+
if not entry.is_zero_based and (entry.is_dynamically_accessed or entry.lbound_used):
5959
bound_ptrs[0] = lbound_label
6060

6161
if entry.ubound_used or OPTIONS.array_check:

src/symbols/call.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# --------------------------------------------------------------------
77

88
from collections.abc import Iterable
9-
from typing import Optional
9+
from typing import Self
1010

1111
import src.api.global_ as gl
1212
from src.api import check, errmsg
@@ -46,6 +46,13 @@ def __init__(self, entry: SymbolID, arglist: Iterable[SymbolARGUMENT], lineno: i
4646
for arg, param in zip(arglist, ref.params): # Sets dependency graph for each argument -> parameter
4747
if arg.value is not None:
4848
arg.value.add_required_symbol(param)
49+
if (
50+
isinstance(arg.value, SymbolID)
51+
and arg.value.class_ == CLASS.array
52+
and param.class_ == CLASS.array
53+
and param.ref.is_dynamically_accessed is True
54+
):
55+
arg.value.ref.is_dynamically_accessed = True
4956

5057
@property
5158
def entry(self):
@@ -80,7 +87,7 @@ def type_(self):
8087
return self.entry.type_
8188

8289
@classmethod
83-
def make_node(cls, id_: str, params, lineno: int, filename: str) -> Optional["SymbolCALL"]:
90+
def make_node(cls, id_: str, params, lineno: int, filename: str) -> Self | None:
8491
"""This will return an AST node for a function/procedure call."""
8592
assert isinstance(params, SymbolARGLIST)
8693
entry = gl.SYMBOL_TABLE.access_func(id_, lineno)
@@ -94,7 +101,7 @@ def make_node(cls, id_: str, params, lineno: int, filename: str) -> Optional["Sy
94101

95102
if entry.declared and not entry.forwarded:
96103
check.check_call_arguments(lineno, id_, params, filename)
97-
else: # All functions goes to global scope by default
104+
else: # All functions go to global scope by default
98105
if entry.token != "FUNCTION":
99106
entry = entry.to_function(lineno)
100107
gl.SYMBOL_TABLE.move_to_global_scope(id_)
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
org 32768
2+
.core.__START_PROGRAM:
3+
di
4+
push ix
5+
push iy
6+
exx
7+
push hl
8+
exx
9+
ld (.core.__CALL_BACK__), sp
10+
ei
11+
jp .core.__MAIN_PROGRAM__
12+
.core.__CALL_BACK__:
13+
DEFW 0
14+
.core.ZXBASIC_USER_DATA:
15+
; Defines USER DATA Length in bytes
16+
.core.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_END - .core.ZXBASIC_USER_DATA
17+
.core.__LABEL__.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_LEN
18+
.core.__LABEL__.ZXBASIC_USER_DATA EQU .core.ZXBASIC_USER_DATA
19+
_array:
20+
DEFW .LABEL.__LABEL0
21+
_array.__DATA__.__PTR__:
22+
DEFW _array.__DATA__
23+
DEFW _array.__LBOUND__
24+
DEFW 0
25+
_array.__DATA__:
26+
DEFB 00h
27+
DEFB 00h
28+
.LABEL.__LABEL0:
29+
DEFW 0000h
30+
DEFB 01h
31+
_array.__LBOUND__:
32+
DEFW 0001h
33+
.core.ZXBASIC_USER_DATA_END:
34+
.core.__MAIN_PROGRAM__:
35+
ld hl, _array
36+
push hl
37+
call _test
38+
ld hl, 0
39+
ld b, h
40+
ld c, l
41+
.core.__END_PROGRAM:
42+
di
43+
ld hl, (.core.__CALL_BACK__)
44+
ld sp, hl
45+
exx
46+
pop hl
47+
exx
48+
pop iy
49+
pop ix
50+
ei
51+
ret
52+
_test:
53+
push ix
54+
ld ix, 0
55+
add ix, sp
56+
ld hl, 0
57+
push hl
58+
ld l, (ix-2)
59+
ld h, (ix-1)
60+
push hl
61+
push ix
62+
pop hl
63+
ld de, 4
64+
add hl, de
65+
call .core.__ARRAY_PTR
66+
ld a, (hl)
67+
ld (0), a
68+
_test__leave:
69+
ld sp, ix
70+
pop ix
71+
exx
72+
pop hl
73+
ex (sp), hl
74+
exx
75+
ret
76+
;; --- end of user code ---
77+
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
78+
; vim: ts=4:et:sw=4:
79+
; Copyleft (K) by Jose M. Rodriguez de la Rosa
80+
; (a.k.a. Boriel)
81+
; http://www.boriel.com
82+
; -------------------------------------------------------------------
83+
; Simple array Index routine
84+
; Number of total indexes dimensions - 1 at beginning of memory
85+
; HL = Start of array memory (First two bytes contains N-1 dimensions)
86+
; Dimension values on the stack, (top of the stack, highest dimension)
87+
; E.g. A(2, 4) -> PUSH <4>; PUSH <2>
88+
; For any array of N dimension A(aN-1, ..., a1, a0)
89+
; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as
90+
; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))]
91+
; What I will do here is to calculate the following sequence:
92+
; ((aN-1 * bN-2) + aN-2) * bN-3 + ...
93+
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/arith/fmul16.asm"
94+
;; Performs a faster multiply for little 16bit numbs
95+
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/arith/mul16.asm"
96+
push namespace core
97+
__MUL16: ; Mutiplies HL with the last value stored into de stack
98+
; Works for both signed and unsigned
99+
PROC
100+
LOCAL __MUL16LOOP
101+
LOCAL __MUL16NOADD
102+
ex de, hl
103+
pop hl ; Return address
104+
ex (sp), hl ; CALLEE caller convention
105+
__MUL16_FAST:
106+
ld b, 16
107+
ld a, h
108+
ld c, l
109+
ld hl, 0
110+
__MUL16LOOP:
111+
add hl, hl ; hl << 1
112+
sla c
113+
rla ; a,c << 1
114+
jp nc, __MUL16NOADD
115+
add hl, de
116+
__MUL16NOADD:
117+
djnz __MUL16LOOP
118+
ret ; Result in hl (16 lower bits)
119+
ENDP
120+
pop namespace
121+
#line 3 "/zxbasic/src/lib/arch/zx48k/runtime/arith/fmul16.asm"
122+
push namespace core
123+
__FMUL16:
124+
xor a
125+
or h
126+
jp nz, __MUL16_FAST
127+
or l
128+
ret z
129+
cp 33
130+
jp nc, __MUL16_FAST
131+
ld b, l
132+
ld l, h ; HL = 0
133+
1:
134+
add hl, de
135+
djnz 1b
136+
ret
137+
pop namespace
138+
#line 20 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
139+
#line 24 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
140+
push namespace core
141+
__ARRAY_PTR: ;; computes an array offset from a pointer
142+
ld c, (hl)
143+
inc hl
144+
ld h, (hl)
145+
ld l, c ;; HL <-- [HL]
146+
__ARRAY:
147+
PROC
148+
LOCAL LOOP
149+
LOCAL ARRAY_END
150+
LOCAL TMP_ARR_PTR ; Ptr to Array DATA region. Stored temporarily
151+
LOCAL LBOUND_PTR, UBOUND_PTR ; LBound and UBound PTR indexes
152+
LOCAL RET_ADDR ; Contains the return address popped from the stack
153+
LBOUND_PTR EQU 23698 ; Uses MEMBOT as a temporary variable
154+
UBOUND_PTR EQU LBOUND_PTR + 2 ; Next 2 bytes for UBOUND PTR
155+
RET_ADDR EQU UBOUND_PTR + 2 ; Next 2 bytes for RET_ADDR
156+
TMP_ARR_PTR EQU RET_ADDR + 2 ; Next 2 bytes for TMP_ARR_PTR
157+
ld e, (hl)
158+
inc hl
159+
ld d, (hl)
160+
inc hl ; DE <-- PTR to Dim sizes table
161+
ld (TMP_ARR_PTR), hl ; HL = Array __DATA__.__PTR__
162+
inc hl
163+
inc hl
164+
ld c, (hl)
165+
inc hl
166+
ld b, (hl) ; BC <-- Array __LBOUND__ PTR
167+
ld (LBOUND_PTR), bc ; Store it for later
168+
#line 66 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
169+
ex de, hl ; HL <-- PTR to Dim sizes table, DE <-- dummy
170+
ex (sp), hl ; Return address in HL, PTR Dim sizes table onto Stack
171+
ld (RET_ADDR), hl ; Stores it for later
172+
exx
173+
pop hl ; Will use H'L' as the pointer to Dim sizes table
174+
ld c, (hl) ; Loads Number of dimensions from (hl)
175+
inc hl
176+
ld b, (hl)
177+
inc hl ; Ready
178+
exx
179+
ld hl, 0 ; HL = Element Offset "accumulator"
180+
LOOP:
181+
ex de, hl ; DE = Element Offset
182+
ld hl, (LBOUND_PTR)
183+
ld a, h
184+
or l
185+
ld b, h
186+
ld c, l
187+
jr z, 1f
188+
ld c, (hl)
189+
inc hl
190+
ld b, (hl)
191+
inc hl
192+
ld (LBOUND_PTR), hl
193+
1:
194+
pop hl ; Get next index (Ai) from the stack
195+
sbc hl, bc ; Subtract LBOUND
196+
#line 116 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
197+
add hl, de ; Adds current index
198+
exx ; Checks if B'C' = 0
199+
ld a, b ; Which means we must exit (last element is not multiplied by anything)
200+
or c
201+
jr z, ARRAY_END ; if B'Ci == 0 we are done
202+
dec bc ; Decrements loop counter
203+
ld e, (hl) ; Loads next dimension size into D'E'
204+
inc hl
205+
ld d, (hl)
206+
inc hl
207+
push de
208+
exx
209+
pop de ; DE = Max bound Number (i-th dimension)
210+
call __FMUL16 ; HL <= HL * DE mod 65536
211+
jp LOOP
212+
ARRAY_END:
213+
ld a, (hl)
214+
exx
215+
#line 146 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
216+
LOCAL ARRAY_SIZE_LOOP
217+
ex de, hl
218+
ld hl, 0
219+
ld b, a
220+
ARRAY_SIZE_LOOP:
221+
add hl, de
222+
djnz ARRAY_SIZE_LOOP
223+
#line 156 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
224+
ex de, hl
225+
ld hl, (TMP_ARR_PTR)
226+
ld a, (hl)
227+
inc hl
228+
ld h, (hl)
229+
ld l, a
230+
add hl, de ; Adds element start
231+
ld de, (RET_ADDR)
232+
push de
233+
ret
234+
ENDP
235+
pop namespace
236+
#line 44 "arch/zx48k/array13.bas"
237+
END
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
SUB test(arr() As UByte)
2+
DIM i As UInteger
3+
POKE 0, arr(i)
4+
END SUB
5+
6+
DIM array(1 TO 2) As UByte
7+
8+
test array
9+

tests/functional/arch/zx48k/bound02.asm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ _a:
2424
DEFW .LABEL.__LABEL0
2525
_a.__DATA__.__PTR__:
2626
DEFW _a.__DATA__
27-
DEFW 0
27+
DEFW _a.__LBOUND__
2828
DEFW 0
2929
_a.__DATA__:
3030
DEFB 00h
@@ -87,6 +87,9 @@ _a.__DATA__:
8787
DEFW 0001h
8888
DEFW 0004h
8989
DEFB 02h
90+
_a.__LBOUND__:
91+
DEFW 0002h
92+
DEFW 0003h
9093
.core.ZXBASIC_USER_DATA_END:
9194
.core.__MAIN_PROGRAM__:
9295
ld a, 1

0 commit comments

Comments
 (0)