Three-Address Code (3AC): Quadruples, Triples and Indirect Triples with a Worked Example
Carry one expression through 3AC, quadruples, triples and indirect triples. See how every record is formed, valued and safely reordered.
KnowledgeGate Team
Exam prep & CS education

Three-address code limits each instruction to one operator. Quadruples store named results, triples refer to producing rows, and indirect triples separate execution order from fixed records; those differences determine how expressions are converted, counted and safely reordered.
The broader Intermediate Code Generation in Compiler Design: Three-Address Code, Quadruples, Triples and Worked Examples connects TAC to unary-minus lowering, syntax-directed translation, control flow and DAG optimisation. By contrast, holding one evaluated expression constant isolates the record-level differences: named quadruple results, positional triple references and indirect-triple pointer order.
Three-address code: what the three addresses mean
A three-address instruction contains one operator, at most two source addresses and one destination. It does not mean three operands appear on the right-hand side. Common shapes include:
x = y op z
x = op y
x = y
if x relop y goto L
goto LAn address can be a variable, temporary, constant, label or indexed location. Abstract 3AC does not decide whether t1 ultimately lives in a register or memory.
In the compiler pipeline, tokenisation happens during Lexical Analysis in Compiler Design: Tokens and Lexemes, while Parsing in Compiler Design: Top-Down and Bottom-Up Explained establishes grammatical structure. After syntax and semantic work, the compiler forms 3AC for optimisation and target-code generation.
Quadruples, triples and indirect triples: one IR, three layouts
The same 3AC can use different record layouts. Here - marks an unused field. A unary operation has no second argument; a quadruple copy may be (=, source, -, destination).
Representation | Record shape | How the result is named | What happens on reordering |
|---|---|---|---|
Quadruple |
| A named result such as | Records can move while named dependencies remain readable |
Triple |
| The producing record number, such as | Physical movement is dangerous because later records refer to positions |
Indirect triple | Triple records plus a pointer list | The triple record number | Execution order changes through pointers, without renumbering records |
Quadruples spend space on temporary names but expose dependencies clearly. Triples remove the result field, so (0) depends on a physical record number. Indirect triples keep records fixed and reorder pointers instead.
Three-address code worked example with exact values
Use the expression E = (a - b) + (c * d) - (a - b) / e, where a = 14, b = 5, c = 3, d = 8 and e = 3. The subexpression (a - b) appears twice. Because all operands here are pure scalar values and do not change during evaluation, it can safely be computed once and reused.
The exact lowering is:
t1 = a - b = 14 - 5 = 9t2 = c * d = 3 * 8 = 24t3 = t1 + t2 = 9 + 24 = 33t4 = t1 / e = 9 / 3 = 3t5 = t3 - t4 = 33 - 3 = 30
Checking against the original expression gives 9 + 24 - 3 = 30. The right-hand side therefore needs five arithmetic 3AC statements and temporaries t1 through t5 under this lowering.
If a question also demands an assignment such as x = E, you may append x = t5. Alternatively, a representation may allow the final arithmetic instruction to write directly to x. State the convention before counting, because the explicit copy changes the instruction total.

Quadruples for the same worked expression
A quadruple stores an operator, two arguments and a named result:
No. | op | arg1 | arg2 | result | value |
|---|---|---|---|---|---|
0 |
|
|
|
| 9 |
1 |
|
|
|
| 24 |
2 |
|
|
|
| 33 |
3 |
|
|
|
| 3 |
4 |
|
|
|
| 30 |
Read row 2 from left to right as t3 = t1 + t2. Going in the other direction, t4 = t1 / e becomes row 3, (/, t1, e, t4). The result belongs in the final column, not in arg1.
If the answer must be copied to x, append row 5 as (=, t5, -, x). A direct final row (-, t3, t4, x) avoids that copy. Both forms can express the intended result, but an instruction-count answer must identify which form it counts.
Triples and indirect triples for the same expression
A triple has no result field. Its row number names the value produced by that row.
No. | op | arg1 | arg2 | value |
|---|---|---|---|---|
0 |
|
|
| 9 |
1 |
|
|
| 24 |
2 |
|
|
| 33 |
3 |
|
|
| 3 |
4 |
|
|
| 30 |
Here (0) means the result produced by triple 0. It is not a variable named zero and not the constant 0. If assignment to x is required, an optional row 5 may be written as (=, (4), x) under this triple convention; it is not part of the five-record right-hand-side comparison.
An indirect triple adds pointers that specify execution order. The original pointer list is:
Pointer | Triple record |
|---|---|
P0 | 0 |
P1 | 1 |
P2 | 2 |
P3 | 3 |
P4 | 4 |
Rows 0 and 1 are independent for these pure scalar operands, so they can exchange execution positions. A legal rescheduled pointer list is:
Pointer | Triple record |
|---|---|
P0 | 1 |
P1 | 0 |
P2 | 2 |
P3 | 3 |
P4 | 4 |
The physical triple numbers remain unchanged, so references inside rows 2 to 4 also remain unchanged. Only the pointer order changes.

How exam questions test three-address code
In the GATE CS Exam Preparation context, four question types matter most:
Translate an expression. Preserve precedence, introduce temporaries and write one operator per 3AC statement.
Count instructions or temporaries. Declare whether common subexpressions are reused and whether a final copy is included.
Fill record fields. Keep the quadruple result in its result column, and replace triple temporary names with record references.
Judge a reorder. Draw dependencies first, then check whether an indirect pointer order schedules every producer before its consumers.
For y = (m + n) * (p - q), with m = 7, n = 5, p = 10 and q = 4, the lowering is t1 = m + n = 12, t2 = p - q = 6, and y = t1 * t2 = 72. The corresponding quadruples are (+, m, n, t1), (-, p, q, t2) and (*, t1, t2, y); the triples replace t1 and t2 with references (0) and (1). The value 72 checks the translation, but the symbolic rows are still required.
Three-address code traps that cost marks
Counting operators without stating reuse. The running expression takes six arithmetic statements if
(a - b)is computed twice, but five when common-subexpression reuse is allowed. The fix is to state the reuse assumption before reporting the count.Moving triple rows as if positions were temporary names. A physical move can invalidate references such as
(0). Draw dependency arrows and use an indirect pointer list when you need a different schedule.Assuming every operation is safe to reuse or move. Arrays, pointer writes, function calls and volatile values may introduce aliasing or side effects. Check those dependencies before applying the pure-scalar reasoning used here.
Smaller notation errors also matter: putting a quadruple result in arg1, reading (0) as constant zero, or silently adding or omitting the final copy. A one-line statement of your convention prevents most counting disputes.
The short version and the next step
3AC limits each instruction to one operator. Quadruples name results, triples use record positions, and indirect triples add a pointer layer that can be reordered. For the worked expression, E = 30. With safe reuse of (a - b), the right-hand side occupies five arithmetic records.
If you want a structured plan across compiler design and the wider syllabus, use GATE Guidance by Sanchit Sir. If you already know the concept and want to test conversion and counting under exam conditions, use the GATE Test Series instead.
As a self-check, convert z = (r + s) * (r + s) - t into 3AC, quadruples, triples and indirect triples, first without reuse and then with reuse. State why the instruction and temporary counts differ.
Keep learning

Intermediate Code Generation in Compiler Design: TAC, Backpatching and DAGs
Connect expressions, short-circuit control flow and local optimisation through a single worked translation, from source code to resolved TAC and a reusable DAG.

Ambiguous Grammars and Inherent Ambiguity: Worked CFG Examples for GATE
Learn what two derivations really prove, resolve expression ambiguity with precedence, and trace the classic inherently ambiguous language through aabbcc.

Simplification of CFG: Remove Epsilon, Unit and Useless Productions Step by Step
Simplify one context-free grammar from nine nonterminals to six. See each intermediate grammar, complete unit closures, symbol checks and final derivations.

Phases of Compiler Explained: Worked Example from Tokens to Target Code
Follow one four-line program through lexical, syntax and semantic analysis, then see its intermediate code optimized to a final stored value of 24.0.