Three-address code – Basic Computer Science

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 a fixed- or floating-point arithmetic operator, or a logical operator on boolean-valued data. Thus a source language expression like x+ y*z might be translated into a sequence

where t1 and t2 are compiler-generated temporary names.

* The unraveling of complicated arithmetic expressions and of 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.

Three-address code is a linearized representation of a syntax tree or a dag in which explicit names correspond to the interior nodes of the graph. The syntax tree and dag are represented by the three-address code sequences. Variable names can appear directly in three address statements.

Fig.3.5 Three-address code corresponding to the syntax tree and dag

The reason for the term “three-address code” is that each statement usually contains three addresses, two for the operands and one for the result.

1.    Assignment statements of the form x : = y op z, where op is a binary arithmetic or logical operation.

2. Assignment instructions of the form x : = op y, where op is a unary operation. Essential unary operations include unary minus, logical negation, shift operators, and conversion operators that, for example, convert a fixed-point number to a floating-point number.

3. Copy statements of the form x : = y where the value of y is assigned to x.

4.     The unconditional jump goto L. The three-address statement with label L is the next to be executed.

5.  Conditional jumps such as if x relop y goto L. This instruction applies a relational operator (<, =, >=, etc. ) to x and y, and executes the statement with label L next if x stands in relation relop to y. If not, the three-address statement following if x relop y as in the usual sequence.

6. param x and call p, n for procedure calls and return y, where y representing a returned value is optional. For example,

7.Indexed assignments of the form x : = y[i] and x[i] : = y.

8.Address and pointer assignments of the form x : = &y , x : = *y, and *x : = y.

When three-address code is generated, temporary names are made up for the interior nodes of a syntax tree. For example, id : = E consists of code to evaluate E into some temporary t, followed by the assignment id.place : = t.

Given input a : = b * – c + b * – c, the three-address code is as shown in Fig. 8.3a. The synthesized attribute S.code represents the three-address code for the assignment S.

The nonterminal E has two attributes :

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

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

Syntax-directed definition to produce three-address code for assignments

Fig.3.6 Semantic rules generating code for a while statement

PRODUCTION SEMANTIC RULES

S->whileEdoS1: S.begin := newlabel;

S.after := newlabel;

S.code := gen(S.begin ‘:’) ||

E.code ||

gen ( ‘if’ E.place ‘=’ ‘0’ ‘goto’ S.after)|| S1.code ||

gen ( ‘goto’ S.begin) || gen ( S.after ‘:’)

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

Ø     Notation gen(x ‘:=’ y ‘+’ z) is used to represent three-address statement x := y + z. Expressions appearing instead of variables like x, y and z are evaluated when passed to gen, and quoted operators or operand, like ‘+’ are taken literally.

Ø     Flow-of-control statements can be added to the language of assignments. The code for S

while E do S1 is generated using new attributes S.begin and S.after to mark the first statement in the code for E and the statement following the code for S, respectively.

Ø The function newlabel returns a new label every time it is called.

We assume that a non-zero expression represents true; that is when the value of E becomes zero, control leaves the while statement.

A three-address statement is an abstract form of intermediate code. In a compiler, these statements can be implemented as records with fields for the operator and the operands. Three such representations are: Quadruples, Triples, Indirect triples

Ø     A quadruple is a record structure with four fields, which are, op, arg1, arg2 and result.

Ø     The op field contains an internal code for the operator. The three-address statement x : = y op z is represented by placing y in arg1, z in arg2 and x in result.

Ø     The contents of fields arg1, arg2 and result are normally pointers to the symbol- entries for the names represented by these fields. If so, temporary names must be entered into the symbol table as they are created.

Triples:

Ø     To avoid entering temporary names into the symbol table, we might refer to a temporary value by the position of the statement that computes it.

Ø     If we do so, three-address statements can be represented by records with only three fields: op, arg1 and arg2.

Ø     The fields arg1 and arg2, for the arguments of op, are either pointers to the symbol table or pointers into the triple structure ( for temporary values ).

Ø     Since three fields are used, this intermediate code format is known as triples.

A ternary operation like x[i] : = y requires two entries in the triple structure while x : = y[i] is naturally represented as two operations.

Fig. 3.8 (a) x[i] : = y (b) x : = y[i]

Indirect Triples:

Another implementation of three-address code is that of listing pointers to triples, rather than listing the triples themselves. This implementation is called indirect triples.

For example, let us use an array statement to list pointers to triples in the desired order. Then the triples shown above might be represented as follows:

Fig. 3.9 Indirect triples representation of three-address statements