CD Unit 3 RV
CD Unit 3 RV
UNIT-3 (Lecture-1)
Example
Example
S→E$ { printE.VAL }
S→E$ { printE.VAL }
UNIT-3 (Lecture-2)
o 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.
o 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.
o Intermediate code generator receives input from its predecessor phase and semantic
analyzer phase. It takes input in the form of an annotated syntax tree.
o 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:
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 is close to the target machine, which makes it suitable for register
and memory allocation etc. it is used for machine-dependent optimizations.
Postfix Notation
o Postfix notation is the useful form of intermediate code if the given language is
expressions.
o Postfix notation is also called as 'suffix notation' and 'reverse polish'.
o Postfix notation is a linear representation of a syntax tree.
o In the postfix notation, any expression can be written unambiguously without
parentheses.
o The ordinary (infix) way of writing the sum of x and y is with operator in the middle: x +
y. But in the postfix notation, we place the operator at the right end as xy+.
o In postfix notation, the operator follows the operand.
When you create a parse tree then it contains more details than actually needed. So, it is very
difficult to compiler to parse the parse tree. Take the following parse tree as an example:
o In the parse tree, most of the leaf nodes are single child to their parent nodes.
o In the syntax tree, we can eliminate this extra information.
o Syntax tree is a variant of parse tree. In the syntax tree, interior nodes are operators and
leaves are operands.
o Syntax tree is usually used when represent a program in a tree structure.
Abstract syntax trees are important data structures in a compiler. It contains the least unnecessary
information.
Abstract syntax trees are more compact than a parse tree and can be easily used by a
compiler.
UNIT-3 (Lecture-3)
Example
Given Expression:
a := (-c * b) + (-c * d)
t1 := -c
t2 := b*t1
t3 := -c
t4 := d * t3
t5 := t2 + t4
a := t5
The three address code can be represented in two forms: quadruples and triples.
Quadruples
The quadruples have four fields to implement the three address code. The field of quadruples
contains the name of the operator, the first source operand, the second source operand and the
result respectively.
Example
a := -b * (c + d)
t1 := -b
t2 := c + d
t3 := t1 * t2
a := t3
(0) uminus b - t1
(1) + c d t2
(2) * t1 t2 t3
(3) := t3 - a
Triples
The triples have three fields to implement the three address code. The field of triples contains the
name of the operator, the first source operand and the second source operand.
In triples, the results of respective sub-expressions are denoted by the position of expression.
Triple is equivalent to DAG while representing expressions.
Example:
a := -b * (c + d)
t1 := -b
t2 := c + d
t3 := t1 * t2
a := t3
These statements are represented by triples as follows:
(0) uminus b -
(1) + c d
(3) := (2) -
UNIT-3 (Lecture-4)
Assignment Statements
In the syntax directed translation, assignment statement is mainly deals with expressions.
The expression can be of type real, integer, array and records.
S → id :=E {p = look_up(id.name);
If p ≠ nil then
Emit (p = E.place)
Else
Error;
}
E → E1 + E2 {E.place = newtemp();
Emit (E.place = E1.place '+' E2.place)
}
E → E1 * E2 {E.place = newtemp();
Emit (E.place = E1.place '*' E2.place)
}
E → id {p = look_up(id.name);
If p ≠ nil then
Emit (p = E.place)
Else
Error;
}
Boolean Expressions
Boolean expressions have two primary purposes. They are used for computing the logical
values. They are also used as conditional expression using if-then-else or while-do.
Consider the grammar
E → E OR E
E → E AND E
E → NOT E
E → (E)
E → TRUE
E → FALSE
The AND and OR are left associated. NOT has the higher precedence then AND and lastly
OR.
E → E1 OR E2 {E.place = newtemp();
Emit (E.place ':=' E1.place 'OR' E2.place)
}
E → E1 + E2 {E.place = newtemp();
Emit (E.place ':=' E1.place 'AND' E2.place)
}
The EMIT function is used to generate the three address code and the newtemp( ) function
is used to generate the temporary variables.
Here is the example which generates the three address code using the above translation
scheme:
p>q AND r<s OR u>v
100: if p>q goto 103
101: t1:=0
102: goto 104
103: t1:=1
104: if r<s goto 107
105: t2:=0
106: goto 108
107: t2:=1
108: if u>v goto 111
109: t3:=0
110: goto 112
111: t3:= 1
112: t4:= t1 AND t2
113: t5:= t4 OR t3
UNIT-3 (Lecture-5)
E->T { E.val=T.val } {}
T->F { T.val=F.val } {}
UNIT-3 (Lecture-6)
1-D Array
Pictorial Representation:
2-D Array
Pictorial Representation:
UNIT-3 (Lecture-7)
Example:-
void main()
{
int x=5, y=6;
swap(x,y);
}
void swap( int x, int y)
{
t1= x;
x=y;
y=t1;
}
1 call main
2 x=5
3 y=6
4 param x
5 param y
6 call swap, 2
7 t1= x;
8 x=y;
9 y=t1;
10 stop
UNIT-3 (Lecture-8)
Case Statements
Example:-
switch(ch)
{
case 1: z=x+y; break;
case 2: z=x-y; break;
default: z=x*y;
}
1 if ch==1 goto 5
2 if ch==2 goto 7
3 z= x*y
4 goto 9
5 z= x+y
6 goto 9
7 z= x-y
8 goto 9
9 stop