Befunge Techniques

Writing Loops in Befunge

Build counted and conditional loops in Befunge by routing the pointer back over earlier cells, with tested-first and tested-last layouts and common pitfalls.

On this page
  1. A loop is a route that returns
  2. Counted loops
  3. Test-first loops
  4. Conditional loops
  5. The compact test-and-skip idiom
  6. Keeping the stack balanced
  7. Debugging an endless or empty loop
  8. Funge-98 note

A loop is a route that returns

There is no loop statement in Befunge. A loop occurs when the pointer’s path comes back to a cell it has already visited, so that the same cells run again. The skill is in making it return only when it should, and in making it leave when the work is done. These are the same ideas as in the geometric loops that arise from grid layout, but here the focus is on deliberately building them.

Every loop needs three parts: a body that does the work, a state that changes during the work, and a test that reads the state and chooses between repeating and leaving. In Befunge the state lives on the stack, or in a grid cell, and the test is a horizontal or vertical if.

Counted loops

A counted loop runs a fixed number of times. The count is the state. Each pass reduces it by one, and the loop leaves when it reaches zero.

The usual bottom-tested form places the test at the end. The pointer does the body, decrements, duplicates the counter, tests the copy, and either returns or leaves. The worked countdown program shows this with every step of the stack written out. A star printer in the same shape:

4>"*",1-:#v_@
 ^        <

This prints four asterisks. The body is "*",, the decrement is 1-, the duplicate and test are : and _, and the return path runs along the bottom row. A bottom-tested loop always runs at least once. That matters: if the starting count could be zero, this loop would print one star and then subtract to -1, which is nonzero, and keep counting down through negative numbers without ever reaching zero. So a bottom-tested loop is only safe when you know the count is at least one.

Test-first loops

A top-tested loop checks before doing anything, so a count of zero does nothing. It costs a little more layout, but it is the safer shape when the count comes from input.

4v  -1,"*"<
 >:       |
          @

The pointer pushes 4 and turns down at the v. The > sends it east, where : copies the counter and the | tests the copy. If the value is zero, the pointer goes down to the @ and the program ends. If it is nonzero, the pointer goes up into the < on the top row and travels west. It enters string mode, pushes the code for an asterisk, prints it, pushes 1 and subtracts, then continues west until it reaches the v and goes down into the test again.

Count the cells and you will see the body is written backward in the source, because the pointer reads it right to left. That reversed reading is the main cost of this shape. Change the 4 to 0 and the program prints nothing.

Conditional loops

A conditional loop runs until some data-dependent condition holds, not for a fixed count. Reading characters until a newline is the classic case, and the guide on numeric input shows a complete version. The structure is identical: a body, state in a value on the stack, and a test that the if instruction can read. The only difference is that the state changes by itself, as input arrives, instead of being counted down.

Euclid’s method is a good example. It keeps replacing a pair of numbers until the remainder is zero. The test is on the remainder, which is a computed value, so the Euclidean algorithm is a conditional loop whose condition is a calculation. Its exact layout is left to the algorithms cluster.

The compact test-and-skip idiom

Many programs squeeze the test and the body together by using the trampoline instruction so that one set of cells serves both the forward pass and the return. The print-until-zero loop is an example. It saves space, but because each cell is read in two directions it is harder to follow. Use it once you are comfortable reading single-direction loops.

Keeping the stack balanced

Each pass should leave the stack the same size as it began, apart from the changing counter. Make a habit of writing the stack height at the top and bottom of the body. If it grows by one each pass, the program leaks values and the stack grows without bound. If it shrinks, you eventually hit stack underflow, which often makes a loop terminate early or never. The factorial program is a good exercise here, because the multiplication accumulates a result and the counter must stay in step with it.

Debugging an endless or empty loop

When a loop runs forever:

  • Check the sign: did the counter go past zero without ever equaling it?
  • Check that the test actually pops what you think it pops. The : before the test leaves the original in place, and forgetting it consumes the counter.
  • Check that the return arrow points where you expect, in the correct column.

When a loop never runs, check the opposite: whether the test sends zero and nonzero to the paths you intended. Swap the exits and see if behavior changes.

Printing the counter at each step with . is a quick way to find these errors, and so is tracing by hand for a count of 2 or 3. Short counts are enough to expose almost every loop bug.

Funge-98 note

Funge-98 adds an iterate instruction that repeats the next instruction a given number of times. It replaces some small loops, but the routing technique here still applies to everything else, and it is the only approach available in Befunge-93.

The complete guide to befunge techniques

Befunge Programming Techniques Overview
Read the guide

Keep exploring

Guides from other topics

All topics →

What Is Funge-98?

Funge-98 generalizes Befunge into a larger, better-defined family of grid languages. Learn its goals, its main differences from Befunge-93, and why it matters.

Funge-98 5 min read