Proposal: CS-DROP (revised 2019-08-22)


This proposal has been moved into this section. Its former address was: /standard/tools/CS-PICK

This page is dedicated to discussing this specific proposal


UlrichHoffmannavatar of UlrichHoffmann CS-DROP (revised 2019-08-22)Proposal2019-09-06 08:24:28

CS-DROP "Request for Discussion"

Change History

2019-08-22 CS-DROP again should drop both, control-flow dest and orig item. Propsal extended to included CS-PICK modification
2018-08-20 CS-DROP now operates only on control-flow dest items, typical use example has simpler control-flow structure
2017-07-27 First version


Forth-94 and Forth-2012 provide explicit access to the control-flow stack by means of the words CS-PICK and CS-ROLL in the Programming-Tools extension wordset (TOOLS EXT). These words allow to copy and rearrange control flow (orig and dest) items.

Control structures (BEGIN IF AHEAD WHILE ...) put control-flow dest resp. orig items onto the control-flow stack. orig items always go along with a yet unresolved forward branch. dest items mark backward branch targets.

There is however no way to remove an item from the control-flow stack without actually resolving it. This limits the abilty to define more complex control structures within the standard's scope.

In its Forth-94 and Forth-2012 version CS-PICK has only defined behaviour when copying dest items to the top of the control flow stack: CS-PICK “c-s-pick” TOOLS EXT
Interpretation: Interpretation semantics for this word are undefined.
Execution: ( C: dest_u ... orig_0|dest_0 –– dest_u ... orig_0|dest_0 dest_u) ( S: u – – )

Remove u. Copy dest_u to the top of the control-flow stack. An ambiguous condition exists if there are less than u+1 items, each of which shall be an orig or dest, on the control-flow stack before CS-PICK is executed.

If the control-flow stack is implemented using the data stack, u shall be the topmost item on the data stack.

See: A. CS-PICK.

u has to index a dest item (dest_u in the above standard text). Trying to copying an orig item with CS-PICK results in an ambigous condition as this would violate the type compatibility with the dest_u input parameter:

4.1.2 Ambiguous conditions

A system shall document the system action taken upon each of the general or specific ambiguous conditions identified in this standard. See 3.4.4 Possible actions on an ambiguous condition.

The following general ambiguous conditions could occur because of a combination of factors:


argument type incompatible with specified input parameter, e.g., passing a flag to a word expecting an n (3.1 Data types);

CS-DROPping orig items

So, with this Forth-94 and Forth-2012 behaviour of CS-PICK (trying to copy an orig item is an ambigous condition) it seems to be reasonable to deal with orig items only by resolving them e.g. by THEN or ELSE. Simply dropping an orig item leaves an unresolved forward branch which actually is malformed code and eventually will crash when executed.

If however CS-PICK could also copy orig items in a defined way, multiple identical orig items could exist in the control flow stack and dropping them later would be perfectly reasonable. The programmer would take care that exactly one of these orig items will be resolved and all other items dropped at the best convenience of her program.

CS-DROPping dest items

An addition, there are situations where control-flow dest items have been generated or duplicated by CS-PICK and then need no further resolution and thus should be simply removed. As dest items designate branch targets, dropping them when not needed is of no further significance.


A control-flow stack operator - CS-DROP - to discard the top most control flow item can be defined to supply the missing functionality.

Combined with the duplication capability of CS-PICK and the re-arrangement capability of CS-ROLL this would allow to do arbitrary control flow stack changes of its top items (down to the first colon-sys, do-sys, case-sys, or of-sys).

Being able to CS-DROP both orig and dest items from the control flow stack calls for tightening the definition of CS-PICK to allow copying dest and also orig items. This would eliminate the ambigous condition of CS-PICK operating on orig items.


Revise the word CS-PICK in the Tools Extension wordset (TOOLS EXT) so that it can copy both orig and dest items (replace with the following paragraph): CS-PICK “c-s-pick” TOOLS EXT  

Interpretation: Interpretation semantics for this word are undefined.  

      ( C: orig_u|dest_u ... orig_0|dest_0 –– orig_u|dest_u ... orig_0|dest_0 orig_u|dest_u) ( S: u –– )  

Remove u. Copy orig_u|dest_u to the top of the control-flow stack. An ambiguous condition
exists if there are less than u+1 items, each of which shall be an orig or dest, on the
control-flow stack before CS-PICK is executed.

If the control-flow stack is implemented using the data stack, u shall be the topmost item
on the data stack.  

See: A. CS-PICK.

Add the word CS-DROP to the Tools Extension wordset (TOOLS EXT).

CS-DROP "c-s-drop" TOOLS EXT  

Interpretation: Interpretation semantics for this word are undefined.  

Execution: ( C: orig|dest -- )  

Remove the top item dest from the control-flow stack. 
An ambiguous condition exists if the top control-flow stack item
is not a dest, an orig, or if the control-flow stack is empty.

Typical Use

Typical use of CS-DROP would be in defining elaborated control structures.

As an example for the use of CS-DROP we create a simple control structure that allows to branch multiple times to an enclosing BEGIN. A corresponding END drops the BEGIN-generated control-flow dest item:

: END ( C: dest -- ) \ Compilation
      ( -- )          \ Run-time

: ?{ ( C: dest –– dest orig dest) \ Compilation
     ( f -- )                     \ Run-time

: }* ( C: orig dest -- )

This can for example be used to define the Collatz function:

: even? ( u -- f )  1 AND 0= ;

: collatz ( u -- )
       DUP .
       DUP even? ?{ 2 / }*
       DUP 1 <>  ?{ 3 * 1+ }*
    DROP ;

19 collatz ( 19 58 29 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1  ok )


Several Forth-94 and Forth-2012 systems already define CS-DROP or the same functionality under a different name. It is already common practice so it is only consequent to standardize its use.

Neither Forth-94 nor Forth-2012 specify the size of orig or dest items. They are even not required to have identical sizes. Different sizes would complicate the implementation of CS-ROLL (and the proposed revised CS-PICK). Most systems therefore implement orig and dest items the same size. The implementation of the proposed revised CS-PICK should thus be straight forward in most systems (and in no case more complicated than CS-ROLL).

Reference implementation

As standard systems are

  • free to choose an appropriate representation for control-flow dest and orig stack items and also

  • free to choose the data stack as control-flow stack or a separate stack for this purpose

a standard definition for CS-DROP cannot be provided.

An estimation for dest items only would be the following definitions that however compile code in the dictionary.



CS-DROP can easily implemented in a system specific way if system knowledge about the control-flow stack implementation is available.

As an example SwiftForth uses a single cell on the data stack as control-flow items. A SwiftForth definition for CS-DROP, which also takes compiler security into account would be:

: CS-DROP ( C: orig|dest -- )  DROP -BAL ;

Win32Forth uses two cells on the data stack as control-flow items including one cell for compiler security, so a defintion for CS-DROP in Win32Forth would be:

: CS-DROP ( C: orig|dest -- )  1 ?PAIRS DROP ;


The following test assures that CS-DROP actually removes the top most dest item from the control-flow stack:

t{ 99 :NONAME BEGIN [ CS-DROP ]                 ; DROP -> 99 }t

The following test assures that CS-PICK can copy orig items and CS-DROP can discard them:

t{ 99 :NONAME IF    [ 1 CS-PICK  CS-DROP ] THEN ; DROP -> 99 }t  


CS-DROP is already available in the following systems:

  • gForth version 0.7.9 (not in 0.7.3)
  • VFX version 4.7.2
  • PFE version 0.33.71
  • DXForth version 4.30

Similar functionality with a different name is supported by:

  • FLT version 1.3.2 as (delete-cs-item)

CS-DROP is not (yet) supported in:

  • SwiftForth version 3.6.3, sample definition given above
  • Win32Forth version 6.15.04, sample definition given above

The Gforth 0.7.9 implementation of CS-PICK includes a check that actually only dest items are copied (by means of the check ?NON-ORIG). Its CS-DROP implementation does not check for dest items.

There are numerous discussions on comp.lang.forth (e.g. [3][4]) about control structure implementation using control-flow stack manipulations. Among the non standard system specific words mentioned in this context CS-DROP is widely accepted.

There seems to be a prior similar proposal probably by Guido U. Draheim as the PFE Forth documentation [2] suggests.


Fall 2018

In its 2018 (12–14 September) meeting in Edinburgh the Forth standards committee discussed the (2018-08-20 revised) CS-DROP proposal with the following outcome:

Allowing CS-DROP to drop an orig was discussed, this would require allowing CS-PICK to pick an orig. Referred to author for further consideration.

Fall 2017

The initial version of the proposal was presented at the fall 2017 standards meeting. It proposed CS-DROP to drop both dest and orig items. Concerns were raised that using CS-DROP with control-flow orig items would lead to unresolved branch origins that eventually will result in run time errors when executed. Every orig created (e.g. by IF AHEAD ELSE WHILE) should be resolved exactly once (e.g. by THEN ELSE REPEAT).

The standardized behaviour of CS-PICK ( in both Forth-92 and Forth-2012 does not allow to copy control-flow orig stack items but requires a control-flow destination item dest-u to be copied. Although not explicitly stated we assume that copying orig items is an ambigous condition. Thus control-flow orig items cannot be copied within the Forth94 and Forth2012 standard scope, only control-flow dest items can. For this it is reasonable to restrict the to be standardized CS-DROP to also only drop control-flow dest items.




Ulrich Hoffmann

AntonErtlavatar of AntonErtl

If you allow CS-PICK and CS-DROP to deal with origs, you have to cover the case where the same orig is not resolved at all, or resolved more than once. Either make it explicitly ambiguous, or define what happens.

I have not yet thought through (Automatic scoping of locals)[] in the presence of these enhanced CS-PICK and new CS-DROP capabilities.

Current Gforth also tests for ?NON-ORIG in CS-DROP, but that can be changed.

Reply New Version