forth: improve input flow

Readline, instead of being triggered by the end of execution of the last
compiled line is now triggered "just in time", by "WORD".

This allows IMMEDIATE words reading input buffer to span multiple lines
( comments for example, but colon definitions will soon follow ).
This commit is contained in:
Virgil Dupras 2020-03-14 19:10:39 -04:00
parent e1f815baeb
commit 7befe56597
5 changed files with 56 additions and 33 deletions

View File

@ -7,18 +7,18 @@
: NOT 1 SWAP SKIP? EXIT 0 * ;
: RECURSE R> R> 2 - >R >R EXIT ;
: ( LIT@ ) WORD SCMP NOT SKIP? RECURSE ; IMMEDIATE
( Hello, hello, krkrkrkr... do you hear me? )
( Ah, voice at last! Some lines above need comments )
( BTW: Forth lines limited to 64 cols because of default )
( input buffer size in Collapse OS )
( NOT: a bit convulted because we don't have IF yet )
( RECURSE: RS TOS is for RECURSE itself, then we have to dig )
( one more level to get to RECURSE's parent's caller. )
( IF true, skip following (fbr). Also, push br cell ref H, )
( to PS )
( Hello, hello, krkrkrkr... do you hear me?
Ah, voice at last! Some lines above need comments
BTW: Forth lines limited to 64 cols because of default
input buffer size in Collapse OS
NOT: a bit convulted because we don't have IF yet
RECURSE: RS TOS is for RECURSE itself, then we have to dig
one more level to get to RECURSE's parent's caller.
IF true, skip following (fbr). Also, push br cell ref H,
to PS )
: IF ['] SKIP? , ['] (fbr) , H 1 ALLOT ; IMMEDIATE
( Subtract TOS from H to get offset to write to IF or ELSE's )
( br cell )
( Subtract TOS from H to get offset to write to IF or ELSE's
br cell )
: THEN DUP H -^ SWAP C! ; IMMEDIATE
( write (fbr) addr, allot, then same as THEN )
: ELSE ['] (fbr) , 1 ALLOT DUP H -^ SWAP C! H 1 - ; IMMEDIATE

View File

@ -468,10 +468,18 @@ CURRENT_:
.dw sysvarWord
.dw CURRENT
.db "IN>"
.fill 4
.dw CURRENT_
.db 0
INP:
.dw sysvarWord
.dw INPUTPOS
; ( n -- )
.db "."
.fill 6
.dw CURRENT_
.dw INP
.db 0
DOT:
.dw nativeWord

View File

@ -112,10 +112,21 @@ LIT@ x -- a Read following LIT and push its addr to a
SCMP a1 a2 -- n Compare strings a1 and a2. See CMP
*** I/O ***
A little word about inputs. There are two kind of inputs: direct and buffered.
As a general rule, we read line in a buffer, then feed words in it to the
interpreter. That's what "WORD" does. If it's at the End Of Line, it blocks and
wait until another line is entered.
KEY input, however, is direct. Regardless of the input buffer's state, KEY will
return the next typed key.
. n -- Print n in its decimal form
EMIT c -- Spit char c to stdout
KEY -- c Get char c from stdin
EMIT c -- Spit char c to output stream
IN> -- a Address of variable containing current pos in input
buffer.
KEY -- c Get char c from direct input
PC! c a -- Spit c to port a
PC@ a -- c Fetch c from port a
WORD -- a Read one word from stdin and push its addr
WORD -- a Read one word from buffered input and push its addr

View File

@ -102,13 +102,15 @@ forthMain:
ld (CURRENT), hl
ld hl, HERE_INITIAL
ld (HERE), hl
; Set (INPUTPOS) to somewhere where there's a NULL so we consider
; ourselves EOL.
ld (INPUTPOS), hl
xor a
ld (hl), a
forthRdLine:
ld hl, msgOk
call printstr
forthRdLineNoOk:
call printcrlf
call stdioReadLine
ld (INPUTPOS), hl
; Setup return stack. After INTERPRET, we run forthExecLine
ld ix, RS_ADDR
; We're about to compile the line and possibly execute IMMEDIATE words.
@ -146,24 +148,18 @@ forthExecLine:
; (we don't have RECURSE here. Calling interpret makes us needlessly use our
; RS stack, but it can take it, can't it? )
; WORD DUP C@ (to check if null) SKIP? (skip if not null) EXIT COMPILE INTERPRET
; WORD COMPILE IN> @ C@ (to check if null) SKIP? (skip if not null) EXIT INTERPRET
.db 0b10 ; UNWORD
INTERPRET:
.dw compiledWord
.dw WORD
.dw DUP
.dw COMPILE
.dw INP
.dw FETCH
.dw CFETCH
.dw CSKIP
.dw .stop
.dw COMPILE
.dw INTERPRET
.dw EXIT
.stop:
.dw compiledWord
.dw DROP
.dw R2P
.dw DROP
.dw INTERPRET
.dw EXIT
msgOk:

View File

@ -7,7 +7,8 @@ pad:
; Read word from (INPUTPOS) and return, in HL, a null-terminated word.
; Advance (INPUTPOS) to the character following the whitespace ending the
; word.
; Z set of word was read, unset if end of line.
; When we're at EOL, we call fetchline directly, so this call always returns
; a word.
readword:
ld hl, (INPUTPOS)
; skip leading whitespace
@ -16,6 +17,7 @@ readword:
inc hl
ld a, (hl)
or a
; When at EOL, fetch a new line directly
jr z, .empty
cp ' '+1
jr c, .loop1
@ -39,9 +41,8 @@ readword:
pop hl ; <-- lvl 1. our result
ret ; Z set from XOR A
.empty:
ld (hl), a
inc a ; unset Z
ret
call fetchline
jr readword
; Sets Z if (HL) == E and (HL+1) == D
HLPointsDE:
@ -336,3 +337,10 @@ DEinHL:
ld (hl), d
inc hl
ret
fetchline:
call printcrlf
call stdioReadLine
ld (INPUTPOS), hl
ret