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