Unit 4 Syntax-Directed Translation & Intermediate Code Generation
Unit 4 Syntax-Directed Translation & Intermediate Code Generation
Unit-4
• Dependency Graphs
• S-attributed Definitions
• L-attributed Definitions
• Synthesized attributes
– A synthesized attribute at node N is defined only in
terms of attribute values of children of N and at N it
• Inherited attributes
– An inherited attribute at node N is defined only in
terms of attribute values at N’s parent, N itself and N’s
siblings
Example of S-attributed SDD
• Dependency graph
– For each parse tree node, the parse tree has a node
for each attribute associated with that node
– If a semantic rule defines the value of synthesized
attribute A.b in terms of the value of X.c then the
dependency graph has an edge from X.c to A.b
– If a semantic rule defines the value of inherited
attribute B.c in terms of the value of X.a then the
dependency graph has an edge from X.c to B.c
Example of Dependency graph
• Synthesized attributes are represented by .val.
• Hence, E.val, E1.val, and E2.val have synthesized
attributes.
• Dependencies are shown by solid arrows.
• Arrows from E1 and E2 show that the value of E
depends upon E1 and E2.
Ordering the evaluation of
attributes
• If dependency graph has an edge from M to N then M
must be evaluated before the attribute of N
• Thus the only allowable orders of evaluation are those
sequence of nodes N1,N2,…,Nk such that if there is an
edge from Ni to Nj then i<j
• Such an ordering is called a topological sort of a graph
S-Attributed definitions
• An SDD is S-attributed if every attribute is synthesized
• We can have a post-order traversal of parse-tree to evaluate
attributes in S-attributed definitions
postorder(N) {
for (each child C of N, from the left) postorder(C);
evaluate the attributes associated with node N;
}
• S-Attributed definitions can be implemented during bottom-up
parsing without the need to explicitly create parse trees
L-Attributed definitions
• A SDD is L-Attributed if the edges in dependency graph
goes from Left to Right but not from Right to Left.
• More precisely, each attribute must be either
– Synthesized
– Inherited, but if there us a production A->X1X2…Xn and
there is an inherited attribute Xi.a computed by a rule
associated with this production, then the rule may only use:
1) L -> E n {print(E.val);}
2) E -> E1 + T {E.val=E1.val+T.val;}
3) E -> T {E.val = T.val;}
4) T -> T1 * F {T.val=T1.val*F.val;}
5) T -> F {T.val=F.val;}
6) F -> (E) {F.val=E.val;}
7) F -> digit {F.val=digit.lexval;}
Parse-Stack implementation of
postfix SDT’s
• In a shift-reduce parser we can easily implement
semantic action using the parser stack
• For each nonterminal (or state) on the stack we can
associate a record holding its attributes
• Then in a reduction step we can execute the semantic
action at the end of a production to evaluate the
attribute(s) of the non-terminal at the leftside of the
production
• And put the value on the stack in replace of the rightside
of production
Example
L -> E n {print(stack[top-1].val);
top=top-1;}
E -> E1 + T {stack[top-2].val=stack[top-2].val+stack.val;
top=top-2;}
E -> T
T -> T1 * F {stack[top-2].val=stack[top-2].val+stack.val;
top=top-2;}
T -> F
F -> (E) {stack[top-2].val=stack[top-1].val
top=top-2;}
F -> digit
SDT’s with actions inside
productions
• For a production B->X {a} Y
– If the parse is bottom-up then we perform action “a” as soon as
this occurrence of X appears on the top of the parser stack
– If the parser is top down we perform “a” just before we expand Y
• Sometimes we cant do things as easily as explained above
• One example is when we are parsing this SDT with a bottom-up
parser
1) L -> E n
2) E -> {print(‘+’);} E1 + T
3) E -> T
4) T -> {print(‘*’);} T1 * F
5) T -> F
6) F -> (E)
7) F -> digit {print(digit.lexval);}
SDT’s with actions inside
productions (cont)
L
• Any SDT can be implemented as
follows
1. Ignore the actions and E
produce a parse tree
2. Examine each interior node {print(‘+’);}
N and add actions as new E + T
children at the correct
position T F
3. Perform a postorder traversal {print(4);}
and execute actions when {print(‘*’);}
T *F digit
their nodes are visited
{print(5);}
F digit
{print(3);}
digit
SDT’s for L-Attributed definitions
• We can convert an L-attributed SDD into an SDT using
following two rules:
– Embed the action that computes the inherited
attributes for a nonterminal A immediately before that
occurrence of A. if several inherited attributes of A are
dpendent on one another in an acyclic fashion, order
them so that those needed first are computed first
– Place the action of a synthesized attribute for the
head of a production at the end of the body of the
production
Example
S -> while (C) S1 L1=new();
L2=new();
S1.next=L1;
C.false=S.next;
C.true=L2;
S.code=label||L1||C.code||label||L2||S1.code
ab – cd + *ab -+
Three-Address Code
• A statement involving no more than three references(two
for operands and one for result) is known as a three
address statement. A sequence of three address
statements is known as a three address code. Three
address statement is of form x = y op z, where x, y, and z
will have address (memory location). Sometimes a
statement might contain less than three references but it
is still called a three address statement.
• For Example: a=b+c*d;
• The Intermediate code generator will try to devide this
expression into subexpressions and then generate the
corresponding code.
r1 = c*d;
r2 = b+r1;
a = r2
Variants of syntax trees
+ *
*
d
a -
b c
SDD for creating DAG’s
Production Semantic Rules
1) E -> E1+T E.node= new Node(‘+’, E1.node,T.node)
2) E -> E1-T E.node= new Node(‘-’, E1.node,T.node)
3) E -> T E.node = T.node
4) T -> (E) T.node = E.node
5) T -> id T.node = new Leaf(id, id.entry)
6) T -> num T.node = new Leaf(num, num.val)
Example: 8) p8=Leaf(id,entry-b)=p3
1) p1=Leaf(id, entry-a) 9) p9=Leaf(id,entry-c)=p4
2) P2=Leaf(id, entry-a)=p1 10) p10=Node(‘-’,p3,p4)=p5
3) p3=Leaf(id, entry-b) 11) p11=Leaf(id,entry-d)
4) p4=Leaf(id, entry-c) 12) p12=Node(‘*’,p5,p11)
5) p5=Node(‘-’,p3,p4) 13) p13=Node(‘+’,p7,p12)
6) p6=Node(‘*’,p1,p5)
7) p7=Node(‘+’,p1,p6)
Value-number method for
constructing DAG’s
= id To entry for i
num 10
+ + 1 2
3 1 3
i 10
• Algorithm
– Search the array for a node M with label op, left child l and right
child r
– If there is such a node, return the value number M
– If not create in the array a new node N with label op, left child l,
and right child r and return its value
• We may use a hash table
Three address code
+
t1 = b – c
+ * t2 = a * t1
t3 = a + t2
* t4 = t1 * d
d
t5 = t3 + t4
a -
b c
Forms of three address
instructions
• x = y op z
• x = op y
• x=y
• goto L
• if x goto L and ifFalse x goto L
• if x relop y goto L
• Procedure calls using:
– param x
– call p,n
– y = call p,n
• x = y[i] and x[i] = y
• x = &y and x = *y and *x =y
Example
L: t1 = i + 1 100: t1 = i + 1
i = t1 101: i = t1
t2 = i * 8 102: t2 = i * 8
t3 = a[t2] 103: t3 = a[t2]
if t3 < v goto L 104: if t3 < v goto 100
⚫
Flow-of-Control Statements
Syntax-directed definition
Generating three-address code for
booleans
Translation of a simple
if-statement