Unit - 3
Unit - 3
If the compiler directly translates source code into the machine code without
generating intermediate code then a full native compiler is required for each
new machine.
The intermediate code keeps the analysis portion same for all the compilers
that's why it doesn't need a full compiler for every unique machine.
Intermediate code generator receives input from its predecessor phase and
semantic analyzer phase. It takes input in the form of an annotated syntax
tree.
Using the intermediate code, the second phase of the compiler synthesis
phase is changed according to the target machine.
Intermediate representation
Intermediate code can be represented in two ways:
1. High Level intermediate code
2. Low Level intermediate code
High Level intermediate code: High level intermediate code can be represented as
source code. To enhance performance of source code, we can easily apply code
modification. But to optimize the target machine, it is less preferred.
Low Level intermediate code: Low level intermediate code is close to the target
machine, which makes it suitable for register and memory allocation etc. it is used
for machine-dependent optimizations.
Three-Address Code
Intermediate code generator receives input from its predecessor phase,
semantic analyzer, in the form of an annotated syntax tree. That syntax tree then
can be converted into a linear representation, e.g., postfix notation. Intermediate
code tends to be machine independent code. Therefore, code generator assumes to
have unlimited number of memory storage (register) to generate code.
Example:
a = b + c * d;
The intermediate code generator will try to divide this expression into sub-
expressions and then generate the corresponding code.
r1 = c * d;
r2 = b + r1;
a = r2
r being used as registers in the target program.
Triples
Each instruction in triples presentation has three fields:
op
arg1 and
arg2
The results of respective sub-expressions are denoted by the position of expression.
Triples represent similarity with DAG and syntax tree. They are equivalent to
DAG while representing expressions.
For computation of attributes we start from leftmost bottom node. The rule F
–> digit is used to reduce digit to F and the value of digit is obtained from lexical
analyzer which becomes value of F i.e. from semantic action F.val = digit.lexval.
Department of Computer Science,
Sri Lakshmi College of Arts & Science,
Kallakurichi
Page | 8
COMPILER DESIGN UNIT - 3
Hence, F.val = 4 and since T is parent node of F so, we get T.val = 4 from semantic
action T.val = F.val. Then, for T –> T1 * F production, the corresponding semantic
action is T.val = T1.val * F.val . Hence, T.val = 4 * 5 = 20
Similarly, combination of E1.val + T.val becomes E.val i.e. E.val = E1.val +
T.val = 26. Then, the production S –> E is applied to reduce E.val = 26 and
semantic action associated with it prints the result E.val . Hence, the output will be
26.
2. Inherited Attributes – These are the attributes which derive their values from
their parent or sibling nodes i.e. value of inherited attributes are computed by value
of parent or sibling nodes.
Example:
A --> BCD { C.in = A.in, C.type = B.type }
Computation of Inherited Attributes –
Construct the SDD using semantic actions.
The annotated parse tree is generated and attribute values are computed in top
down manner.
Example: Consider the following grammar
S --> T L
T --> int
T --> float
T --> double
L --> L1, id
L --> id
The SDD for the above grammar can be written as follow
Let us assume an input string int a, c for computing inherited attributes. The
annotated parse tree for the input string is