6.1.2380 UNLOOP CORE

Interpretation:

Interpretation semantics for this word are undefined.

Execution:

( -- ) ( R: loop-sys -- )

Discard the loop-control parameters for the current nesting level. An UNLOOP is required for each nesting level before the definition may be EXITed. An ambiguous condition exists if the loop-control parameters are unavailable.

See:

Rationale:

Typical use:
: X ...
   limit first DO
   ... test IF ... UNLOOP EXIT THEN ...
   LOOP ...
;

UNLOOP allows the use of EXIT within the context of DO ... LOOP and related do-loop constructs. UNLOOP as a function has been called UNDO. UNLOOP is more indicative of the action: nothing gets undone — we simply stop doing it.

Testing:

T{ : GD6 ( PAT: {0 0},{0 0}{1 0}{1 1},{0 0}{1 0}{1 1}{2 0}{2 1}{2 2} ) 
      0 SWAP 0 DO 
         I 1+ 0 DO 
           I J + 3 = IF I UNLOOP I UNLOOP EXIT THEN 1+ 
         LOOP 
      LOOP ; -> }T

T{ 1 GD6 -> 1 }T
T{ 2 GD6 -> 3 }T
T{ 3 GD6 -> 4 1 2 }T

ContributeContributions

AtHavatar of AtH [18] Another use of UNLOOPSuggested Testcase2016-05-16 21:55:15

Old standard concentrates on UNLOOP EXIT

I suggest to legalize in the new standard UNLOOP LEAVE for breaking the outer loop.

AntonErtlavatar of AntonErtl

A common implementation of UNLOOP is as just a run-time word, while a common implementation of LEAVE is a compile word that generates a branch to the end of the loop. Your suggestion would cause quite a bit of additional implementation complexity with such a LEAVE. If we need to leave two DO LOOPs, a word LEAVE2 would be simpler to implement (although word counters won't like it). Or, with the current standard, put the nested loop in an extra colon definition, and leave it with UNLOOP UNLOOP EXIT.

AtHavatar of AtH

There are two ways to implement LEAVE

  1. As you said, compile UNLOOP with direct BRANCH to the first word after first LOOP

  2. When end of loop address is part of discarded loop-control parameters, fetch this exit point and indirect branch to it.

First implementation is slightly faster, the second allows to use UNLOOPs for leaving any number of nested loops. I use the second way, LEAVE is just a regular primitive without IMMEDIATE and DO always knows, where it's LOOP

UNLOOP could be more powerful, without extra words in the standard like LEAVE2 LEAVE3 etc.

AntonErtlavatar of AntonErtl

Do we want to limit the Forth implementations to those that are implemented in the way you describe? I don't.

Anyway, don't let my objections stop you. If you think it is worth it, make a proposal.

Reply New Version

ruvavatar of ruv [339] Is it possible to eliminate the need for `UNLOOP`?Request for clarification2024-05-13 08:33:18

The need for the UNLOOP word can be eliminated in two different ways:

  1. In compilation time. When the compilation semantics for EXIT are performed, the number of containing DO ... LOOP structures is known, so the corresponding number of an internal word (UNLOOP) can be compiled automatically before EXIT.

  2. In run-time. When the DO run-time semantics are performed, an internal word (UNLOOP-EXIT) entry point can be placed on the return stack as a part of loop-sys; then, if EXIT run-time semantics are performed inside the loop, (UNLOOP-EXIT) takes control, removes other loop-sys params and performs the run-time semantics of EXIT; if EIXT run-time are not performed inside the loop, (UNLOOP-EXIT) is removed by LOOP run-time semantics as a part of loop-sys.

In any case, these approaches should be used by Forth systems to remove the local variables frame before exiting.

If the UNLOOP word is not needed, the stack diagram for the EXIT run-time semantics would be:
Run-time EXIT: ( R: i*loop-sys nest-sys -- )

Do you think it is theoretically possible in the future? For backward compatibility, UNLOOP can be implemented as a synonym of NOP.

Rationale

  • slightly simpler and less error-prone code (you cannot miss UNLOOP if you don't need it at all);
  • more consistent language (why we don't need an analog of UNLOOP to manually remove a local variables frame?);
  • don't do manually what the system can do automatically.

ruvavatar of ruv

Correction:

If the UNLOOP word is not needed, the stack diagram for the EXIT run-time semantics would be:
Run-time EXIT: ( R: nest-sys i*loop-sys -- )

AntonErtlavatar of AntonErtl

How would your automatic approach correctly implement stuff like:

: foo
  >r
  ... ?do
    >r ?do
      ... if
        unloop r> unloop r> exit then
      ...
    loop
    ... r> ...
  loop
  ... r> ... ;

if unloop is a noop.

Concerning locals: The standard puts a lot of restrictions on locals usage in order to, (among other things) eliminate the need for something like unlocals, e.g., a standard program must not use multiple locals definitions nor define locals inside a control structure. Gforth does not restrict its programmers that much, but pays for it by having to maintain a separate locals stack.

ruvavatar of ruv

Anton, thank you for your example. You are right, in this standard-compliant case unloop cannot be eliminated, without additional restrictions on the do-loop implementation (to not use r-stack for loop-sys).

Closed
Reply New Version