◄ WORLD V · SONNY 5DART 265 · a helldive at the net

THREE-ADDRESS CODE one operator, three operands, a fresh temporary per step

Three-address code is the classic compiler intermediate representation: every instruction is x = y op z — at most one operator, three addresses. A nested expression is flattened into a sequence with a fresh temporary per subexpression: (a+b)*c becomes t1 = a + b; t2 = t1 * c. This flat form is where the optimizer lives — the basic blocks, the dataflow, the CSE of batch 35 all operate on three-address code. It sits between the syntax tree and the machine: linear like assembly, but with unlimited virtual temporaries and no commitment to registers yet.

THE TECHNIQUE x = y op z; a fresh temporary per subexpression

The expression (a+b)*c lowered to three-address code. The demo emits one instruction per operator, allocating temporaries: live demo


HISTORY & CREDIT Aho-Sethi-Ullman lineage

“The compiler optimizes the syntax tree.” — it flattens the tree to three-address code first, because dataflow and CSE need a linear sequence of simple assignments, not a nest. The IR, not the AST, is where optimization happens. cited

lineage · three-address code (quadruples/triples) has no single inventor; it was codified as the teaching IR by Aho, Sethi & Ullman (the “Dragon Book”, 1986) after decades of compiler practice.
role · the substrate for basic blocks, dataflow, and CSE (batch 35).
now · LLVM IR and GCC's GIMPLE are its industrial descendants.

Flatten the tree to x = y op z and every optimization becomes a walk over a list. The temporary per step is the price of linearity — and the room the optimizer needs to work. Dragon Book lineage

RECOMMEND FOR I-13 lowering + temporaries, computed

On the canonical compiler, lowering (2+3)*4 allocates 2 temporaries (t1, t2) and reaches 20:

$ i13 run m_tac.i13 # t1 = a+b ; t2 = t1*c RUN OK . 18 step(s) . peak stack 2 . call depth 0 t1 = 5 t2 = 20 temps = 2
Recommend: i13's IVM opcode stream is a three-address-code-shaped IR — a linear sequence of simple operations, each consuming operands and producing one result, exactly the form the optimizer wants. That is why batch 35's FREE/REPORT passes (reaching-definitions, available-expressions, CSE) map onto i13 at all: they operate on this flat IR. i13 doesn't expose named temporaries (it uses the stack, dart 262), but its single-pass validator walks the same linear form. TAC is not a recommend; it is the shape i13's middle already has.