6.1.0140+LOOPplus-loopCORE

Interpretation:

Interpretation semantics for this word are undefined.

Compilation:

( C: do-sys -- )

Append the run-time semantics given below to the current definition. Resolve the destination of all unresolved occurrences of LEAVE between the location given by do-sys and the next location for a transfer of control, to execute the words following +LOOP.

Run-time:

( n -- ) ( R: loop-sys1 -- | loop-sys2 )

An ambiguous condition exists if the loop control parameters are unavailable. Add n to the loop index. If the loop index did not cross the boundary between the loop limit minus one and the loop limit, continue execution at the beginning of the loop. Otherwise, discard the current loop control parameters and continue execution immediately following the loop.

Rationale:

Typical use: : `X` ... limit first DO ... step +LOOP ;

Testing:

T{ : GD2 DO I -1 +LOOP ; -> }T
T{        1          4 GD2 -> 4 3 2  1 }T
T{       -1          2 GD2 -> 2 1 0 -1 }T
T{ MID-UINT MID-UINT+1 GD2 -> MID-UINT+1 MID-UINT }T

VARIABLE gditerations
VARIABLE gdincrement

: gd7 ( limit start increment -- )
gdincrement !
0 gditerations !
DO
1 gditerations +!
I
gditerations @ 6 = IF LEAVE THEN
gdincrement @
+LOOP gditerations @
;

T{    4  4  -1 gd7 ->  4                  1  }T
T{    1  4  -1 gd7 ->  4  3  2  1         4  }T
T{    4  1  -1 gd7 ->  1  0 -1 -2  -3  -4 6  }T
T{    4  1   0 gd7 ->  1  1  1  1   1   1 6  }T
T{    0  0   0 gd7 ->  0  0  0  0   0   0 6  }T
T{    1  4   0 gd7 ->  4  4  4  4   4   4 6  }T
T{    1  4   1 gd7 ->  4  5  6  7   8   9 6  }T
T{    4  1   1 gd7 ->  1  2  3            3  }T
T{    4  4   1 gd7 ->  4  5  6  7   8   9 6  }T
T{    2 -1  -1 gd7 -> -1 -2 -3 -4  -5  -6 6  }T
T{   -1  2  -1 gd7 ->  2  1  0 -1         4  }T
T{    2 -1   0 gd7 -> -1 -1 -1 -1  -1  -1 6  }T
T{   -1  2   0 gd7 ->  2  2  2  2   2   2 6  }T
T{   -1  2   1 gd7 ->  2  3  4  5   6   7 6  }T
T{    2 -1   1 gd7 -> -1 0 1              3  }T
T{  -20 30 -10 gd7 -> 30 20 10  0 -10 -20 6  }T
T{  -20 31 -10 gd7 -> 31 21 11  1  -9 -19 6  }T
T{  -20 29 -10 gd7 -> 29 19  9 -1 -11     5  }T

\ With large and small increments

MAX-UINT 8 RSHIFT 1+ CONSTANT ustep
ustep NEGATE CONSTANT -ustep
MAX-INT 7 RSHIFT 1+ CONSTANT step
step NEGATE CONSTANT -step

VARIABLE bump

T{  : gd8 bump ! DO 1+ bump @ +LOOP ; -> }T

T{  0 MAX-UINT 0 ustep gd8 -> 256 }T
T{  0 0 MAX-UINT -ustep gd8 -> 256 }T
T{  0 MAX-INT MIN-INT step gd8 -> 256 }T
T{  0 MIN-INT MAX-INT -step gd8 -> 256 }T

mcondron[80] Numeric overflow/underflowRequest for clarification2019-05-21 03:17:42

What is supposed to happen if the index overflows the upper value of an int -- or the lower bound of negative int? I.E. for a 16-bit system, when the index + increment goes over 32767 but never equals 32767, like counting 10 +LOOP and the index is 32765? There are obviously ways to test for this, but is that expected, or is this one of those "don't do that" situations? Strictly speaking, the standard does say the loop terminates when the index crosses the boundary between limit and limit-1, which is pretty easy to define for all positive limits, but not so for a negative limit of -32768. I'm inclined to go for the "don't do that" option, but maybe that's just laziness. Testing for this involves either extension to double-width values within the runtime code for +LOOP, or some minor headache code to avoid the over/underflow by testing if the difference between index and the MAX/MIN int is less than the increment. I guess it could be specified as implementation-dependent. But it seems the behavior in this condition should at least be mentioned.

AntonErtl[r214] 2019-05-21 05:54:21

I'll assume that you use 2s-complement representation for negative numbers here (which will be required in the next standard after Forth-2012); the answer is more complex for other integer representations.

Note that the loop control parameters can be either signed or unsigned, and +LOOP has to work for both. For systems with 2s-complement representation for signed numbers, the way to go is to use circular arithmetic: compute x=(index-limit)+minint, and observe if the addition x+n crosses the boundary between minint and maxint. Many architectures report this through the overflow flag. If you don't have or cannot use the overflow flag, look at the source code of (+LOOP) in Gforth for another way to implement +LOOP with circular arithmetic.

mcondron[r216] 2019-05-21 23:27:07

OK...this is just two's-complement overflow, it seems. That's pretty straightforward. I am using 2C arithmetic, but my CPU doesn't have an overflow flag (I'm working with a homebrew 8085 system). It's pretty easy to detect this just by looking at the signs of the index and increment and the sign of the sum. Thanks! It does seem like the overflow condition should be explicitly mentioned in the description of this word, even though it is implied by the wording. Better to bring this issue up right where everyone can see it clearly.

PeterKnaggs[r218] 2019-05-22 18:30:57

No, but it does have a carry flag.

rrt[r372] 2020-06-08 09:41:43

For reference, the gforth source code that Anton refers to is the word `(+loop)`, which you can find by searching for `condbranch((+loop),` at http://git.savannah.gnu.org/cgit/gforth.git/tree/prim

rrt[r373] 2020-06-08 09:49:29

A more helpful link direct to gforth's source for `(+loop)`: http://git.savannah.gnu.org/cgit/gforth.git/tree/prim#n373