fix(v4.0.0): EXPECT, QUERY and WORD follow FORTH-79

Ruled 2026-10-04: standard words follow the standard where v3 did not.

EXPECT takes up to n characters (v3 took n-1) and does nothing for
n <= 0.  QUERY takes up to 80 (v3: 1024).  WORD stores the delimiter it
met, or a zero at the end of the text, after the word, and leaves >IN
just past that one delimiter (v3 skipped them all and stored a zero);
the word may be up to 255 characters (v3: 62).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-04 08:37:44 -04:00
co-authored by Claude Opus 5.5
parent 443439c3d2
commit 7b42a9b6c1
3 changed files with 123 additions and 101 deletions
+29 -23
View File
@@ -7,12 +7,11 @@
\ capsule: it runs on the host node. Rests on core.v4.
\
\ Constants the loader supplies:
\ TIB byte address of the text input buffer, #TIB bytes long
\ #TIB 1025: 1024 characters and a terminating zero, as v3
\ TIB byte address of the text input buffer; QUERY fills at most 81 bytes
\ >IN word address of the variable: offset in TIB of the next character
\ SPAN word address of the variable: how many characters the last
\ EXPECT or QUERY read
\ WBUF byte address of WORD's buffer, 64 bytes
\ WBUF byte address of WORD's buffer, 257 bytes
\ (P) word address of six cells of scratch for this file
\ TIB >IN SPAN and BL are in-line: written in a definition they are literals.
@@ -21,25 +20,26 @@ macro BL 32 endmacro
\ ( -- baddr u ) the input buffer and how much of it is in use
: SOURCE TIB SPAN a! @ -if P drop 0 P: ;
\ ( baddr u -- ) read a line into u bytes at baddr, as v3's fgets did: at
\ most u-1 characters, stopping after a new-line, which is taken but not
\ stored; then a zero. A line of u-1 characters or more leaves what did not
\ fit, its new-line included, to be read next. SPAN is the number of characters stored. With u = 0
\ nothing is read or stored; u < 0 does nothing and sets NODE-ERROR.
\ ( baddr n -- ) FORTH-79: characters from the terminal are stored from
\ baddr upward until a new-line or until n have been received; the new-line
\ is taken but not stored. A zero is added after the text, so the buffer
\ must hold n + 1 bytes. No action for n <= 0. SPAN is how many characters
\ were stored (SPAN is not FORTH-79; v3 has it). A line longer than n leaves
\ the rest, its new-line included, to be read next.
: EXPECT
-if OK drop drop NODE-ERROR b! -1 !b ;
OK: if ZERO
-if NN drop drop ; \ n < 0
NN: if ZERO
over push \ p n R: start
L: -1 + if END \ room for the zero only
L: if END
push KEY dup -10 + if NL \ p c x R: start n
drop over C! 1 + pop jump L
drop over C! 1 + pop -1 + jump L
NL: drop drop pop
END: drop 0 over C! \ p
pop - SPAN a! ! ;
ZERO: drop drop 0 SPAN a! ! ;
ZERO: drop drop ;
\ ( -- ) read a line into TIB and start at its beginning
: QUERY TIB #TIB EXPECT 0 >IN a! ! ;
\ ( -- ) FORTH-79: up to 80 characters, or a line, into TIB; >IN to 0.
: QUERY TIB 80 EXPECT 0 >IN a! ! ;
\ ---- WORD ------------------------------------------------------------------
\ (P)+0 the delimiter, (P)+1 the length of the text in TIB.
@@ -56,21 +56,26 @@ macro (WLEN) (P) 1 + endmacro
L: (LEFT) -if E drop (CH) if E drop 1 + jump L
E: drop ;
\ ( c -- baddr ) the next word of TIB delimited by c, as a counted string
\ in WBUF with a zero after it. Leading delimiters are skipped; so, as in
\ v3, are all those that follow the word. A word longer than 62 characters
\ is cut to 62. At the end of the text the count is 0.
\ ( c -- baddr ) FORTH-79: characters are taken from TIB until the
\ delimiter c or the end of the text, leading delimiters ignored, and stored
\ in WBUF as a counted string. The delimiter met -- c, or a zero if the text
\ ran out -- is stored after them and is not counted. >IN is left just past
\ that delimiter. With nothing left the count is 0. The count is a byte,
\ so a word longer than 255 characters is cut to 255.
: WORD
255 and (WDELIM) a! !
SPAN a! @ -if A drop 0 A: (WLEN) a! !
>IN a! @ -if B drop 0 B:
(SKIP) dup push (SCAN) \ end R: start
pop over over - \ end start len
dup -63 + -if CAP drop jump FITS CAP: drop drop 62 FITS:
dup -256 + -if CAP drop jump FITS CAP: drop drop 255 FITS:
dup WBUF C!
dup push push TIB + WBUF 1 + pop CMOVE \ end R: len
0 pop WBUF + 1 + C!
(SKIP) >IN a! ! WBUF ;
(LEFT) -if RANOUT
drop (WDELIM) a! @ pop WBUF + 1 + C! \ the delimiter after the text
1 + >IN a! ! WBUF ;
RANOUT: drop 0 pop WBUF + 1 + C!
>IN a! ! WBUF ;
\ ---- ENCLOSE ---------------------------------------------------------------
\ (P)+0 the delimiter, (P)+1 the string's address.
@@ -120,7 +125,8 @@ macro (WLEN) (P) 1 + endmacro
\ the current BASE; it may begin with a minus sign. If it is empty, is only
\ a sign, or holds anything that is not a digit, the result is 0 and
\ NODE-ERROR is set. The character after the string must not be a digit
\ (WORD puts a zero there); if it is, that too is reported as an error. (P)+3 the address of its last character, (P)+4 the sign.
\ (WORD puts the delimiter or a zero there); if it is, that too is reported
\ as an error. (P)+3 the address of its last character, (P)+4 the sign.
: NUMBER
dup C@ if ERR2
over + (P) 3 + a! ! \ baddr