Translating Arithmetic Expressions into Three-Address Code (TAC): From Syntax Tree to TAC

Translating Arithmetic Expressions into Three-Address Code (TAC): From Syntax Tree to TAC

Verified Sources
Sep 12, 2026

Three-address code [TAC\text{TAC}]{def="An intermediate code where each instruction uses at most three operands: two inputs and one result"} is a linearized intermediate representation used in compilers. Each TAC instruction typically has the form x:=y op zx := y \ \text{op}\ z (binary) or x:=op yx := \text{op}\ y (unary), where operands are names (identifiers, constants, or compiler-generated temporaries).2

A standard translation workflow is:

  1. Parse the expression into a tree structure (AST/parse tree).
  2. Traverse the tree (commonly postorder) so that child computations are emitted before the parent.
  3. For each operator node, emit one TAC instruction using temporaries to hold intermediate results.
  4. The final TAC value is the “place”/temporary of the root node.2

Mermaid view of the idea (AST node → emitted TAC line):

Key ideas/terms you will use:

  • AST
  • Temporary variable
  • Postorder traversal
  • Unary minus
  • Intermediate code generation

Footnotes

  1. Lecture 8: Intermediate-Code Generation - Defines TAC and shows unraveling into temporaries.

  2. Three-Address Code (UWO CS447) - Gives TAC instruction forms and syntax-directed translation rules. 2

  3. CS316 Compilers Lab PA4.pdf - Describes generating TAC from an AST via post-order with temporaries.

Syntax-directed translation intuition (expression to intermediate code)

Three-address code (TAC) translation process

TAC instruction constraints

In TAC, “complicated arithmetic expressions are represented as a sequence of three-address instructions, using temporaries for intermediate values.”2 Concretely:

  • Binary operators (e.g., ++, *, -):
    emit tk:=left.place op right.placet_k := \text{left.place} \ \text{op}\ \text{right.place}
  • Unary minus (e.g., b-b):
    emit tk:=minus operand.placet_k := \text{minus}\ \text{operand.place} (often written as a unary operator like minus to distinguish it from binary subtraction).2

The core generation can be described with a syntax-directed translation scheme where each expression node has attributes:

  • E.placeE.\text{place}: where the value of EE lives (identifier or temporary)
  • E.codeE.\text{code}: the TAC emitted to compute EE.

In practice, the compiler performs a postorder walk: compute children TAC first, then emit the parent TAC using their resulting places.

Algorithm (tree → TAC)

Let each node in the AST return its placeplace:

  • If the node is an identifier xx: E.place:=xE.\text{place} := x and E.code:=ϵE.\text{code} := \epsilon.
  • If the node is a binary operator op(L,R)\text{op}(L,R):
    • translate LL and RR to get L.place,R.placeL.\text{place}, R.\text{place}
    • create a new temporary tt
    • emit t := L.place op R.place
    • return tt
  • If the node is unary minus minus(U)\text{minus}(U):
    • translate UU to get U.placeU.\text{place}
    • create a new temporary tt
    • emit t := minus U.place
    • return tt.2

Unary minus vs binary minus: many compiler presentations explicitly use a special operator minus for unary negation so that TAC generation uses different instruction forms for unary negation and subtraction.

Footnotes

  1. Lecture 8: Intermediate-Code Generation - Defines TAC and shows unraveling into temporaries.

  2. Three-Address Code (UWO CS447) - Gives TAC instruction forms and syntax-directed translation rules. 2 3 4

  3. Lecture 7 (compiler/three-address-code PDF snippet) - Shows unary minus handled with a special unary operator and provides a TAC example. 2 3

  4. CS316 Compilers Lab PA4.pdf - Describes generating TAC from an AST via post-order with temporaries.

Generating TAC by postorder traversal for an arithmetic expression

  1. 1
    Step 1

    Parse the expression with correct precedence/associativity into an AST.

  2. 2
    Step 2

    For each operator node, recursively translate children (postorder).

  3. 3
    Step 3

    For identifiers/constants, set E.placeE.\text{place} to the identifier itself and emit no TAC.

  4. 4
    Step 4

    If the node is unary minus, create a fresh temporary tt and emit t:=minus E1.placet := \text{minus}\ E_1.\text{place}.

  5. 5
    Step 5

    If the node is binary operator (e.g., ++, -, *), create fresh temporary tt and emit t:=EL.place op ER.placet := E_L.\text{place} \ \text{op} \ E_R.\text{place}.

  6. 6
    Step 6

    After processing the root operator, the returned place is the TAC result; optionally emit a final copy into the destination.

Expression to translate

Translate into TAC the arithmetic expression: ab+(cd)ea * -b + (c - d) * e

We must respect precedence:

  • Unary minus binds to bb first.
  • Multiplication * binds tighter than addition ++.
  • Parentheses (cd)(c-d) force subtraction before the multiplication by ee.

Corresponding syntax tree (AST)

Using an AST whose internal nodes are operators and leaves are operands, the structure is:

  • Root is ++
  • Left child is * between aa and (b)(-b)
  • Right child is * between (cd)(c-d) and ee

Mermaid syntax tree:

Translate AST to TAC

We perform postorder:

  1. Compute b-b
  2. Compute a(b)a * (-b)
  3. Compute (cd)(c-d)
  4. Compute (cd)e(c-d) * e
  5. Compute the final sum

Let temporaries be t1,t2,t3,t_1,t_2,t_3,\dots in creation order. TAC instructions (quadruple style omitted, using the common assignment form):

TAC sequence

  1. Unary minus t1:=minus bt_1 := \text{minus}\ b (i.e., t1=bt_1 = -b)2
  2. Left multiplication t2:=at1t_2 := a * t_1
  3. Subtraction in parentheses t3:=cdt_3 := c - d
  4. Right multiplication t4:=t3et_4 := t_3 * e
  5. Final addition t5:=t2+t4t_5 := t_2 + t_4

If the expression is assigned to some destination xx, you would finish with: x:=t5x := t_5 (though your prompt only asks to translate the expression itself).

These steps mirror the standard rule that each TAC instruction corresponds to one operator node, and operator outputs flow upward via temporaries.3

Footnotes

  1. Three-Address Code (UWO CS447) - Gives TAC instruction forms and syntax-directed translation rules. 2

  2. Lecture 7 (compiler/three-address-code PDF snippet) - Shows unary minus handled with a special unary operator and provides a TAC example.

  3. Lecture 8: Intermediate-Code Generation - Defines TAC and shows unraveling into temporaries.

  4. CS316 Compilers Lab PA4.pdf - Describes generating TAC from an AST via post-order with temporaries.

Operator-to-TAC mapping (one instruction per AST operator node)

Counts show how many TAC instructions correspond to each AST operator type in this expression.

Common pitfalls and how to avoid them

Pro Tip: Think “place” + “code”

When translating each AST node, return two things: where its value lives (place) and the TAC emitted to compute it (code). This is the classic SDT setup for TAC generation.

Footnotes

  1. Three-Address Code (UWO CS447) - Gives TAC instruction forms and syntax-directed translation rules.

Beware of precedence errors

If you accidentally parse ab+(cd)ea * -b + (c-d) * e as a(b+(cd)e)a * -(b + (c-d) * e) (or similar), the TAC order of emitted operations will change. Always reflect precedence and parentheses in the AST first.2

Footnotes

  1. Lecture 8: Intermediate-Code Generation - Defines TAC and shows unraveling into temporaries.

  2. Three-Address Code (UWO CS447) - Gives TAC instruction forms and syntax-directed translation rules.

Knowledge Check

Question 1 of 4
Q1Single choice

In typical three-address code (TAC) generation for expressions, what is the purpose of temporaries like t1,t2,t_1, t_2, \dots?