JimBoyd wrote:
... FIG Forth's
INTERPRET does look like an endless loop, but it isn't. When the text stream is exhausted
WORD leaves a counted string at
HERE . The string has a count of 1 and a single null for the text. There is such a word in the FIG Forth dictionary.
Code:
: X
BLK @
IF ?EXEC ENDIF
R> DROP ; IMMEDIATE
The name is not really
X , it is the null name and when found will force
INTERPRET to exit. This is how
INTERPRET 'knows' when to stop interpreting.
It seems like the key to all of this is the fig Forth text scanning primitive ENCLOSE:
Quote:
ENCLOSE ( addr1 c --- addr1 n1 n2 n3 )
The text scanning primitive used by WORD. From the text address addr1 and an ascii delimiting character c, is determined the byte offset to the first non-delimiter character n1, the offset to the first delimiter after the text n2, and the offset to the first character not included.
This procedure will not process past an ascii 'null', treating it as an unconditional delimiter.
Code:
Uniforth >>>
: WORD ( c -- ca ) \ parse counted string, located at ca
BLK @ IF BLK @ BLOCK ELSE TIB @ THEN
\ c addr0 \ the base address of the text source
>IN @ +
\ c addr1 \ This is the address start of the unparsed text
SWAP ENCLOSE
\ addr1 n1 n2 n3 \ unparsed text address & 3 offsets
HERE 2+ 22 BLANKS
\ addr1 n1 n2 n3 \ blank out HERE+2...HERE+23 ... evidently hex
>IN +!
\ addr1 n1 n2 \ update start of unparsed text
OVER - >R R@
\ addr1 n1 (n2-n1) R: (n2-n1)
HERE 2+ C!
\ addr1 n1 R: (n2-n1) \ count stored at HERE+2
+ HERE 3 + R>
\ (addr1+n1) (HERE+3) (n2-n1) \ set up copy
CMOVE
\ \ counted string at HERE+2
HERE 2+
\ HERE+2 \ return WORD counted string address
;
~~~~~~~~~~~~
Code:
fig-Forth >>>
: WORD ( c -- )
BLK @ IF BLK @ BLOCK ELSE TIB @ THEN IN @ +
\ c addr1 \
SWAP ENCLOSE
\ addr1 n1 n2 n3 \
HERE 34 BLANKS IN +!
\ addr1 n1 n2 \ same as Uniforth except word name is at HERE, not HERE+2
OVER - >R R
\ addr1 n1 (n2-1) | R: (n2-n1) \
HERE C!
\ addr1 n1 | R: (n2-n1) \ now the count is at HERE
+ HERE 1+ R>
\ (addr1+n1) (here+1) (n2-n1) \ set up for cmove
CMOVE
\ \
;
Note that UniForth likely has the link at the beginning of the dictionary entry rather than after the name, which is why the WORD buffer is at HERE+2 rather than at HERE, as with fig Forth.
If UniForth WORD does not process past the end of the current buffer, even if there is junk past the end of the current buffer left over from a longer previous line, then perhaps UniForth ENCLOSE is respecting TIB# for text in the TIB and the block length for a screen in a block buffer.
Perhaps the fig Forth ENCLOSE can hacked to have the same effect, acting "as if" there was a 0 at the address past the end of parse-able text. Otherwise, the start of the definition:
Code:
BLK @ IF BLK @ BLOCK ELSE TIB @ THEN IN @ +
... leaves you with an opening. A word "EOL? ( c ca -- c ca flag )" that tests for the address at ca, skipping any "c" delimiters, being at the end of the TIB or the end of the block buffer would allow:
Code:
...
BLK @ IF BLK @ BLOCK ELSE TIB @ THEN IN @ +
EOL? IF DROP DROP 1 HERE ! ELSE ...
and then a "THEN" right before the concluding ; in WORD.
I'd reckon EOL? should be implemented as a code word, to avoid bogging down the outer interpreter.