Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/arch/z80/backend/_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ def _astoref(ins: Quad) -> list[str]:

def _astorestr(ins: Quad) -> list[str]:
"""Stores a string value into a memory address.
It copies content of 2nd operand (string), into 1st, reallocating
dynamic memory for the 1st str. These instruction DOES ALLOW
It copies the content of the 2nd operand (string), into 1st, reallocating
dynamic memory for the 1st str. These instructions DO ALLOW
immediate strings for the 2nd parameter, starting with '#'.
"""
output = _addr(ins[1])
Expand Down
17 changes: 11 additions & 6 deletions src/arch/z80/backend/_parray.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,22 +284,25 @@ def _pastoref(ins: Quad) -> list[str]:

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

indirect = value[0] == "*"
if indirect:
value = value[1:]

immediate = value[0]
immediate = value[0] == "#"
if immediate:
value = value[1:]

temporal = not immediate and value[0] != "$"
if temporal:
value = value[1:]

if value[0] == "_":
if indirect:
if immediate:
Expand All @@ -313,8 +316,10 @@ def _pastorestr(ins: Quad) -> list[str]:
else:
output.append("ld de, (%s)" % value)
else:
output.append("pop de")
temporal = True
if immediate:
output.append("ld de, %s" % value)
else:
output.append("pop de")

if indirect:
output.append(runtime_call(RuntimeLabel.LOAD_DE_DE))
Expand Down
2 changes: 1 addition & 1 deletion src/symbols/id_/ref/varref.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def t(self) -> str:
if self.parent.type_ is None or not self.parent.type_.is_dynamic:
return self._t

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

@property
def size(self) -> int:
Expand Down
2 changes: 1 addition & 1 deletion src/symbols/sentence.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ def args(self):

@property
def token(self):
"""Sentence takes it's token from the keyword not from it's name"""
"""Sentence takes its token from the keyword not from its name"""
return self.keyword
5 changes: 3 additions & 2 deletions src/zxbc/zxbparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ def make_call(id_: str, lineno: int, args: sym.ARGLIST):
- a(4) can be a string slice if 'a' is a string variable: a$(4)
- a(4) can be an access to an array if 'a' is an array

This function will inspect the id_. If it is undeclared then
This function will inspect the id_. If it is undeclared, then
id_ will be taken as a forwarded function.
"""
if args is None:
Expand Down Expand Up @@ -1198,7 +1198,8 @@ def p_arr_assignment(p):

if entry.type_ == TYPE.string:
variable = gl.SYMBOL_TABLE.access_array(id_, p.lineno(i))
if len(variable.ref.bounds) + 1 == len(arg_list):
# variable is an array. If it has 0 bounds means they are undefined (param byref)
if len(variable.ref.bounds) and len(variable.ref.bounds) + 1 == len(arg_list):
ss = arg_list.children.pop().value
p[0] = make_array_substr_assign(p.lineno(i), id_, arg_list, (ss, ss), expr)
return
Expand Down
236 changes: 236 additions & 0 deletions tests/functional/arch/zx48k/arr_elem_by_ref01.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
org 32768
.core.__START_PROGRAM:
di
push ix
push iy
exx
push hl
exx
ld (.core.__CALL_BACK__), sp
ei
jp .core.__MAIN_PROGRAM__
.core.__CALL_BACK__:
DEFW 0
.core.ZXBASIC_USER_DATA:
; Defines USER DATA Length in bytes
.core.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_END - .core.ZXBASIC_USER_DATA
.core.__LABEL__.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_LEN
.core.__LABEL__.ZXBASIC_USER_DATA EQU .core.ZXBASIC_USER_DATA
_a:
DEFW .LABEL.__LABEL0
_a.__DATA__.__PTR__:
DEFW _a.__DATA__
DEFW 0
DEFW 0
_a.__DATA__:
DEFB 01h
DEFB 02h
DEFB 03h
.LABEL.__LABEL0:
DEFW 0000h
DEFB 01h
.core.ZXBASIC_USER_DATA_END:
.core.__MAIN_PROGRAM__:
ld hl, 1
push hl
ld hl, _a
call .core.__ARRAY
push hl
call _Incr
ld a, (_a.__DATA__ + 1)
ld (0), a
ld hl, 0
ld b, h
ld c, l
.core.__END_PROGRAM:
di
ld hl, (.core.__CALL_BACK__)
ld sp, hl
exx
pop hl
exx
pop iy
pop ix
ei
ret
_Incr:
push ix
ld ix, 0
add ix, sp
ld h, (ix+5)
ld l, (ix+4)
ld a, (hl)
inc a
ld h, (ix+5)
ld l, (ix+4)
ld (hl), a
_Incr__leave:
ld sp, ix
pop ix
exx
pop hl
ex (sp), hl
exx
ret
;; --- end of user code ---
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
; vim: ts=4:et:sw=4:
; Copyleft (K) by Jose M. Rodriguez de la Rosa
; (a.k.a. Boriel)
; http://www.boriel.com
; -------------------------------------------------------------------
; Simple array Index routine
; Number of total indexes dimensions - 1 at beginning of memory
; HL = Start of array memory (First two bytes contains N-1 dimensions)
; Dimension values on the stack, (top of the stack, highest dimension)
; E.g. A(2, 4) -> PUSH <4>; PUSH <2>
; For any array of N dimension A(aN-1, ..., a1, a0)
; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as
; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))]
; What I will do here is to calculate the following sequence:
; ((aN-1 * bN-2) + aN-2) * bN-3 + ...
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/arith/fmul16.asm"
;; Performs a faster multiply for little 16bit numbs
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/arith/mul16.asm"
push namespace core
__MUL16: ; Mutiplies HL with the last value stored into de stack
; Works for both signed and unsigned
PROC
LOCAL __MUL16LOOP
LOCAL __MUL16NOADD
ex de, hl
pop hl ; Return address
ex (sp), hl ; CALLEE caller convention
__MUL16_FAST:
ld b, 16
ld a, h
ld c, l
ld hl, 0
__MUL16LOOP:
add hl, hl ; hl << 1
sla c
rla ; a,c << 1
jp nc, __MUL16NOADD
add hl, de
__MUL16NOADD:
djnz __MUL16LOOP
ret ; Result in hl (16 lower bits)
ENDP
pop namespace
#line 3 "/zxbasic/src/lib/arch/zx48k/runtime/arith/fmul16.asm"
push namespace core
__FMUL16:
xor a
or h
jp nz, __MUL16_FAST
or l
ret z
cp 33
jp nc, __MUL16_FAST
ld b, l
ld l, h ; HL = 0
1:
add hl, de
djnz 1b
ret
pop namespace
#line 20 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
#line 24 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
push namespace core
__ARRAY_PTR: ;; computes an array offset from a pointer
ld c, (hl)
inc hl
ld h, (hl)
ld l, c ;; HL <-- [HL]
__ARRAY:
PROC
LOCAL LOOP
LOCAL ARRAY_END
LOCAL TMP_ARR_PTR ; Ptr to Array DATA region. Stored temporarily
LOCAL LBOUND_PTR, UBOUND_PTR ; LBound and UBound PTR indexes
LOCAL RET_ADDR ; Contains the return address popped from the stack
LBOUND_PTR EQU 23698 ; Uses MEMBOT as a temporary variable
UBOUND_PTR EQU LBOUND_PTR + 2 ; Next 2 bytes for UBOUND PTR
RET_ADDR EQU UBOUND_PTR + 2 ; Next 2 bytes for RET_ADDR
TMP_ARR_PTR EQU RET_ADDR + 2 ; Next 2 bytes for TMP_ARR_PTR
ld e, (hl)
inc hl
ld d, (hl)
inc hl ; DE <-- PTR to Dim sizes table
ld (TMP_ARR_PTR), hl ; HL = Array __DATA__.__PTR__
inc hl
inc hl
ld c, (hl)
inc hl
ld b, (hl) ; BC <-- Array __LBOUND__ PTR
ld (LBOUND_PTR), bc ; Store it for later
#line 66 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
ex de, hl ; HL <-- PTR to Dim sizes table, DE <-- dummy
ex (sp), hl ; Return address in HL, PTR Dim sizes table onto Stack
ld (RET_ADDR), hl ; Stores it for later
exx
pop hl ; Will use H'L' as the pointer to Dim sizes table
ld c, (hl) ; Loads Number of dimensions from (hl)
inc hl
ld b, (hl)
inc hl ; Ready
exx
ld hl, 0 ; HL = Element Offset "accumulator"
LOOP:
ex de, hl ; DE = Element Offset
ld hl, (LBOUND_PTR)
ld a, h
or l
ld b, h
ld c, l
jr z, 1f
ld c, (hl)
inc hl
ld b, (hl)
inc hl
ld (LBOUND_PTR), hl
1:
pop hl ; Get next index (Ai) from the stack
sbc hl, bc ; Subtract LBOUND
#line 116 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
add hl, de ; Adds current index
exx ; Checks if B'C' = 0
ld a, b ; Which means we must exit (last element is not multiplied by anything)
or c
jr z, ARRAY_END ; if B'Ci == 0 we are done
dec bc ; Decrements loop counter
ld e, (hl) ; Loads next dimension size into D'E'
inc hl
ld d, (hl)
inc hl
push de
exx
pop de ; DE = Max bound Number (i-th dimension)
call __FMUL16 ; HL <= HL * DE mod 65536
jp LOOP
ARRAY_END:
ld a, (hl)
exx
#line 146 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
LOCAL ARRAY_SIZE_LOOP
ex de, hl
ld hl, 0
ld b, a
ARRAY_SIZE_LOOP:
add hl, de
djnz ARRAY_SIZE_LOOP
#line 156 "/zxbasic/src/lib/arch/zx48k/runtime/array/array.asm"
ex de, hl
ld hl, (TMP_ARR_PTR)
ld a, (hl)
inc hl
ld h, (hl)
ld l, a
add hl, de ; Adds element start
ld de, (RET_ADDR)
push de
ret
ENDP
pop namespace
#line 44 "arch/zx48k/arr_elem_by_ref01.bas"
END
10 changes: 10 additions & 0 deletions tests/functional/arch/zx48k/arr_elem_by_ref01.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
REM Test passing an array element by ref

DIM a(2) As UByte => {1, 2, 3}

SUB Incr(ByRef x As UByte)
LET x = x + 1
END SUB

Incr(a(1))
POKE 0, a(1)
Loading