Compiler Design
Compiler Design
if-then-else
B s1 s2
1
Abstract Syntax tree …
• Chain of single productions may be collapsed, and
operators move to the parent nodes
E +
E + T * id3
T F id1 id2
T * F id3
F id2
id1 2
Constructing Abstract Syntax Tree
for expression
• Each node can be represented as a
record
• operators: one field for operator,
remaining fields ptrs to operands
mknode(op,left,right )
• identifier: one field with label id and
another ptr to symbol table
mkleaf(id,entry)
• number: one field with label num and
another to keep the value of the number
mkleaf(num,val)
3
Example
the following
sequence of function
calls creates a parse P5
tree for a- 4 + c
+
P3 P4
P1 = mkleaf(id, entry.a)
- id
P2 = mkleaf(num, 4) P1
P2 entry of c
P3 = mknode(-, P1, P2)
id num 4
P4 = mkleaf(id, entry.c)
P5 = mknode(+, P3, P4) entry of a
4
A syntax directed definition for
constructing syntax tree
E → E1 + T E.ptr = mknode(+, E1.ptr, T.ptr)
E →T E.ptr = T.ptr
T → T1 * F T.ptr := mknode(*, T1.ptr, F.ptr)
T →F T.ptr := F.ptr
F → (E) F.ptr := E.ptr
F → id F.ptr := mkleaf(id, entry.id)
F → num F.ptr := mkleaf(num,val)
5
DAG for Expressions
Expression a + a * ( b – c ) + ( b - c ) * d
make a leaf or node if not present,
otherwise return pointer to the existing node
P1 = makeleaf(id,a) +
P13
P2 = makeleaf(id,a)
P7
P3 = makeleaf(id,b)
P4 = makeleaf(id,c) +
P5 = makenode(-,P3,P4)
P6 = makenode(*,P2,P5) P6 P12
P7 = makenode(+,P1,P6) * *
P8 = makeleaf(id,b) P1 P2
P5 P10 P11
P9 = makeleaf(id,c)
P10 = makenode(-,P8,P9) a - d
P11 = makeleaf(id,d) P3 P8
P4 P9
P12 = makenode(*,P10,P11)
b c
P13 = makenode(+,P7,P12)
6
Bottom-up evaluation of S-attributed
definitions
• Can be evaluated while parsing
• Whenever reduction is made, value of
new synthesized attribute is computed
from the attributes on the stack
• Extend stack to hold the values also
• The current top of stack is indicated by
top pointer
state value
top stack stack
7
Bottom-up evaluation of S-attributed
definitions
• Suppose semantic rule
A.a = f(X.x, Y.y, Z.z)
is associated with production
A → XYZ
• Before reducing XYZ to A, value of Z is in
val(top), value of Y is in val(top-1) and
value of X is in val(top-2)
• If symbol has no attribute then the
entry is undefined
• After the reduction, top is decremented
by 2 and state covering A is put in
val(top) 8
Example: desk calculator
LE$ Print (E.val)
EE+T E.val = E.val + T.val
ET E.val = T.val
TT*F T.val = T.val * F.val
TF T.val = F.val
F (E) F.val = E.val
F digit F.val = digit.lexval
10
Example: desk calculator
L → E$ print(val(top))
E→E+T val(ntop) = val(top-2) + val(top)
E→T
T→T*F val(ntop) = val(top-2) * val(top)
T→F
F → (E) val(ntop) = val(top-1)
F → digit
In YACC
E→E+T $$ = $1 + $3
$$ maps to val[top – r + 1]
$k maps to val[top – r + k]
r=#symbols on RHS ( here 3)
$$ = $1 is the default action in YACC
L-attributed definitions
• When translation takes place during
parsing, order of evaluation is linked to
the order in which nodes are created
• In S-attributed definitions parent’s
attribute evaluated after child’s.
• A natural order in both top-down and
bottom-up parsing is depth first-order
• L-attributed definition: where attributes
can be evaluated in depth-first order
14
L attributed definitions …
• A syntax directed definition is L-
attributed if each inherited attribute of
Xj (1 ≤ j ≤ n) at the right hand side of
A→X1 X2…Xn depends only on
– Attributes of symbols X1 X2…Xj-1 and
– Inherited attribute of A
• Examples (i inherited, s synthesized)
A → LM L.i = f1(A.i) A → QR R.i = f4(A.i)
M.i = f2(L.s) Q.i = f5(R.s)
A.s = f3(M.s) A.s = f6(Q.s)
15
Translation schemes
• A CFG where semantic actions occur
within the rhs of production
T R
num print(num) Є
(2)
17
Evaluation of Translation Schemes
• Assume actions are terminal symbols
• Perform depth first order traversal to
obtain 9 5 – 2 +
18
• An inherited attribute for a symbol on RHS
of a production must be computed in an
action before that symbol S
S → A1 A2 {A1.in = 1,A2.in = 2}
A → a {print(A.in)} A1 A2 A1.in=1
A2.in=2
a print(A1.in) a print(A2.in)
27
ETR
R + T {print (+)} R
R - T {print (-)} R
RЄ
T num {print(num.val)}
transforms to
E→TR
R→+TMR
R→-TNR
R→Є
T → num {print(num.val)}
M→Є {print(+)}
N→Є {print(-)}
28
Inheriting attribute on parser stacks
• bottom up parser reduces rhs of A →
XY by removing XY from stack and
putting A on the stack
• synthesized attributes of Xs can be
inherited by Y by using the copy rule
Y.i=X.s
29
Inherited Attributes: SDD
DTL L.in = T.type
T real T.type = real
T int T.type = int
L L1, id L1.in = L.in;
addtype(id.entry, L.in)
L id addtype (id.entry,L.in)
Exercise: Convert to Translation Scheme
30
Inherited Attributes: Translation
Scheme
D T {L.in = T.type} L
T int {T.type = integer}
T real {T.type = real}
L → {L1.in =L.in} L1,id {addtype(id.entry,Lin)}
L → id {addtype(id.entry,Lin)}
Example: take string real p,q,r
31
State stack INPUT PRODUCTION
real p,q,r
real p,q,r
T p,q,r T → real
Tp ,q,r
TL ,q,r L → id
TL, q,r
TL,q ,r
TL ,r L → L,id
TL, r
TL,r -
TL - L → L,id
D - D →TL
Every time a string is reduced to L, T.val is
just below it on the stack 32
Example …
• Every time a reduction to L is made value of T
type is just below it
• Use the fact that T.val (type information) is at a
known place in the stack
• When production L id is applied, id.entry is at
the top of the stack and T.type is just below it,
therefore,
addtype(id.entry,L.in)
addtype(val[top], val[top-1])
• Similarly when production L L1 , id is applied
id.entry is at the top of the stack and T.type is
three places below it, therefore,
addtype(id.entry, L.in)
addtype(val[top],val[top-3])
33
Example …
Therefore, the translation scheme becomes
DTL
T int val[top] =integer
T real val[top] =real
34
Simulating the evaluation of
inherited attributes
• The scheme works only if grammar allows
position of attribute to be predicted.
• Consider the grammar
S aAC Ci = As
S bABC Ci = As
Cc Cs = g(Ci)
• C inherits As
• there may or may not be a B between A
and C on the stack when reduction by rule
Cc takes place
• When reduction by C c is performed the
value of Ci is either in [top-1] or [top-2]
35
Simulating the evaluation …
• Insert a marker M just before C in the
second rule and change rules to
S aAC Ci = As
S bABMC Mi = As; Ci = Ms
Cc Cs = g(Ci)
Mε Ms = Mi
• When production M ε is applied we have
Ms = Mi = As
• Therefore value of Ci is always at val[top-1]
36
Simulating the evaluation …
• Markers can also be used to simulate
rules that are not copy rules
S aAC Ci = f(A.s)
• using a marker
38
Algorithm …
• If the reduction is to a marker Mj and
the marker belongs to a production
A M1 X1… MnXn then
Ai is in position top-2j+2
X1.i is in position top-2j+3
X1.s is in position top-2j+4
• If reduction is to a non terminal A by
production A M1 X1… MnXn
then compute As and push on the
stack
39
Space for attributes at compile
time
• Lifetime of an attribute begins when it is first
computed
40
Example
• Consider following definition
D T L L.in := T.type
T real T.type := real
T int T.type := int
L L1,I L1.in :=L.in; I.in=L.in
LI I.in = L.in
I I1[num] I1.in=array(numeral, I.in)
I id addtype(id.entry,I.in)
41
Consider string int x[3], y[5]
its parse tree and dependence graph
D
T1 2 L
int 6 L , 3I
7 I 5I [ num ]
4 5
I [ num ] id
9 83 y
id
x 42
Resource requirement
1 2 3 4 5 6 7 8 9
R1 R1 R2 R3 R2 R1 R1 R2 R1
44
Example
• Consider rule B B1 B2 with inherited attribute ps and
synthesized attribute ht
• The parse tree for this string and a snapshot of the stack at
each node appears as
B.ps B B.ht
B.ps
B2.ht
B2.ps
B1.ht
B1.ps
B1.ps B1.ht B2.ps B.ps
B.ps B1.ps B1.ht
B1 B.ps B1.ps B2
B.ps
45
Example …
• However, if different stacks are maintained for the
inherited and synthesized attributes, the stacks will
normally be smaller
B2.ht
B.ps B1.ht
B.ps
B1 B.ps B1.ht B.ps B1.ht B2
46