Intermediate Code Generation
Intermediate representations include syntax trees, DAGs, postfix notation and three-address code (TAC), where each instruction has at most three addresses: x = y op z.
Three-Address Code Example
Source: a = b * -c + b * -c
t1 = minus c
t2 = b * t1
t3 = minus c
t4 = b * t3
t5 = t2 + t4
a = t5
Quadruples, Triples and Indirect Triples
| # | op | arg1 | arg2 | result |
|---|---|---|---|---|
| 0 | minus | c | t1 | |
| 1 | * | b | t1 | t2 |
| 2 | minus | c | t3 | |
| 3 | * | b | t3 | t4 |
| 4 | + | t2 | t4 | t5 |
| 5 | = | t5 | a |
Triples omit the result field and refer to earlier instructions by position, e.g. (1) * b (0). Indirect triples keep a separate list of pointers to triples, so instructions can be reordered easily during optimization.
Control Flow
Source: while (i < 10) { sum = sum + i; i = i + 1; }
L1: if i < 10 goto L2
goto L3
L2: t1 = sum + i
sum = t1
t2 = i + 1
i = t2
goto L1
L3: ...
Backpatching fills in jump targets later, allowing one-pass generation of code for boolean expressions and control flow.
Track your progress through the Compiler Design course