Type a branch, a subject or a topic — “round robin”, “paging”, “civil”.

Three-Address Code

Walk the syntax tree bottom-up; every operator emits exactly one instruction.

Skip to the animation

Three-address code is a flat list of instructions, each with at most one operator and at most three operands — the representation a compiler optimises before it commits to any particular machine.

Why flatten the tree at all

The syntax tree is the right shape for checking a program and the wrong shape for improving one. Questions an optimiser asks constantly — is this value used again? is this operand a constant? does this instruction depend on that one? — require walking a tree, but are simple inspection on a list.

So the tree is flattened into instructions with explicit names for every intermediate value. The name three-address comes from the general form x = y op z: two operand addresses and one result.

FormExample
Binaryt2 = rate * t1
Unaryt1 = inttofloat(60)
Copyposition = t3
Unconditional jumpgoto L1
Conditional jumpif x < y goto L1
Indexedt1 = a[i]

The generation rule

One postorder walk, and one rule: every interior node emits exactly one instruction, after its children have been reduced to addresses. Leaves emit nothing, because a variable or constant is already an address.

  1. 1Visit the left child, then the right child.
  2. 2Both are now names — either original variables or temporaries.
  3. 3Emit one instruction combining them, into a fresh temporary.
  4. 4Return that temporary as this subtree's address.

Count the operators in the tree and you know exactly how many instructions you will get. Four operators here — a conversion, a multiply, an add and an assignment — give four instructions.

Instruction order comes from the tree, not the source

The source reads initial + rate * 60, but the multiplication is emitted before the addition. That is not an optimisation — it is forced. The addition cannot emit until its right operand has a name, and that name only exists once the multiply has run.

So the precedence that syntax analysis baked into the tree's shape reappears here as the order of the instructions. Every phase preserves that decision in whatever form it uses.

Quadruples, triples and SSA

Quadruples
(op, arg1, arg2, result) — each instruction names its own result, so instructions can be reordered or deleted freely. This is what optimising compilers use.
Triples
(op, arg1, arg2), with results referred to by instruction position. More compact, but moving one instruction renumbers every reference to it.
Static single assignment
The modern refinement: every name is assigned exactly once, so "where did this value come from?" has one answer. Nearly every serious optimiser works in SSA today.

Advantages and disadvantages

Advantages

  • Simple and uniform, so optimisations are easy to state and implement.
  • Machine independent — one front end can serve many targets.
  • Every intermediate value has a name, which makes dataflow analysis straightforward.

Disadvantages

  • Loses the structure the tree made explicit; loops must be rediscovered from jumps.
  • Generates many temporaries, most of which register allocation must later eliminate.
  • Longer than the source, so compilation uses more memory.

Watch it work

loading visualisation…

Check yourself

question 1 / 4

One question at a time. Pick an answer to see why it is right or wrong, then move on — there is no score to keep and nothing is saved.

Why is it called three-address code?
Walking the syntax tree bottom-up, what does each operator node emit?
Why generate an intermediate representation at all, rather than emitting machine code from the tree?
Quadruples versus triples: what is the practical difference?

0 / 4

4 still unanswered — the dots above jump straight to them.