Skip to content

Commit 233c845

Browse files
authored
Merge pull request #1008 from boriel-basic/fix/byref_str_array_assignment
Fix/byref str array assignment
2 parents 0cd16dc + 77ca256 commit 233c845

19 files changed

+4096
-139
lines changed

src/arch/z80/backend/_array.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ def _astoref(ins: Quad) -> list[str]:
313313

314314
def _astorestr(ins: Quad) -> list[str]:
315315
"""Stores a string value into a memory address.
316-
It copies content of 2nd operand (string), into 1st, reallocating
317-
dynamic memory for the 1st str. These instruction DOES ALLOW
316+
It copies the content of the 2nd operand (string), into 1st, reallocating
317+
dynamic memory for the 1st str. These instructions DO ALLOW
318318
immediate strings for the 2nd parameter, starting with '#'.
319319
"""
320320
output = _addr(ins[1])

src/arch/z80/backend/_parray.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -284,22 +284,25 @@ def _pastoref(ins: Quad) -> list[str]:
284284

285285
def _pastorestr(ins: Quad) -> list[str]:
286286
"""Stores a string value into a memory address.
287-
It copies content of 2nd operand (string), into 1st, reallocating
288-
dynamic memory for the 1st str. These instruction DOES ALLOW
287+
It copies the content of the 2nd operand (string), into 1st, reallocating
288+
dynamic memory for the 1st str. These instructions DO ALLOW
289289
immediate strings for the 2nd parameter, starting with '#'.
290290
"""
291291
output = _paddr(ins[1])
292-
temporal = False
293292
value = ins[2]
294293

295294
indirect = value[0] == "*"
296295
if indirect:
297296
value = value[1:]
298297

299-
immediate = value[0]
298+
immediate = value[0] == "#"
300299
if immediate:
301300
value = value[1:]
302301

302+
temporal = not immediate and value[0] != "$"
303+
if temporal:
304+
value = value[1:]
305+
303306
if value[0] == "_":
304307
if indirect:
305308
if immediate:
@@ -313,8 +316,10 @@ def _pastorestr(ins: Quad) -> list[str]:
313316
else:
314317
output.append("ld de, (%s)" % value)
315318
else:
316-
output.append("pop de")
317-
temporal = True
319+
if immediate:
320+
output.append("ld de, %s" % value)
321+
else:
322+
output.append("pop de")
318323

319324
if indirect:
320325
output.append(runtime_call(RuntimeLabel.LOAD_DE_DE))

src/symbols/id_/ref/varref.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def t(self) -> str:
3939
if self.parent.type_ is None or not self.parent.type_.is_dynamic:
4040
return self._t
4141

42-
return f"${self._t}" # Local string variables (and parameters) use '$' (see backend)
42+
return f"${self._t}" # Local string variables (and ByVal parameters) use '$' (see backend)
4343

4444
@property
4545
def size(self) -> int:

src/symbols/sentence.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ def args(self):
2929

3030
@property
3131
def token(self):
32-
"""Sentence takes it's token from the keyword not from it's name"""
32+
"""Sentence takes its token from the keyword not from its name"""
3333
return self.keyword

src/zxbc/zxbparser.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ def make_call(id_: str, lineno: int, args: sym.ARGLIST):
371371
- a(4) can be a string slice if 'a' is a string variable: a$(4)
372372
- a(4) can be an access to an array if 'a' is an array
373373
374-
This function will inspect the id_. If it is undeclared then
374+
This function will inspect the id_. If it is undeclared, then
375375
id_ will be taken as a forwarded function.
376376
"""
377377
if args is None:
@@ -1198,7 +1198,8 @@ def p_arr_assignment(p):
11981198

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

0 commit comments

Comments
 (0)