GARTHWILSON wrote:
I've had occasion to do BEGIN-WHILE-UNTIL-THEN a couple of times, but it seems like I solved it some other way. There's also the possibility of multiple WHILEs, although I've never written the innards for that.
Huh? I implemented conditional words and indefinite loops in my Forth-83 Forth in what I thought was the easiest way. Multiple
WHILE's are available without additional code.
I built these words around the mark and resolve words:
Code:
: >MARK ( -- ADR 1 )
HERE 0 , 1 ;
: <MARK ( -- ADR 2 )
?COMP
HERE 2 ;
: >RESOLVE ( ADR 1 -- )
?COMP
1 ?PAIRS HERE SWAP ! ;
: <RESOLVE ( ADR 2 -- )
2 ?PAIRS , ;
The compiler security is
not meant to force a certain way of using the
IF words or the
BEGIN words. It is just to make certain that a
>MARK is resolved by a
>RESOLVE and a
<MARK is resolved by a
<RESOLVE. Also to make sure the control flow words are only used while compiling.
Here are the
IF words:
Code:
: IF ( -- ADR CS )
COMPILE ?BRANCH
>MARK ; IMMEDIATE
: AHEAD ( -- ADR CS )
COMPILE BRANCH
>MARK ; IMMEDIATE
: THEN ( ADR CS -- )
>RESOLVE ; IMMEDIATE
: ELIF ( ADR1 CS -- ADR2 CS )
[COMPILE] IF 2SWAP
[COMPILE] THEN ; IMMEDIATE
: ELSE ( ADR1 CS -- ADR2 CS )
[COMPILE] AHEAD 2SWAP
[COMPILE] THEN ; IMMEDIATE
And here are the indefinite loop words:
Code:
: BEGIN ( -- ADR CS )
<MARK ; IMMEDIATE
: AGAIN ( ADR CS -- )
COMPILE BRANCH
<RESOLVE ; IMMEDIATE
: UNTIL ( ADR CS -- )
COMPILE ?BRANCH
<RESOLVE ; IMMEDIATE
: REPEAT ( ADR1 CS1 ADR2 CS2 -- )
[COMPILE] AGAIN
[COMPILE] THEN ; IMMEDIATE
: WHILE ( ADR1 CS1 -- ADR2 CS2 )
[COMPILE] IF 2SWAP ; IMMEDIATE
Notice that a
BEGIN-
WHILE-
REPEAT loop is no different from a
BEGIN-
WHILE-
AGAIN THEN loop.
A
BEGIN-
WHILE-
UNTIL-
THEN loop is straightforward:
Code:
: TEST
BEGIN
<do something that leaves a flag on stack>
WHILE
<do something else that leaves flag on stack>
UNTIL
<made it through loop>
THEN ;
Or even
Code:
: TEST
BEGIN
<do something that leaves a flag on stack>
WHILE
<do something else that leaves flag on stack>
UNTIL
<made it through loop>
ELSE
<left loop at while>
THEN ;
Here is an example of multiple
WHILE's. Just keep in mind that each
WHILE is paired with a matching
THEN and one of them is built into
REPEAT.
Code:
: WTEST
BEGIN
NOOP TRUE
WHILE
NOOP TRUE
WHILE
NOOP TRUE
WHILE
NOOP
REPEAT
CR
THEN
CR
THEN
CR ;
It doesn't do anything useful, but
SEE shows what got compiled and where each
WHILE (
?BRANCH ) branched.
Code:
SEE WTEST
WTEST
5A84 NOOP
5A86 TRUE
5A88 ?BRANCH 5AA6
5A8C NOOP
5A8E TRUE
5A90 ?BRANCH 5AA4
5A94 NOOP
5A96 TRUE
5A98 ?BRANCH 5AA2
5A9C NOOP
5A9E BRANCH 5A84
5AA2 CR
5AA4 CR
5AA6 CR
5AA8 EXIT
OK
Hopefully, someone will find this useful.
Cheers,
Jim