Here is the bottom-up parse of the assignment statement a = b*-c + b*-c and the syntax-directed translation into three-address code.
|Parser action||attribute||Three- address code|
|id=id ∗ –id + id ∗ –id|
|id=E1 ∗ –id + id ∗ –id||E1.place = b|
|id=E1 ∗ –E2 + id ∗ –id||E2.place = c|
|id=E1 ∗ E2 + id ∗ –id||E2.place = t1||t1 = – c|
|id=E1 + id ∗ –id||E1.place = t2||t2 = b∗t1|
|id=E1 + E2 ∗ –id||E2.place = b|
|id=E1 + E2 ∗ –E3||E3.place = c|
|id=E1 + E2 ∗ E3||E3.place = t3||t3 = – c|
|id=E1 + E2||E2.place = t4||t4 = b∗t3|
|id=E1||E1.place = t5||t5 = t2+t4|
|S||a = t5|
Three-address codes are often implemented as a set of quadruples. Each quadruple has
four fields: an operator, two operands (or sources) and a destination. In C++, for
example, one can design a quadruple class and then declare a simple array of quadruples.
This leads to the following arrangement; the index of the array element acts as the number of quadruple generated.
An array of pointers to quads can be employed which leads to the following structure:
We now use the syntax-directed translation scheme for the flow-of-control statements found in most procedural programming languages.
where E is a boolean expression. Consider the statement
if c < d then
x = y + z
x = y – z
One possible 3-address code could be
if c < d goto L1
L1: x = y + z
L2: x = y – z
We will assume that a three-address statement can be symbolically labeled;
the function newlabel() returns a new symbolic label each time it is called