Three-Address Statements
Three-address code: a linear intermediate representation where every instruction has at most one operator and three addresses. Covers the general form, where temporaries come from, the common statement forms, and a fully worked translation of (a + b) * (c - d).
Definition
A three-address statement (or instruction) is an intermediate-code instruction with at most one operator on the right-hand side and at most three addresses — two operands and one result — of the general form
x = y op z.
An address is one of three things:
- a name — a programmer variable such as
aorcount; - a constant — a literal such as
4or3.14; - a compiler-generated temporary — a fresh name such as
t1, invented to hold an intermediate result.
Why "three-address"?
Look at the general form x = y op z. It mentions three addresses:
The result x is one address; the two operands y and z are the other two. Because at most one operator is allowed per statement, a complex expression cannot be written in a single line — it must be flattened into a sequence of these simple statements, each introducing a temporary for one operator. That uniformity is exactly what makes three-address code easy to optimise and easy to translate to a real machine.
Where Temporaries Come From
A complex expression is broken into a sequence of three-address statements, generating one new temporary per interior (operator) node of its syntax tree. Each operator in the tree becomes exactly one statement, and the temporary that statement assigns to is the "result" handed up to the parent node.
Take the running example x = (a + b) \* (c - d). Its syntax tree has three interior nodes — +, -, and \* — so we generate three temporaries t1, t2, t3, plus a final copy into x:
The leaves (a, b, c, d, x) are programmer variables and need no temporaries — only the interior operator nodes do. Translation walks the tree bottom-up: each child is reduced to a single address before its parent is emitted, which is why t3's operands are already the temporaries t1 and t2.
The Common Forms
Despite the single name, "three-address statement" covers a small family of instruction shapes. Each still obeys the at-most-one-operator rule.
| Form | Syntax | Example | Meaning |
|---|---|---|---|
| Binary assignment | x = y op z | t1 = a + b | apply a binary operator |
| Unary assignment | x = op y | t = minus c , x = not y | apply a unary operator |
| Copy | x = y | x = t3 | copy one address into another |
| Unconditional jump | goto L | goto L1 | jump to labelled statement L |
| Conditional jump | if x relop y goto L | if a < b goto L1 | jump to L when the test holds |
| Procedure call | param x … call p, n … return y | param a ; call p, 1 | pass n params, then call p |
| Indexed copy | x = y[i] , x[i] = y | t = a[i] | read / write an array element |
| Pointer & address | x = &y , x = \*y , \*x = y | p = &a | take address / load / store via pointer |
A few notes:
- Unary operators like
minus(arithmetic negation) andnot(logical) take only one operand, so they fit inx = op y. - Jumps carry a label
Lrather than a data operand; labels mark target statements and are how control flow is expressed in flat code. - A procedure call is split across several statements: one
paramper argument, then a singlecall p, nnaming the procedure and its argument count.
Worked Example: x = (a + b) \* (c - d)
Walking the syntax tree bottom-up, each interior node produces one statement:
Reading it line by line:
t1 = a + b— the left subtree(a + b)is reduced to the single addresst1.t2 = c - d— the right subtree(c - d)is reduced to the single addresst2.t3 = t1 \* t2— the root multiply combines the two subresults; both operands are already single addresses, satisfying the at-most-three-addresses rule.x = t3— a copy statement stores the result into the programmer's variablex.
Three operators in the source produced three temporaries (t1, t2, t3) — one per interior node — plus one copy.
How They Are Stored
These statements are not kept as text; they are held in one of three concrete data structures — quadruples, triples, and indirect triples — each a different way of recording the operator and its addresses, covered in the next topic.
Key Points
- A three-address statement has at most one operator and at most three addresses (two operands, one result):
x = y op z. - An address is a name, a constant, or a compiler-generated temporary.
- A complex expression is flattened into a sequence of these statements — one temporary per interior node of the syntax tree.
- The family of forms includes binary/unary assignments, copies, jumps, conditional jumps, calls, indexed accesses, and pointer operations.
- For
x = (a + b) \* (c - d)the three operators yieldt1,t2,t3plus a copy intox. - Three-address code is stored as quadruples, triples, or indirect triples.