Fort: portable indefinite loop with multiple exit points

I need to implement an endless loop with multiple exit points. Unfortunately, the most obvious solution - REPEAT - UNTIL with several WHILEs, doesn’t work in either Gforth or swapforth (of course, the loop in the example below can be implemented with DO-LOOP. However, this code is just a demonstration. The problem is with hardware control in embedded system, so the loop should really be undefined):

: test1 ( step -- step count )
    0
    begin
      over +
      dup .
      dup 20 < while
      dup 13 = while
    repeat
;

3 test1 

In "Thinking Forth," Moore's expression is given:

Many times conditional expressions are used to exit loops. This can be avoided by using loops with multiple exit points. This is a lively theme due to the multiple WHILE construct, which is in poly-Forth but does not leak to Forth 83. Its an easy way to define multiple WHILEs in the same REPEAT. Also, Dean Sanderson [of Forth, Inc.] invented a new design that introduces two outputs indicating DO LOOP. Given that you will have fewer tests.

Unfortunately, I could not find Dean's solution. Is there any portable way to implement multiple exit points in an indefinite loop in Forth?

+4
source share
3 answers

DO + LOOP. , , .

Gforth swapforth. , . : 0 1 DO 0 + LOOP. LEAVE, IF THEN.

:

: test1 ( start step -- count step )
    swap
    1 0 do
      over +
      dup .
      dup 20 > if 
        ." >20 "
        leave
      then
      dup 13 = if
        ." =13 "
        leave
      then
      dup 17 = if
        ." =17 "
        leave
      then
    0 +loop
;

:

> 1 3 test1
 4 7 10 13 =13  ok
> 2 3 test1
 5 8 11 14 17 =17  ok
> 0 3 test1
 3 6 9 12 15 18 21 >20  ok
+2

EXIT, , . , , :

: test ( start step -- count step )
  swap [: begin
    over + dup .
    dup 20 > if ." >20" exit then
    dup 13 = if ." =13" exit then
    dup 17 = if ." =17" exit then
  again ;] execute
  ( EXITs from loop continue here ) ;
+2

, ruvim, , WHILE, THEN:

: test1 ( step start -- step count )
    cr
    begin
      over +
      dup . cr
      dup 30 < while
      dup 13 <> while
      dup 17 <> while
    repeat
        ." before 1st else" cr
    else
        ." after 1st else" cr
    then
        ." before 2nd else" cr
    else 
        ." after 2nd else" cr
    then
;

, . , , .

:

5 1 test1 
6 
11 
16 
21 
26 
31 
after 2nd else
 ok

, :

5 3 test1 
8 
13 
after 1st else
before 2nd else
 ok

, :

5 2 test1 
7 
12 
17 
before 1st else
before 2nd else
 ok

So, if someone wants to assign an action to each WHILE, this should be done as follows:

: test1 ( step start -- step count )
    cr
    begin
      over +
      dup . cr
      dup 30 < while
      dup 13 <> while
      dup 17 <> while
    repeat
    ." exited after the 3rd while" cr
    else
    ." exited after the 2nd while" cr
    then
    else
    ." exited after the 1st while" cr
    then
;

It would be interesting how higher the scales for even more WHILE. Following is the syntax that works for 4 WHILEs:

: test1 ( step start -- step count )
    cr
    begin
      over +
      dup . cr
      dup 30 < while
      dup 13 <> while
      dup 17 <> while
      dup 19 <> while
    repeat
    ." exited after the 4th while" cr
    else
    ." exited after the 3nd while" cr
    then
    else
    ." exited after the 2nd while" cr
    then
    else
    ." exited after the 1st while" cr
    then
;

The above code has been tested in both Gforth and swapforth. An interesting question is filling out the downloadable package in various possible solutions. (For example, in CPU J1B, the depth of the returned stack is only 32 levels).

+1
source

Source: https://habr.com/ru/post/1649695/


All Articles