Forth DISCUSSION

Forth return stack: why does my word crash or misread data when I park a value before a DO loop?

Started by plcprogramming Forth return stackDO LOOP indexUNLOOP?DOstack balance
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

Forth return stack: why does my word crash or misread data when I park a value before a DO loop?

plcprogramming Forth Forum
#1

To keep the data stack tidy I move a scale factor to the return stack before a loop: : SCALE-ALL ( addr n k -- ) >R 0 DO DUP I CELLS + DUP @ R@ * SWAP ! LOOP DROP R> DROP ;. Instead of multiplying every cell by k, the array fills with strange numbers. A second word, where I forgot the final R>, crashes the system as soon as it returns, and calling the word with a count of 0 seems to hang.

What are the rules for using the return stack, and how should this word be written?

Community replies 5

Re: Forth return stack: why does my word crash or misread data when I park a value before a DO loop?

#2

The return stack is not a spare data stack; the system uses it too. It holds the return address of every word in progress, and on most systems DO places the loop limit and index there as well. Inside your loop, R@ therefore fetches a loop parameter, not the k you pushed before DO; your value sits underneath and is out of reach until LOOP has finished.

The standard says exactly this: values placed on the return stack before a DO are not accessible inside the loop.

Re: Forth return stack: why does my word crash or misread data when I park a value before a DO loop?

#3

The rules that follow from that are short:

  • Every >R must be matched by an R> (or R> DROP) in the same definition, on every path, before the word ends or executes EXIT.
  • Inside a loop, anything pushed must be popped again within the same iteration, and I cannot be used between the >R and its R>.
  • To leave a word from inside a DO loop, call UNLOOP before EXIT to discard the loop parameters.

Your second word crashed because at ; the system took the forgotten value as its return address and jumped to it.

Re: Forth return stack: why does my word crash or misread data when I park a value before a DO loop?

#4

With locals the word needs no return-stack tricks at all: : SCALE-ALL {: addr n k -- :} n 0 ?DO addr I CELLS + DUP @ k * SWAP ! LOOP ;. For each index it computes the cell address, duplicates it, fetches the value, multiplies by k and stores the product back. Scaling the cells 1, 2 and 3 by 10 leaves 10, 20 and 30.

Without locals, keep k on the data stack and loop directly over addresses: : SCALE-ALL ( addr n k -- ) ROT ROT CELLS OVER + SWAP ?DO I @ OVER * I ! 1 CELLS +LOOP DROP ;. Here I is the address of the current cell and k stays on top of the stack throughout.

Re: Forth return stack: why does my word crash or misread data when I park a value before a DO loop?

#5

The hang with a count of 0 is a separate trap. DO always executes its body at least once and only stops when the index crosses the boundary between limit-1 and limit. 0 0 DO starts with the index already at the limit, so it runs until the index has wrapped through the whole number range: 65,536 iterations on a 16-bit system and about 4.3 billion on a 32-bit one, writing over memory all the way.

?DO skips the loop entirely when limit and index are equal. Use ?DO whenever the count comes from data rather than from a constant you wrote yourself.

Re: Forth return stack: why does my word crash or misread data when I park a value before a DO loop?

#6

For debugging this kind of fault, test each word from the prompt with a known stack and look at the result with .S, which prints the data stack without changing it. A word that should consume three items and leave none must show the same depth before and after. Imbalance on the data stack is visible immediately; imbalance on the return stack is not, which is why those bugs appear as crashes instead.

Also do not experiment with >R and R> directly at the prompt. They are meant for use inside definitions, and on many systems the interpreter itself has items on the return stack that you would disturb.

TEP COMMUNITY