Chapter 8: Intermediate Code Generation

Syntax directed translation of expression into 3-address code

S id := E S.code = E.code ||
  gen(id.place:= E.place)
E E1 + E2 E.place:= newtmp
  E.code:= E 1 .code || E2 .code ||
  gen(E.place := E 1 .place + E 2 .place)
E E1 * E 2 E.place:= newtmp
  E.code := E 1 .code || E 2 .code ||
  gen(E.place := E1 .place * E 2 .place)
   

Three-address code is a sequence of statements of the general form

X := y op z

Where x, y and z are names, constants, or compiler generated temporaries. op stands for any operator, such as fixed- or floating-point arithmetic operator, or a logical operator on Boolean-valued data. Note that no built up arithmetic expression are permitted, as there is only one operator on the right side of a statement. Thus a source language expression like x + y * z might be translated into a sequence

t1 := y * z

t2 := x + t1

where t1 and t2 are compiler-generated temporary names. This unraveling of complicated arithmetic expression and of nested flow-of-control statements makes three- address code desirable for target code generation and optimization.

The use of names for the intermediate values computed by a program allows three-address code to be easily rearranged unlike postfix notation. We can easily generate code for the three-address code given above. The S-attributed definition above generates three-address code for assigning statements. The synthesized attribute S.code represents the three-address code for the assignment S. The nonterminal E has two attributes:

. E.place , the name that will hold the value of E, and

. E.code , the sequence of three-address statements evaluating E.

The function newtemp returns a sequence of distinct names t1, t2,.. In response to successive calls.