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

Updated 16 Sep 20266 min read

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:

Code
x = y op z
x = op y
x = y
if x relop y goto L
goto L

An 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

(op, arg1, arg2, result)

A named result such as t1

Records can move while named dependencies remain readable

Triple

(op, arg1, arg2)

The producing record number, such as (0)

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:

  1. t1 = a - b = 14 - 5 = 9

  2. t2 = c * d = 3 * 8 = 24

  3. t3 = t1 + t2 = 9 + 24 = 33

  4. t4 = t1 / e = 9 / 3 = 3

  5. t5 = 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.

DAG for the worked expression E, with the shared node t1 = a - b feeding both t3 and t4 and the root t5 = 30.

Quadruples for the same worked expression

A quadruple stores an operator, two arguments and a named result:

No.

op

arg1

arg2

result

value

0

-

a

b

t1

9

1

*

c

d

t2

24

2

+

t1

t2

t3

33

3

/

t1

e

t4

3

4

-

t3

t4

t5

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

-

a

b

9

1

*

c

d

24

2

+

(0)

(1)

33

3

/

(0)

e

3

4

-

(2)

(3)

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.

Three-panel comparison of the five records as quadruples, triples with record references, and a reordered indirect-triple pointer list.

How exam questions test three-address code

In the GATE CS Exam Preparation context, four question types matter most:

  1. Translate an expression. Preserve precedence, introduce temporaries and write one operator per 3AC statement.

  2. Count instructions or temporaries. Declare whether common subexpressions are reused and whether a final copy is included.

  3. Fill record fields. Keep the quadruple result in its result column, and replace triple temporary names with record references.

  4. 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

  1. 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.

  2. 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.

  3. 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.