Layer 5 of the compiler capsule. The host node is now started at QUIT and left running: it prompts, reads a line from its console with QUERY, interprets it, says " ok" or " ERROR", and goes round again. - capsule/quit.v4: QUIT and ABORT (FORTH-79), ABORT" and (ABORT") as v3 has them, ." and (.") (FORTH-79). Text is compiled as a counted string after the call; the run-time word returns to the cell after it. - INTERPRET prints v3's messages before abandoning a line: UNKNOWN WORD: 'xxx' and xxx: compile-only. - core.v4: CR SPACE COUNT TYPE, as DECOMPOSITION.md gives them. - input.v4: WORD split so that (PARSE) can take text without skipping leading delimiters (." " is an empty string); EXPECT keeps its place in memory, so six values may wait on the stack while a line is typed. - tests/test_host_quit.c: the node is fed characters and its output read; 16 sessions are transcripts of the v3 binary. QUIT stops the line from inside any word and says nothing; v3's goes on with the line and cannot be compiled. v3's compiled ABORT" crashes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
112 lines
4.4 KiB
Plaintext
112 lines
4.4 KiB
Plaintext
\ quit.v4 -- the prompt: lines read from the console and interpreted, one
|
|
\ after another, for as long as the node runs; and the words that print text
|
|
\ written in the source.
|
|
\
|
|
\ DECOMPOSITION.md 5.15 and 5.10: QUIT ABORT ABORT" (ABORT") ." (."). Part of
|
|
\ the compiler capsule. Rests on all the files before it.
|
|
\
|
|
\ WHAT THE CONSOLE SHOWS, as v3:
|
|
\ ok> 65 EMIT the prompt, then the line as it is typed
|
|
\ A ok what the line printed, then " ok"
|
|
\ ok> NOSUCH
|
|
\ UNKNOWN WORD: 'NOSUCH'
|
|
\ ERROR any line that sets NODE-ERROR ends so
|
|
\ The line itself is not sent back: the terminal shows what is typed.
|
|
\
|
|
\ THE RETURN STACK is circular (D-2): it has no bottom to be reset to, and
|
|
\ what is on it is simply never returned to once QUIT stops returning. So
|
|
\ QUIT and ABORT "clear" it by jumping into the loop, from however deep. The
|
|
\ data stack is circular too: ABORT has nothing to clear.
|
|
\
|
|
\ Constants the loader supplies:
|
|
\ (Q) word address of two cells of scratch for this file
|
|
|
|
\ ( -- ) stop compiling; forget the word being built and any open control
|
|
\ structures. A definition that was under way stays hidden.
|
|
: (RESET) 0 STATE a! ! (CG-RESET) CFBASE (CFP) a! ! ;
|
|
|
|
\ ( k -- ) the loop. It is entered with what to say first -- 0 nothing,
|
|
\ 1 " ok", anything else " ERROR" -- and never returns. Each line is
|
|
\ interpreted with one return entry under it, this word's call of INTERPRET.
|
|
: (REPL)
|
|
if GO -1 + if OK
|
|
drop (RESET) $52524520 (EMIT4) $524F (EMIT4) CR jump READ \ " ERROR"
|
|
OK: drop $6B6F20 (EMIT4) CR jump READ \ " ok"
|
|
GO: drop
|
|
READ:
|
|
$203E6B6F (EMIT4) \ "ok> "
|
|
QUERY
|
|
0 NODE-ERROR b! !b
|
|
INTERPRET
|
|
NODE-ERROR b! @b if GOOD
|
|
drop 2 jump (REPL)
|
|
GOOD: drop 1 jump (REPL)
|
|
|
|
\ FORTH-79: clear the return stack, set execution mode, return control to
|
|
\ the terminal; no message is given. The data stack is left as it is.
|
|
header QUIT
|
|
: QUIT (RESET) CR 0 jump (REPL)
|
|
|
|
\ FORTH-79: clear the data and return stacks, set execution mode, return
|
|
\ control to the terminal. As v3, the line it stops ends with " ok".
|
|
header ABORT
|
|
: ABORT (RESET) 1 jump (REPL)
|
|
|
|
\ ---- text in the source ---------------------------------------------------------
|
|
\ ." and ABORT" take the text up to the next " , which may be none at all
|
|
\ (input.v4's (PARSE)); with no closing " it is the rest of the line. Inside a definition they lay
|
|
\ down a call to their run-time word and, after it, the text as a counted
|
|
\ string: the count byte and the characters, four to a cell, the last cell
|
|
\ filled with zeros. The run-time word finds the string by the return
|
|
\ address the call left, and returns to the cell after the string.
|
|
|
|
\ ( -- ) lay the counted string in WBUF into the dictionary, as above.
|
|
\ (Q)+0 how many bytes are still to go, (Q)+1 which is next.
|
|
: (STRING,)
|
|
(FLUSH)
|
|
WBUF C@ 1 + (Q) a! ! 0 (Q)+1 a! !
|
|
L: (Q) a! @ if DONE -1 + !
|
|
(Q)+1 a! @ dup 1 + ! WBUF + C@ C,
|
|
jump L
|
|
DONE: drop
|
|
P: DP b! @b 3 and if ALIGNED drop 0 C, jump P
|
|
ALIGNED: drop ;
|
|
|
|
\ The run time of ." : print the string after the call, go on after it.
|
|
\ It takes the return address off before it calls anything and keeps the
|
|
\ count there instead, so a word that prints text goes no deeper than one
|
|
\ that calls any other word.
|
|
: (.")
|
|
pop 4* dup C@ \ baddr n
|
|
L: if DONE
|
|
push 1 + dup C@ EMIT pop -1 + jump L
|
|
DONE: drop 4/ 1 + push ; \ the cell after the last character
|
|
|
|
\ FORTH-79: ." text" prints the text -- now, if interpreting; when the word
|
|
\ it is compiled into runs, if compiling.
|
|
header ." immediate
|
|
: DOT-QUOTE
|
|
34 (PARSE) drop
|
|
STATE a! @ if NOW
|
|
drop &(.") (CALL,) jump (STRING,)
|
|
NOW: drop WBUF COUNT jump TYPE
|
|
|
|
\ ( flag -- ) the run time of ABORT" : if the flag is not zero print the
|
|
\ string after the call, start a new line and ABORT; otherwise go on after
|
|
\ the string.
|
|
: (ABORT")
|
|
if NO
|
|
drop pop 4* COUNT TYPE CR jump ABORT
|
|
NO: drop pop 4* dup C@ + 4/ 1 + push ;
|
|
|
|
\ ( flag -- ) ABORT" text" as v3 (it is FORTH-83's, not FORTH-79's): if
|
|
\ the flag is not zero, print the text and ABORT.
|
|
header ABORT" immediate
|
|
: ABORT-QUOTE
|
|
34 (PARSE) drop
|
|
STATE a! @ if NOW
|
|
drop &(ABORT") (CALL,) jump (STRING,)
|
|
NOW: drop if NO
|
|
drop WBUF COUNT TYPE CR jump ABORT
|
|
NO: drop ;
|