One stack becomes many
In the original Befunge there is a single stack. Every routine shares it, so a careless routine that leaves an extra value behind or removes one it should not can upset everything that runs afterwards. Funge-98 keeps the same stack idea but arranges stacks into a stack of its own. The stack at the top is the one all ordinary instructions use, and it is called the top stack. The one directly beneath it is the second stack.
Two instructions create and remove stacks. Block begin is {. Block end is }. A third, stack under stack, written u, moves values between the top stack and the one below it. Together they give a program a way to isolate a piece of work.
What block begin does
When the pointer executes {, it pops a count from the current stack. Then it:
- Creates a new, empty stack on top of the pile.
- Moves that many values from the old stack to the new one, keeping their order, so the value that was nearest the top is still nearest the top.
- Saves the current storage offset as a vector on the old stack.
- Sets a new storage offset, pointing at the cell after the brace.
If the count is zero, nothing is transferred and the new stack starts empty. If the count is negative, the old stack receives that many zeros instead. The exact behavior with edge cases is in the specification, and it is worth confirming against your interpreter.
The idea is simple: pass the arguments in, then work in a clean space. Inside the block, the code sees only its arguments. Anything beneath, belonging to the caller, is out of reach unless you reach for it deliberately.
What block end does
The instruction } reverses the process. It pops a count, then:
- Moves that many values from the top stack to the stack beneath it, again keeping their order.
- Discards the top stack, including anything left in it.
- Restores the saved storage offset from the stack beneath.
So the block can return a chosen number of results to the caller, and everything else it left behind vanishes. Cleaning up is automatic, which is a large part of the appeal.
If there is only one stack, block end has nothing to return to and acts as an unsupported instruction, which means the pointer reflects. The same applies to the stack-under-stack instruction. Mismatched braces are therefore a classic cause of programs that bounce backwards unexpectedly.
Moving values with stack under stack
The u instruction pops a count and then moves that many values between the stack below and the top stack, one at a time. If the count is positive, values come up from the stack beneath; if negative, values go down to it. Because the values move one by one, they arrive in reversed order, unlike the block instructions, which keep order. Programs that need to reach into the caller’s data without closing the block use this instruction.
A useful pattern is to open a block with no arguments, do some work with an empty stack, and use u to pull in one or two values from the caller exactly when needed. It is slightly slower to write, but it makes dependencies visible.
Why programs use separate stacks
Protection. A routine that opens a block cannot pop below its own values. In a shared stack, a routine that pops one too many consumes something belonging to its caller. With a separate stack, popping an empty stack yields zeros, a problem that is easier to notice than corrupted outer data. The pitfalls of that behavior are discussed under stack underflow.
Clear contracts. A routine can be described as “takes three values, returns one.” The counts given to begin and end spell out that contract in the code.
Local scratch space. Intermediate results live and die with the block. No cleanup code is needed, and no leftover values accumulate during a long run.
Easier reuse. Combined with the storage offset, a block becomes a self-contained unit with its own stack and its own variable area. This is a strong foundation for grid subroutines that can be pasted into any program.
Concurrency. When a pointer splits, each pointer gets its own copy of the stack of stacks. Using blocks to keep working values private fits well with that design.
An example in words
Imagine a routine that adds two numbers and multiplies by a third. The caller puts three numbers on the stack and sends the pointer into the routine. The routine begins with a count of three and {. Now the three numbers sit on a fresh stack. It does its arithmetic. At the end, the stack holds one result. The routine pushes a one and executes }, which moves that single result back to the caller’s stack and throws away everything else. The caller sees the three inputs replaced by one output, with nothing left over.
Compare that with a shared stack, where any mistake in counting leaves the caller’s stack with a different number of entries from what it expected, usually without any sign of what went wrong until much later.
Common mistakes
- Wrong count on begin or end. If you pass three arguments but say two, one value stays behind in the caller’s stack. If you return more than exist, zeros fill the gap.
- Unbalanced braces. Each begin needs an end on every path the pointer can take. A branch that skips the end leaves an extra stack and a shifted offset.
- Forgetting that order is kept. Block instructions preserve order while stack under stack reverses it. Mixing the two without thinking produces swapped values.
- Assuming the old stack is visible. Inside a block, a pop does not reach the caller’s values. Bring in what you need first.
- Leaving results behind. Anything not counted into the end instruction is discarded, which is the point, but easy to forget when adding a new result late in development.
Testing the idea
When learning, write a block that takes zero values, pushes a few, and ends with a count of one. Trace the stacks by hand before and after. Then try a count that is too large and watch where the zeros come from. A few minutes of this builds an intuition that makes larger programs much safer, and it pays off whenever you use the program stack in a more demanding way than the basics allow.