Search code examples
loopsforth

Forth: Portable indefinite loop with multiple exit points


I need to implement an idefinite loop with multiple exit points. Unfortunately the most obvious solution - REPEAT - UNTIL with multiple WHILE doesn't work neither in Gforth nor in swapforth (Of course the loop in the example below may be implemented with DO - LOOP. However, that code is just a demonstration. The real problem is related to hardware control in an embedded system, so the loop indeed must be indefinite):

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

3 test1 

In "Thinking Forth" there is Moore's statement quoted:

Many times conditionals are used to get out of loops. That particular use can be avoided by having loops with multiple exit points. This is a live topic, because of the multiple WHILE construct which is in poly- Forth but hasn’t percolated up to Forth ’83. It’s a simple way of defining multiple WHILEs in the same REPEAT. Also Dean Sanderson [of Forth, Inc.] has invented a new construct that introduces two exit points to a DO LOOP. Given that construction you’ll have fewer tests.

Unfortunately I failed to find the Dean's solution. Is there any portable way to implement multiple exit points in the indefinite loop in Forth?


Solution

  • After some experiments, I have created a solution based on a DO +LOOP. I don't know if it is the same as the one proposed by Dean Sanderson.

    I have successfully tested it in Gforth and in swapforth. It seems that it is possible to create the arbitrary number of exit points. The indefinite loop is created via: 0 1 DO loop content here 0 +LOOP. The exit points are created by LEAVE placed in IF THEN.

    Example code:

    : 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
    ;
    

    Test results:

    > 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