\ coroutines
\ Do a coroutine call. To be explained later.
\ In ciforth this is in the kernel.
: CO R> R> SWAP >R >R ;
\ Allocate AMOUNT locals on the return stack, to be accessed
\ by $# words.
: LOCALS
R> SWAP \ Move return stack top to stack
RSP@ SWAP CELLS OVER SWAP - RSP! >R \ Allocate X cells
>R \ Move back
CO \ Execute caller
R> RSP! \ Restore stack pointer
;
\ Compile the address of local variable 3.
: $3 3 2 + CELLS POSTPONE LITERAL POSTPONE RSP@ POSTPONE + ;
IMMEDIATE
\ local variables by $0 .. $9
\ This is a denotation equivalent to the above definition.
: $ 0. (WORD) >NUMBER 2DROP DROP 2 +
POSTPONE LITERAL
POSTPONE CELLS POSTPONE RSP@ POSTPONE + ; IMMEDIATE
LATEST >FFA 8 TOGGLE
\ Test code
: V+ 4 LOCALS ( a b c d -- a+c b+d )
$3 ! $2 ! $1 ! $0 !
$0 @ $2 @ + $1 @ $3 @ +
;
." EXPECT : 202 101 :" 100 200 1 2 V+ . . CR
: TOKYO
." HERE TOKYO OVER" CR CO
." WHAT GIVES? OVER" CR CO
." YES, MORE? OVER" CR CO
." OVER AND OUT" CR
;
: AMSTERDAM
TOKYO
." HERE ASTERDAM OVER" CR CO
." HAS IT ARRIVED OVER" CR CO
." NO. OVER AND OUT" CR
;
." EXPECT SENSIBLE CONVERSATION:" CR AMSTERDAM
EXIT
: AMSTERDAM | : TOKYO
TOKYO | ." HERE TOKYO OVER" CR CO
." HERE ASTERDAM OVER" CR CO | ." WHAT GIVES? OVER" CR CO
." HAS IT ARRIVED? OVER" CR CO | ." YES, MORE? OVER" CR CO
." NO. OVER AND OUT" CR | ." OVER AND OUT" CR
; | ;
Using CO for iteration.
With the iterator FOR-WORDS the xt on the stack is executed once for
each word in the wid that is on the stack :
CRACK WORDS
: WORDS
C/L OUT ! 'ID. CURRENT @ FOR-WORDS
;
The implementation of FOR-WORDS is rather ugly:
CRACK FOR-WORDS
: FOR-WORDS
SWAP >R >R ( keep xt runner on the return stack)
BEGIN
R> R@
OVER >LFA @ >R ( Prepare next runner)
EXECUTE
R@ 0= UNTIL ( Next runner is zero)
RDROP RDROP (Clean return stack)
;
With coroutines this all becomes
\ Break off my co-routine.
'RDROP ALIAS CO-EXIT
: FOR-WORDS BEGIN DUP WHILE DUP CO >LFA @ REPEAT CO-EXIT ;
: WORDS' C/L OUT ! CURRENT @ FOR-WORDS BEGIN ID. CO AGAIN ;
This however leaves a zero on the stack of the end of the link chain.
What if you don't want to drop that zero in FOR-WORDS ?
(Doing so introduces a kind of stack imbalance. If we force FOR-WORDS
out of business by a CO-EXIT in WORDS' , FOR-WORDS leaves a word
on the stack compared to the regular exit.)
Once more coroutines come to the rescue.
: AFTER-DROP CO DROP ;
And we get.
: WORDS' C/L OUT ! CURRENT @ AFTER-DROP FOR-WORDS BEGIN ID. CO AGAIN ;
The good thing here is that we are no longer restricted to a single
word at the position of ID.
Further ideas:
Look up the STRING in wordlist WID. Leave STRING and DEA.
The dea may be a ``NULL''.
: (FIND) FOR-WORDS BEGIN MATCH 0= WHILE CO AGAIN CO-EXIT ;
Match now only have to take care of comparing the STRING with the
name of the dictionary entry, not with any bookkeeping.
This does away with a MATCH word that zero's out the third item
on the return stack and remembers a result in a global variable (!).