mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-30 22:48:08 +11:00
forth: make readCompWord read from RS' BOS instead of TOS
Previous approach was broken with regards to defined word using CREATE. Also, reduce name length by one to make space for a new flags field for "immediate" (which isn't used yet).
This commit is contained in:
parent
0e8af3cea4
commit
03bd9ee39b
@ -1,5 +1,6 @@
|
|||||||
; A dictionary entry has this structure:
|
; A dictionary entry has this structure:
|
||||||
; - 8b name (zero-padded)
|
; - 7b name (zero-padded)
|
||||||
|
; - 1b flags (bit 0: IMMEDIATE)
|
||||||
; - 2b prev pointer
|
; - 2b prev pointer
|
||||||
; - 2b code pointer
|
; - 2b code pointer
|
||||||
; - Parameter field (PF)
|
; - Parameter field (PF)
|
||||||
@ -168,14 +169,16 @@ exit:
|
|||||||
jp compiledWord
|
jp compiledWord
|
||||||
|
|
||||||
; ( R:I -- )
|
; ( R:I -- )
|
||||||
.db "QUIT", 0, 0, 0, 0
|
.db "QUIT"
|
||||||
|
.fill 4
|
||||||
.dw EXIT
|
.dw EXIT
|
||||||
QUIT:
|
QUIT:
|
||||||
.dw nativeWord
|
.dw nativeWord
|
||||||
quit:
|
quit:
|
||||||
jp forthRdLine
|
jp forthRdLine
|
||||||
|
|
||||||
.db "ABORT", 0, 0, 0
|
.db "ABORT"
|
||||||
|
.fill 3
|
||||||
.dw QUIT
|
.dw QUIT
|
||||||
ABORT:
|
ABORT:
|
||||||
.dw nativeWord
|
.dw nativeWord
|
||||||
@ -198,7 +201,8 @@ BYE:
|
|||||||
ret
|
ret
|
||||||
|
|
||||||
; ( c -- )
|
; ( c -- )
|
||||||
.db "EMIT", 0, 0, 0, 0
|
.db "EMIT"
|
||||||
|
.fill 4
|
||||||
.dw BYE
|
.dw BYE
|
||||||
EMIT:
|
EMIT:
|
||||||
.dw nativeWord
|
.dw nativeWord
|
||||||
@ -208,7 +212,8 @@ EMIT:
|
|||||||
jp exit
|
jp exit
|
||||||
|
|
||||||
; ( addr -- )
|
; ( addr -- )
|
||||||
.db "EXECUTE", 0
|
.db "EXECUTE"
|
||||||
|
.db 0
|
||||||
.dw EMIT
|
.dw EMIT
|
||||||
EXECUTE:
|
EXECUTE:
|
||||||
.dw nativeWord
|
.dw nativeWord
|
||||||
@ -239,19 +244,18 @@ DEFINE:
|
|||||||
; All we need to do is to know how many bytes to copy. To do so, we
|
; All we need to do is to know how many bytes to copy. To do so, we
|
||||||
; skip compwords until EXIT is reached.
|
; skip compwords until EXIT is reached.
|
||||||
ld (HERE), hl ; where we write compwords.
|
ld (HERE), hl ; where we write compwords.
|
||||||
; Let's save old RS TOS
|
ld l, (ix)
|
||||||
ld e, (ix)
|
ld h, (ix+1)
|
||||||
ld d, (ix+1)
|
|
||||||
.loop:
|
.loop:
|
||||||
call RSIsEXIT
|
call HLPointsEXIT
|
||||||
jr z, .loopend
|
jr z, .loopend
|
||||||
call compSkip
|
call compSkip
|
||||||
jr .loop
|
jr .loop
|
||||||
.loopend:
|
.loopend:
|
||||||
; At this point, RS' TOS points to EXIT compword. We'll copy it too.
|
; At this point, HL points to EXIT compword. We'll copy it too.
|
||||||
; We'll use LDIR. BC will be RSTOP-OLDRSTOP+2
|
; We'll use LDIR. BC will be RSTOP-OLDRSTOP+2
|
||||||
ld l, (ix)
|
ld e, (ix)
|
||||||
ld h, (ix+1)
|
ld d, (ix+1)
|
||||||
inc hl \ inc hl ; our +2
|
inc hl \ inc hl ; our +2
|
||||||
or a ; clear carry
|
or a ; clear carry
|
||||||
sbc hl, de
|
sbc hl, de
|
||||||
@ -267,7 +271,8 @@ DEFINE:
|
|||||||
ld (HERE), de ; update HERE
|
ld (HERE), de ; update HERE
|
||||||
jp exit
|
jp exit
|
||||||
|
|
||||||
.db "DOES>", 0, 0, 0
|
.db "DOES>"
|
||||||
|
.fill 3
|
||||||
.dw DEFINE
|
.dw DEFINE
|
||||||
DOES:
|
DOES:
|
||||||
.dw nativeWord
|
.dw nativeWord
|
||||||
@ -300,7 +305,8 @@ KEY:
|
|||||||
push hl
|
push hl
|
||||||
jp exit
|
jp exit
|
||||||
|
|
||||||
.db "INTERPRE"
|
.db "INTERPR"
|
||||||
|
.db 0
|
||||||
.dw KEY
|
.dw KEY
|
||||||
INTERPRET:
|
INTERPRET:
|
||||||
.dw nativeWord
|
.dw nativeWord
|
||||||
@ -317,7 +323,8 @@ interpret:
|
|||||||
ld iy, COMPBUF
|
ld iy, COMPBUF
|
||||||
jp compiledWord
|
jp compiledWord
|
||||||
|
|
||||||
.db "CREATE", 0, 0
|
.db "CREATE"
|
||||||
|
.fill 2
|
||||||
.dw INTERPRET
|
.dw INTERPRET
|
||||||
CREATE:
|
CREATE:
|
||||||
.dw nativeWord
|
.dw nativeWord
|
||||||
@ -338,7 +345,8 @@ HERE_: ; Caution: conflicts with actual variable name
|
|||||||
.dw sysvarWord
|
.dw sysvarWord
|
||||||
.dw HERE
|
.dw HERE
|
||||||
|
|
||||||
.db "CURRENT", 0
|
.db "CURRENT"
|
||||||
|
.db 0
|
||||||
.dw HERE_
|
.dw HERE_
|
||||||
CURRENT_:
|
CURRENT_:
|
||||||
.dw sysvarWord
|
.dw sysvarWord
|
||||||
@ -514,7 +522,8 @@ STOREINC:
|
|||||||
|
|
||||||
; ( n -- )
|
; ( n -- )
|
||||||
; HERE +!
|
; HERE +!
|
||||||
.db "ALLOT", 0, 0, 0
|
.db "ALLOT"
|
||||||
|
.fill 3
|
||||||
.dw STOREINC
|
.dw STOREINC
|
||||||
ALLOT:
|
ALLOT:
|
||||||
.dw compiledWord
|
.dw compiledWord
|
||||||
@ -523,7 +532,8 @@ ALLOT:
|
|||||||
.dw EXIT
|
.dw EXIT
|
||||||
|
|
||||||
; CREATE 2 ALLOT
|
; CREATE 2 ALLOT
|
||||||
.db "VARIABLE"
|
.db "VARIABL"
|
||||||
|
.db 0
|
||||||
.dw ALLOT
|
.dw ALLOT
|
||||||
VARIABLE:
|
VARIABLE:
|
||||||
.dw compiledWord
|
.dw compiledWord
|
||||||
@ -535,7 +545,8 @@ VARIABLE:
|
|||||||
|
|
||||||
; ( n -- )
|
; ( n -- )
|
||||||
; CREATE HERE @ ! DOES> @
|
; CREATE HERE @ ! DOES> @
|
||||||
.db "CONSTANT"
|
.db "CONSTAN"
|
||||||
|
.db 0
|
||||||
.dw VARIABLE
|
.dw VARIABLE
|
||||||
CONSTANT:
|
CONSTANT:
|
||||||
.dw compiledWord
|
.dw compiledWord
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
; Number of bytes we keep as a padding between HERE and the scratchpad
|
; Number of bytes we keep as a padding between HERE and the scratchpad
|
||||||
.equ PADDING 0x20
|
.equ PADDING 0x20
|
||||||
; Max length of dict entry names
|
; Max length of dict entry names
|
||||||
.equ NAMELEN 8
|
.equ NAMELEN 7
|
||||||
; Offset of the code link relative to the beginning of the word
|
; Offset of the code link relative to the beginning of the word
|
||||||
.equ CODELINK_OFFSET NAMELEN+2
|
.equ CODELINK_OFFSET NAMELEN+3
|
||||||
|
|
||||||
; *** Variables ***
|
; *** Variables ***
|
||||||
.equ INITIAL_SP FORTH_RAMSTART
|
.equ INITIAL_SP FORTH_RAMSTART
|
||||||
|
@ -43,78 +43,78 @@ readword:
|
|||||||
inc a ; unset Z
|
inc a ; unset Z
|
||||||
ret
|
ret
|
||||||
|
|
||||||
RSIsDE:
|
; Sets Z if (HL) == E and (HL+1) == D
|
||||||
push hl
|
HLPointsDE:
|
||||||
ld l, (ix)
|
|
||||||
ld h, (ix+1)
|
|
||||||
ld a, (hl)
|
ld a, (hl)
|
||||||
cp e
|
cp e
|
||||||
jr nz, .end ; no
|
ret nz ; no
|
||||||
inc hl
|
inc hl
|
||||||
ld a, (hl)
|
ld a, (hl)
|
||||||
|
dec hl
|
||||||
cp d ; Z has our answer
|
cp d ; Z has our answer
|
||||||
.end:
|
|
||||||
pop hl
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
; Is RS' TOS pointing to a NUMBER word?
|
HLPointsNUMBER:
|
||||||
; Z if yes, NZ if no.
|
|
||||||
RSIsNUMBER:
|
|
||||||
push de
|
push de
|
||||||
ld de, NUMBER
|
ld de, NUMBER
|
||||||
call RSIsDE
|
call HLPointsDE
|
||||||
pop de
|
pop de
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Is RS' TOS pointing to a LIT word?
|
HLPointsLIT:
|
||||||
; Z if yes, NZ if no.
|
|
||||||
RSIsLIT:
|
|
||||||
push de
|
push de
|
||||||
ld de, LIT
|
ld de, LIT
|
||||||
call RSIsDE
|
call HLPointsDE
|
||||||
pop de
|
pop de
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Is RS' TOS pointing to EXIT?
|
HLPointsEXIT:
|
||||||
; Z if yes, NZ if no.
|
|
||||||
RSIsEXIT:
|
|
||||||
push de
|
push de
|
||||||
ld de, EXIT
|
ld de, EXIT
|
||||||
call RSIsDE
|
call HLPointsDE
|
||||||
pop de
|
pop de
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Skip the compword where RS' TOS is currently pointing. If it's a regular word,
|
; Skip the compword where HL is currently pointing. If it's a regular word,
|
||||||
; it's easy: we inc by 2. If it's a NUMBER, we inc by 4. If it's a LIT, we skip
|
; it's easy: we inc by 2. If it's a NUMBER, we inc by 4. If it's a LIT, we skip
|
||||||
; to after null-termination.
|
; to after null-termination.
|
||||||
compSkip:
|
compSkip:
|
||||||
push hl
|
call HLPointsNUMBER
|
||||||
ld l, (ix)
|
|
||||||
ld h, (ix+1)
|
|
||||||
; At the minimum, we skip by 2
|
|
||||||
inc hl \ inc hl
|
|
||||||
call RSIsNUMBER
|
|
||||||
jr z, .isNum
|
jr z, .isNum
|
||||||
call RSIsLIT
|
call HLPointsLIT
|
||||||
jr nz, .end ; A word
|
jr nz, .isWord
|
||||||
; We have a literal
|
; We have a literal
|
||||||
|
inc hl \ inc hl
|
||||||
call strskip
|
call strskip
|
||||||
inc hl ; byte after word termination
|
inc hl ; byte after word termination
|
||||||
jr .end
|
ret
|
||||||
.isNum:
|
.isNum:
|
||||||
; skip by 4
|
; skip by 4
|
||||||
inc hl \ inc hl
|
inc hl \ inc hl
|
||||||
.end:
|
; continue to isWord
|
||||||
; HL is good, write it to RS
|
.isWord:
|
||||||
ld (ix), l
|
; skip by 2
|
||||||
ld (ix+1), h
|
inc hl \ inc hl
|
||||||
pop hl
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Checks RS' TOS and, if it points to a string literal (LIT), makes HL point
|
; The goal of this routine is to read a string literal following the currently
|
||||||
; to it and advance IP to byte following null-termination.
|
; executed words. For example, CREATE and DEFINE need this. Things are a little
|
||||||
; If it doesn't, things get interesting: If it's a word reference, then it's
|
; twisted, so bear with me while I explain how it works.
|
||||||
|
;
|
||||||
|
; When we call this routine, everything has been compiled. We're on an atom and
|
||||||
|
; we're executing it. Now, we're looking for a string literal or a word-with-a
|
||||||
|
; name that follows our readCompWord caller. We could think that this word is
|
||||||
|
; right there on RS' TOS, but no! You have to account for words wrapping the
|
||||||
|
; caller. For example, "VARIABLE" calls "CREATE". If you call "VARIABLE foo",
|
||||||
|
; if CREATE looks at what follows in RS' TOS, it will only find the "2" in
|
||||||
|
; "CREATE 2 ALLOT".
|
||||||
|
;
|
||||||
|
; Therefore, we actually need to check in RS' *bottom of stack* for our answer.
|
||||||
|
; If that atom is a LIT, we're good. We make HL point to it and advance IP to
|
||||||
|
; byte following null-termination.
|
||||||
|
;
|
||||||
|
; If it isn't, things get interesting: If it's a word reference, then it's
|
||||||
; not an invalid literal. For example, one could want to redefine an existing
|
; not an invalid literal. For example, one could want to redefine an existing
|
||||||
; word. So in that case, we'll copy the word's name on the pad (it might not be
|
; word. So in that case, we'll copy the word's name on the pad (it might not be
|
||||||
; null-terminated) and set HL to point to it.
|
; null-terminated) and set HL to point to it.
|
||||||
@ -124,18 +124,22 @@ compSkip:
|
|||||||
; word. Yeah, it means that ";" can't be overridden...
|
; word. Yeah, it means that ";" can't be overridden...
|
||||||
; If name can't be read, we abort
|
; If name can't be read, we abort
|
||||||
readCompWord:
|
readCompWord:
|
||||||
; In all cases, we want RS' TOS in HL. Let's get it now.
|
; In all cases, we want RS' BOS in HL. Let's get it now.
|
||||||
ld l, (ix)
|
ld hl, (RS_ADDR)
|
||||||
ld h, (ix+1)
|
call HLPointsLIT
|
||||||
call RSIsLIT
|
|
||||||
jr nz, .notLIT
|
jr nz, .notLIT
|
||||||
; RS TOS is a LIT, make HL point to string, then skip this RS compword.
|
; RS BOS is a LIT, make HL point to string, then skip this RS compword.
|
||||||
inc hl \ inc hl ; HL now points to string itself
|
inc hl \ inc hl ; HL now points to string itself
|
||||||
jr compSkip
|
push hl ; --> lvl 1, our result
|
||||||
|
call strskip
|
||||||
|
inc hl ; byte after word termination
|
||||||
|
ld (RS_ADDR), hl
|
||||||
|
pop hl ; <-- lvl 1, our result
|
||||||
|
ret
|
||||||
.notLIT:
|
.notLIT:
|
||||||
; Alright, not a literal, but is it a word? If it's not a number, then
|
; Alright, not a literal, but is it a word? If it's not a number, then
|
||||||
; it's a word.
|
; it's a word.
|
||||||
call RSIsNUMBER
|
call HLPointsNUMBER
|
||||||
jr z, .notWord
|
jr z, .notWord
|
||||||
; Not a number, then it's a word. Copy word to pad and point to it.
|
; Not a number, then it's a word. Copy word to pad and point to it.
|
||||||
call intoHL
|
call intoHL
|
||||||
@ -153,7 +157,9 @@ readCompWord:
|
|||||||
; null-terminate
|
; null-terminate
|
||||||
xor a
|
xor a
|
||||||
ld (de), a
|
ld (de), a
|
||||||
call compSkip
|
; Advance RS' BOS by 2
|
||||||
|
ld hl, RS_ADDR
|
||||||
|
inc (hl) \ inc (hl)
|
||||||
pop hl ; <-- lvl 1
|
pop hl ; <-- lvl 1
|
||||||
ret
|
ret
|
||||||
.notWord:
|
.notWord:
|
||||||
@ -251,13 +257,15 @@ compile:
|
|||||||
; HL points to new (HERE)
|
; HL points to new (HERE)
|
||||||
entryhead:
|
entryhead:
|
||||||
call readCompWord
|
call readCompWord
|
||||||
call printstr
|
|
||||||
ld de, (HERE)
|
ld de, (HERE)
|
||||||
call strcpy
|
call strcpy
|
||||||
ex de, hl ; (HERE) now in HL
|
ex de, hl ; (HERE) now in HL
|
||||||
ld de, (CURRENT)
|
ld de, (CURRENT)
|
||||||
ld a, NAMELEN
|
ld a, NAMELEN
|
||||||
call addHL
|
call addHL
|
||||||
|
xor a ; IMMED
|
||||||
|
ld (hl), a
|
||||||
|
inc hl
|
||||||
ld (hl), e
|
ld (hl), e
|
||||||
inc hl
|
inc hl
|
||||||
ld (hl), d
|
ld (hl), d
|
||||||
|
Loading…
Reference in New Issue
Block a user