forth: Replace "SKIP?" with "(?br)"

There is an alternate git history where I continued the Forth-ification of
words, including "SKIP?", but that was a bad idea: because that word was
written by flow control immediates, I stepped into quicksands where stability
became necessary in z80c.fs and I couldn't gracefully get out of it.

I'm stepping back and take this opportunity to replace the shoddy SKIP? algo
with a more straightforward (?br) implementation.

(br) and (?br) will always stay in boot code where it's easier manage a stable
ABI.
This commit is contained in:
Virgil Dupras 2020-03-29 09:10:23 -04:00
parent 9fcfebd84c
commit 48078d9c9c
7 changed files with 28 additions and 64 deletions

Binary file not shown.

View File

@ -2,17 +2,17 @@
: -^ SWAP - ; : -^ SWAP - ;
: [ INTERPRET 1 FLAGS ! ; IMMEDIATE : [ INTERPRET 1 FLAGS ! ; IMMEDIATE
: ] R> DROP ; : ] R> DROP ;
: LIT [ JTBL 26 + LITN ] , ; : LIT JTBL 26 + , ;
: LITS LIT SCPY ; : LITS LIT SCPY ;
: LIT< WORD LITS ; IMMEDIATE : LIT< WORD LITS ; IMMEDIATE
: _err LIT< word-not-found (print) ABORT ; : _err LIT< word-not-found (print) ABORT ;
: ' WORD (find) SKIP? _err ; : ' WORD (find) NOT (?br) [ 4 , ] _err ;
: ['] WORD (find) SKIP? _err LITN ; IMMEDIATE : ['] ' LITN ; IMMEDIATE
: COMPILE ' LITN ['] , , ; IMMEDIATE : COMPILE ' LITN ['] , , ; IMMEDIATE
: [COMPILE] ' , ; IMMEDIATE : [COMPILE] ' , ; IMMEDIATE
: BEGIN H@ ; IMMEDIATE : BEGIN H@ ; IMMEDIATE
: AGAIN COMPILE (br) H@ - , ; IMMEDIATE : AGAIN COMPILE (br) H@ - , ; IMMEDIATE
: UNTIL COMPILE SKIP? COMPILE (br) H@ - , ; IMMEDIATE : UNTIL COMPILE (?br) H@ - , ; IMMEDIATE
: ( BEGIN LIT< ) WORD SCMP NOT UNTIL ; IMMEDIATE : ( BEGIN LIT< ) WORD SCMP NOT UNTIL ; IMMEDIATE
( Hello, hello, krkrkrkr... do you hear me? ( Hello, hello, krkrkrkr... do you hear me?
Ah, voice at last! Some lines above need comments Ah, voice at last! Some lines above need comments
@ -29,8 +29,7 @@
: ALLOT HERE +! ; : ALLOT HERE +! ;
: IF ( -- a | a: br cell addr ) : IF ( -- a | a: br cell addr )
COMPILE SKIP? ( if true, don't branch ) COMPILE (?br)
COMPILE (br)
H@ ( push a ) H@ ( push a )
2 ALLOT ( br cell allot ) 2 ALLOT ( br cell allot )
; IMMEDIATE ; IMMEDIATE
@ -73,7 +72,7 @@
the RS ) the RS )
: LOOP : LOOP
COMPILE R> 1 LITN COMPILE + COMPILE DUP COMPILE >R COMPILE R> 1 LITN COMPILE + COMPILE DUP COMPILE >R
COMPILE I' COMPILE = COMPILE SKIP? COMPILE (br) COMPILE I' COMPILE = COMPILE (?br)
H@ - , H@ - ,
COMPILE R> COMPILE DROP COMPILE R> COMPILE DROP COMPILE R> COMPILE DROP COMPILE R> COMPILE DROP
; IMMEDIATE ; IMMEDIATE

View File

@ -73,10 +73,9 @@ Note about flow words: flow words can only be used in definitions. In the
INTERPRET loop, they don't have the desired effect because each word from the INTERPRET loop, they don't have the desired effect because each word from the
input stream is executed immediately. In this context, branching doesn't work. input stream is executed immediately. In this context, branching doesn't work.
(fbr) -- Branches forward by the number specified in its (br) -- Branches by the number specified in the 2 following
atom's cell. bytes. Can be negative.
(bbr) -- Branches backward by the number specified in its (?br) f -- Branch if f is false.
atom's cell.
[ -- Begin interetative mode. In a definition, words [ -- Begin interetative mode. In a definition, words
between here and "]" will be executed instead of between here and "]" will be executed instead of
compiled. compiled.
@ -92,9 +91,6 @@ INTERPRET -- Get a line from stdin, compile it in tmp memory,
then execute the compiled contents. then execute the compiled contents.
QUIT R:drop -- Return to interpreter prompt immediately QUIT R:drop -- Return to interpreter prompt immediately
RECURSE R:I -- R:I-2 Run the current word again. RECURSE R:I -- R:I-2 Run the current word again.
SKIP? f -- If f is true, skip the execution of the next atom.
Use this right before ";" and you're gonna have a
bad time.
THEN I:a -- *I* Set branching cell at a. THEN I:a -- *I* Set branching cell at a.
UNTIL f -- *I* Jump backwards to BEGIN if f is *false*. UNTIL f -- *I* Jump backwards to BEGIN if f is *false*.

View File

@ -670,61 +670,28 @@ BR:
ld (IP), hl ld (IP), hl
jp next jp next
; Skip the compword where HL is currently pointing. If it's a regular word, .fill 72
; 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. .db "(?br)"
.db "SKIP?"
.dw $-BR .dw $-BR
.db 5 .db 5
CSKIP: CBR:
.dw nativeWord .dw nativeWord
pop hl pop hl
call chkPS call chkPS
ld a, h ld a, h
or l or l
jp z, next ; False, do nothing. jp z, BR+2 ; False, branch
ld hl, (IP) ; True, skip next 2 bytes and don't branch
ld de, NUMBER ld hl, IP
call .HLPointsDE inc (hl)
jr z, .isNum inc (hl)
ld de, BR
call .HLPointsDE
jr z, .isNum
ld de, LIT
call .HLPointsDE
jr nz, .isWord
; We have a literal
inc hl \ inc hl
call strskip
inc hl ; byte after word termination
jr .end
.isNum:
; skip by 4
inc hl
inc hl
; continue to isWord
.isWord:
; skip by 2
inc hl \ inc hl
.end:
ld (IP), hl
jp next jp next
; Sets Z if (HL) == E and (HL+1) == D .fill 18
.HLPointsDE:
ld a, (hl)
cp e
ret nz ; no
inc hl
ld a, (hl)
dec hl
cp d ; Z has our answer
ret
.fill 45
.db "," .db ","
.dw $-CSKIP .dw $-CBR
.db 1 .db 1
WR: WR:
.dw nativeWord .dw nativeWord
@ -1046,3 +1013,5 @@ CMP:
.db "_bend" .db "_bend"
.dw $-CMP .dw $-CMP
.db 5 .db 5
; Offset: 06ee
.out $

View File

@ -54,7 +54,7 @@
( This is only the "early parser" in earlier stages. No need ( This is only the "early parser" in earlier stages. No need
for an abort message ) for an abort message )
: (parse) : (parse)
(parsed) SKIP? _c ABORT (parsed) NOT IF _c ABORT THEN
; ;
( a -- ) ( a -- )

View File

@ -75,10 +75,10 @@
; ;
: (parse) ( a -- n ) : (parse) ( a -- n )
(parsec) NOT SKIP? EXIT (parsec) IF EXIT THEN
(parseh) NOT SKIP? EXIT (parseh) IF EXIT THEN
(parseb) NOT SKIP? EXIT (parseb) IF EXIT THEN
(parsed) NOT SKIP? EXIT (parsed) IF EXIT THEN
( nothing works ) ( nothing works )
ABORT" unknown word! " ABORT" unknown word! "
; ;

View File

@ -4,6 +4,6 @@
: fail SPC ." failed" LF 1 1 PC! BYE ; : fail SPC ." failed" LF 1 1 PC! BYE ;
: # SKIP? fail SPC ." pass" LF ; : # IF SPC ." pass" LF ELSE fail THEN ;
: #eq 2DUP SWAP . SPC '=' EMIT SPC . '?' EMIT = # ; : #eq 2DUP SWAP . SPC '=' EMIT SPC . '?' EMIT = # ;