zasm: make symbol registry easily parametrizable

I'm about to split the global registry in two (labels and consts)
and the previous state of registry selection made things murky.
Now it's much better.
This commit is contained in:
Virgil Dupras 2019-07-22 13:37:57 -04:00
parent 518f12b07f
commit 311d04e9aa
4 changed files with 95 additions and 96 deletions

View File

@ -36,20 +36,28 @@
.equ SYM_LOC_VALUES SYM_NAMES+SYM_BUFSIZE .equ SYM_LOC_VALUES SYM_NAMES+SYM_BUFSIZE
.equ SYM_LOC_NAMES SYM_LOC_VALUES+SYM_LOC_MAXCOUNT*2 .equ SYM_LOC_NAMES SYM_LOC_VALUES+SYM_LOC_MAXCOUNT*2
; Pointer to the currently selected registry ; Pointer to the active registry
.equ SYM_CTX_NAMES SYM_LOC_NAMES+SYM_LOC_BUFSIZE .equ SYM_CTX SYM_LOC_NAMES+SYM_LOC_BUFSIZE
.equ SYM_CTX_NAMESEND SYM_CTX_NAMES+2
.equ SYM_CTX_VALUES SYM_CTX_NAMESEND+2
; Pointer, in (SYM_CTX_VALUES), to the result of the last symFind
.equ SYM_CTX_PTR SYM_CTX_VALUES+2
; Pointer, in the value list, to the result of the last _symFind
.equ SYM_CTX_PTR SYM_CTX+2
.equ SYM_RAMEND SYM_CTX_PTR+2 .equ SYM_RAMEND SYM_CTX_PTR+2
; *** Registries ***
; A symbol registry is a 6 bytes record with points to names and values of
; one of the register.
; It's 3 pointers: names, names end, values
SYM_GLOBAL_REGISTRY:
.dw SYM_NAMES, SYM_NAMES+SYM_BUFSIZE, SYM_VALUES
SYM_LOCAL_REGISTRY:
.dw SYM_LOC_NAMES, SYM_LOC_NAMES+SYM_LOC_BUFSIZE, SYM_LOC_VALUES
; *** Code *** ; *** Code ***
; Advance HL to the beginning of the next symbol name in SYM_NAMES except if ; Assuming that HL points in to a symbol name list, advance HL to the beginning
; (HL) is already zero, meaning we're at the end of the chain. In this case, ; of the next symbol name except if (HL) is already zero, meaning we're at the
; do nothing. ; end of the chain. In this case, do nothing.
; Sets Z if it succeeded, unset it if there is no next. ; Sets Z if it succeeded, unset it if there is no next.
_symNext: _symNext:
xor a xor a
@ -73,31 +81,17 @@ symInit:
; Continue to symSelectGlobalRegistry ; Continue to symSelectGlobalRegistry
symSelectGlobalRegistry: symSelectGlobalRegistry:
push af
push hl push hl
ld hl, SYM_NAMES ld hl, SYM_GLOBAL_REGISTRY
ld (SYM_CTX_NAMES), hl ld (SYM_CTX), hl
ld hl, SYM_NAMES+SYM_BUFSIZE
ld (SYM_CTX_NAMESEND), hl
ld hl, SYM_VALUES
ld (SYM_CTX_VALUES), hl
pop hl pop hl
pop af
ret ret
symSelectLocalRegistry: symSelectLocalRegistry:
push af
push hl push hl
ld hl, SYM_LOC_NAMES ld hl, SYM_LOCAL_REGISTRY
ld (SYM_CTX_NAMES), hl ld (SYM_CTX), hl
ld hl, SYM_LOC_NAMES+SYM_LOC_BUFSIZE
ld (SYM_CTX_NAMESEND), hl
ld hl, SYM_LOC_VALUES
ld (SYM_CTX_VALUES), hl
ld a, h
ld a, l
pop hl pop hl
pop af
ret ret
; Sets Z according to whether label in (HL) is local (starts with a dot) ; Sets Z according to whether label in (HL) is local (starts with a dot)
@ -106,43 +100,51 @@ symIsLabelLocal:
cp (hl) cp (hl)
ret ret
; Place HL at the end of (SYM_CTX_NAMES) end (that is, at the point where we ; Given a registry in (IX), place HL at the end of its names that is, at the
; have two consecutive null chars and DE at the corresponding position in ; point where we have two consecutive null chars and DE at the corresponding
; SYM_CTX_VALUES). ; position in its values.
; If we're within bounds, Z is set, otherwise unset. ; If we're within bounds, Z is set, otherwise unset.
symNamesEnd: _symNamesEnd:
push ix push iy
push bc push bc
ld ix, (SYM_CTX_VALUES) ; IY --> values
ld hl, (SYM_CTX_NAMES) ld l, (ix+4)
ld de, (SYM_CTX_NAMESEND) ld h, (ix+5)
push hl \ pop iy
; HL --> names
ld l, (ix)
ld h, (ix+1)
; DE --> names end
ld e, (ix+2)
ld d, (ix+3)
.loop: .loop:
call _symNext call _symNext
jr nz, .success ; We've reached the end of the chain. jr nz, .success ; We've reached the end of the chain.
inc ix inc iy
inc ix inc iy
; Are we out of bounds name-wise? ; Are we out of bounds name-wise?
call cpHLDE call cpHLDE
jr nc, .outOfBounds ; HL >= DE jr nc, .outOfBounds ; HL >= DE
; are we out of bounds value-wise? check if IX == (SYM_CTX_NAMES) ; are we out of bounds value-wise? check if IY == (IX)'s names
; Is is assumed that values are placed right before names ; Is is assumed that values are placed right before names
push hl push hl
push ix \ pop bc push iy \ pop bc
ld hl, (SYM_CTX_NAMES) ld l, (ix)
ld h, (ix+1)
sbc hl, bc sbc hl, bc
pop hl pop hl
jr z, .outOfBounds ; IX == (SYM_CTX_NAMES) jr z, .outOfBounds ; IY == (IX)'s names
jr .loop jr .loop
.outOfBounds: .outOfBounds:
call unsetZ call unsetZ
jr .end jr .end
.success: .success:
push ix \ pop de ; our values pos goes in DE push iy \ pop de ; our values pos goes in DE
cp a ; ensure Z cp a ; ensure Z
.end: .end:
pop bc pop bc
pop ix pop iy
ret ret
; Register label in (HL) (minus the ending ":") into the symbol registry and ; Register label in (HL) (minus the ending ":") into the symbol registry and
@ -150,29 +152,33 @@ symNamesEnd:
; If successful, Z is set and A is the symbol index. Otherwise, Z is unset and ; If successful, Z is set and A is the symbol index. Otherwise, Z is unset and
; A is an error code (ERR_*). ; A is an error code (ERR_*).
symRegister: symRegister:
call symFind push ix ; --> lvl 1
ld ix, (SYM_CTX)
call _symFind
jr z, .alreadyThere jr z, .alreadyThere
push hl ; will be used during processing. it's the symbol to add push hl ; --> lvl 2. it's the symbol to add
push de ; will be used during processing. it's our value. push de ; --> lvl 3. it's our value.
; First, let's get our strlen ; First, let's get our strlen
call strlen call strlen
ld c, a ; save that strlen for later ld c, a ; save that strlen for later
call symNamesEnd call _symNamesEnd
jr nz, .outOfMemory jr nz, .outOfMemory
; Is our new name going to make us go out of bounds? ; Is our new name going to make us go out of bounds?
push hl push hl ; --> lvl 4
push de push de ; --> lvl 5
ld de, (SYM_CTX_NAMESEND) ld e, (ix+2)
ld d, (ix+3)
; DE --> names end
ld a, c ld a, c
call addHL call addHL
call cpHLDE call cpHLDE
pop de pop de ; <-- lvl 5
pop hl pop hl ; <-- lvl 4
jr nc, .outOfMemory ; HL >= DE jr nc, .outOfMemory ; HL >= DE
; Success. At this point, we have: ; Success. At this point, we have:
@ -183,11 +189,11 @@ symRegister:
; Let's start with the value. ; Let's start with the value.
push hl \ pop ix ; save HL for later push hl \ pop ix ; save HL for later
pop hl ; value to register pop hl ; <-- lvl 3. value to register
call writeHLinDE ; write value where it goes. call writeHLinDE ; write value where it goes.
; Good! now, the string. ; Good! now, the string.
pop hl ; string to register pop hl ; <-- lvl 2. string to register
push ix \ pop de ; string destination push ix \ pop de ; string destination
; Copy HL into DE until we reach null char ; Copy HL into DE until we reach null char
call strcpyM call strcpyM
@ -196,15 +202,16 @@ symRegister:
; list. DE is already correctly placed, A is already zero ; list. DE is already correctly placed, A is already zero
ld (de), a ld (de), a
pop ix ; <-- lvl 1
cp a ; ensure Z cp a ; ensure Z
; Nothing to pop. We've already popped our stack in the lines above.
ret ret
.outOfMemory: .outOfMemory:
ld a, ERR_OOM ld a, ERR_OOM
call unsetZ call unsetZ
pop de pop de ; <-- lvl 3
pop hl pop hl ; <-- lvl 2
pop ix ; <-- lvl 1
ret ret
.alreadyThere: .alreadyThere:
@ -224,51 +231,61 @@ symRegister:
; symbol names. So, if we end up in .alreadyThere during first pass, ; symbol names. So, if we end up in .alreadyThere during first pass,
; then it's an error condition. If it's not first pass, then we need ; then it's an error condition. If it's not first pass, then we need
; to update our value. ; to update our value.
; Let's pop our lvl 1 IX now, we don't need it any more.
pop ix ; <-- lvl 1
call zasmIsFirstPass call zasmIsFirstPass
jr z, .duplicateError jr z, .duplicateError
; Second pass. Don't error out, just update value ; Second pass. Don't error out, just update value
push hl push hl ; --> lvl 1
ld hl, (SYM_CTX_PTR) ld hl, (SYM_CTX_PTR)
ex de, hl ex de, hl
call writeHLinDE call writeHLinDE
pop hl pop hl ; <-- lvl 1
cp a ; ensure Z cp a ; ensure Z
ret ret
.duplicateError: .duplicateError:
ld a, ERR_DUPSYM ld a, ERR_DUPSYM
jp unsetZ ; return jp unsetZ ; return
; Find name (HL) in (SYM_CTX_NAMES) and make (SYM_CTX_PTR) point to the ; Assuming that IX points to a register context, find name HL in its names and
; corresponding entry in (SYM_CTX_VALUES). ; make the context pointer point to the corresponding entry in its values.
; If we find something, Z is set, otherwise unset. ; If we find something, Z is set, otherwise unset.
symFind: _symFind:
push ix push iy
push hl push hl
push de push de
ex de, hl ; it's easier if HL is haystack and DE is ex de, hl ; it's easier if HL is haystack and DE is
; needle. ; needle.
ld ix, (SYM_CTX_VALUES) ; IY --> values
ld hl, (SYM_CTX_NAMES) ld l, (ix+4)
ld h, (ix+5)
push hl \ pop iy
; HL --> names
ld l, (ix)
ld h, (ix+1)
.loop: .loop:
call strcmp call strcmp
jr z, .match jr z, .match
; ok, next! ; ok, next!
call _symNext call _symNext
jr nz, .nomatch ; end of the chain, nothing found jr nz, .nomatch ; end of the chain, nothing found
inc ix inc iy
inc ix inc iy
jr .loop jr .loop
.nomatch: .nomatch:
call unsetZ call unsetZ
jr .end jr .end
.match: .match:
ld (SYM_CTX_PTR), ix push iy \ pop hl
ld (SYM_CTX_PTR), hl
cp a ; ensure Z cp a ; ensure Z
.end: .end:
pop de pop de
pop hl pop hl
pop ix pop iy
ret ret
; For a given symbol name in (HL), find it in the appropriate symbol register ; For a given symbol name in (HL), find it in the appropriate symbol register
@ -277,15 +294,18 @@ symFind:
; always called when the global registry is selected. Therefore, we always ; always called when the global registry is selected. Therefore, we always
; reselect it afterwards. ; reselect it afterwards.
symFindVal: symFindVal:
push ix
ld ix, SYM_GLOBAL_REGISTRY
call symIsLabelLocal call symIsLabelLocal
jp nz, .notLocal jp nz, .notLocal
call symSelectLocalRegistry ld ix, SYM_LOCAL_REGISTRY
.notLocal: .notLocal:
call symFind call _symFind
jr nz, .end jr nz, .end
; Found! let's fetch value ; Found! let's fetch value
; Return value that (SYM_CTX_PTR) is pointing at in DE. ; Return value that (SYM_CTX_PTR) is pointing at in DE.
ld de, (SYM_CTX_PTR) ld de, (SYM_CTX_PTR)
call intoDE call intoDE
.end: .end:
jp symSelectGlobalRegistry pop ix
ret

Binary file not shown.

View File

@ -1,21 +0,0 @@
.equ RAMSTART 0x4000
.equ ACIA_CTL 0x80 ; Control and status. RS off.
.equ ACIA_IO 0x81 ; Transmit. RS on.
#include "err.h"
#include "core.asm"
#include "parse.asm"
.equ ACIA_RAMSTART RAMSTART
#include "acia.asm"
.equ BLOCKDEV_RAMSTART ACIA_RAMEND
.equ BLOCKDEV_COUNT 1
#include "blockdev.asm"
.dw aciaGetC, aciaPutC, 0, 0
.equ STDIO_RAMSTART BLOCKDEV_RAMEND
#include "stdio.asm"
.equ SHELL_RAMSTART STDIO_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 0
#include "shell.asm"

Binary file not shown.