Lec05 Syntaxdirected
Lec05 Syntaxdirected
Lec05 Syntaxdirected
E.val=17 return
E.val=5 + T.val=12
digit.lexval=5 digit.lexval=3
E.val=17
E.val=5 T.val=12
digit.lexval=5 digit.lexval=3
D L.in=real
id id.entry=p
stack parallel-stack
top Z Z.z
Y Y.y
X X.x top
A A.a
. . . .
CS416 Compiler Design 14
Bottom-Up Eval. of S-Attributed Definitions (cont.)
Production Semantic Rules
L → E return print(val[top-1])
E → E1 + T val[ntop] = val[top-2] + val[top]
E→T
T → T1 * F val[ntop] = val[top-2] * val[top]
T→F
F→(E) val[ntop] = val[top-1]
F → digit
• At each shift of digit, we also push digit.lexval into val-stack.
• At all other shifts, we do not put anything into val-stack because
other terminals do not have attributes (but we increment the
stack pointer for val-stack).
CS416 Compiler Design 15
Canonical LR(0) Collection for The Grammar
.. L . . .
I0: L’→
.
L I1: L’→L I7: L →Er I11: E →E+T *
.. .. .
r 9
L→ Er T T →T *F
E→
E→
..
E+T E
T
I2: L →E r
E →E +T
+ I8: E →E+ T
T → T*F .. (
F 4
.. ..
5
T→ T*F T→ F d
..
T→ F T I3: E →T F → (E) 6
F→ (E) T →T *F F→ d
F→ d
. *
. .
F
I4: T →F
(
I5: F →
E→ .. .
( E)
E+T
I9: T →T* F
F → (E)
F→ d
.. F
(
I12: T →T*F
5
..
E→ T E d
..
6
.
T→ T*F
T→
F→
F→
.. F
(E)
d
T
F
3
I10: F →(E )
E →E +T
)
+
I13: F →(E)
.
4 8
(
d 5
I6: F →d d
6
procedure A() {
call B(); A→B
}
procedure B() {
if (currtoken=0) { consume 0; call B(); } B→0B
else if (currtoken=1) { consume 1; call B(); } B→1B
else if (currtoken=$) {} // $ is end-marker B→
else error(“unexpected token”);
}
Semantic Actions
CS416 Compiler Design 24
Translation Schemes
• When designing a translation scheme, some restrictions should be
observed to ensure that an attribute value is available when a semantic
action refers to that attribute.
• These restrictions (motivated by L-attributed definitions) ensure that
a semantic action does not refer to an attribute that has not yet
computed.
• In translation schemes, we use semantic action terminology instead of
semantic rule terminology used in syntax-directed definitions.
• The position of the semantic action on the right side indicates when that
semantic action will be evaluated.
E → E1 + T { E.val = E1.val + T.val } the production of the corresponding
translation scheme
E→TR
R → + T { print(“+”) } R1
R→
T → id { print(id.name) }
a+b+c ab+c+
T R
id {print(“a”)} + T {print(“+”)} R
id {print(“b”)} + T {print(“+”)} R
id {print(“c”)}
The depth first traversal of the parse tree (executing the semantic actions in that order)
will produce the postfix representation of the infix expression.
CS416 Compiler Design 28
Inherited Attributes in Translation Schemes
• If a translation scheme has to contain both synthesized and inherited
attributes, we have to observe the following rules:
1. An inherited attribute of a symbol on the right side of a production
must be computed in a semantic action before that symbol.
2. A semantic action must not refer to a synthesized attribute of a
symbol to the right of that semantic action.
3. A synthesized attribute for the non-terminal on the left can only be
computed after all attributes it references have been computed (we
normally put this semantic action at the end of the right side of the
production).
• With a L-attributed syntax-directed definition, it is always possible
to construct a corresponding translation scheme which satisfies
these three conditions (This may not be possible for a general
syntax-directed translation).
CS416 Compiler Design 29
Top-Down Translation
• We will look at the implementation of L-attributed definitions during
predictive parsing.
• Instead of the syntax-directed translations, we will work with
translation schemes.
• We will see how to evaluate inherited attributes (in L-attributed
definitions) during recursive predictive parsing.
• We will also look at what happens to attributes during the left-recursion
elimination in the left-recursive grammars.
• When we eliminate the left recursion from the grammar (to get a suitable
grammar for the top-down parsing) we also have to change semantic
actions
CS416 Compiler Design 33
Eliminating Left Recursion (cont.)
inherited attribute synthesized attribute
E → T { A.in=T.val } A { E.val=A.syn }
A → + T { A1.in=A.in+T.val } A1 { A.syn = A1.syn}
A → - T { A1.in=A.in-T.val } A1 { A.syn = A1.syn}
A → { A.syn = A.in }
T → F { B.in=F.val } B { T.val=B.syn }
B → * F { B1.in=B.in*F.val } B1 { B.syn = B1.syn}
B→ { B.syn = B.in }
F → ( E ) { F.val = E.val }
F → digit { F.val = digit.lexval }
CS416 Compiler Design 34
Eliminating Left Recursion (in general)
A → A1 Y { A.a = g(A1.a,Y.y) } a left recursive grammar with
A → X { A.a=f(X.x) } synthesized attributes (a,y,x).
A → X { R.in=f(X.x) } R { A.a=R.syn }
R → Y { R1.in=g(R.in,Y.y) } R1 { R.syn = R1.syn}
R→ { R.syn = R.in }
CS416 Compiler Design 35
Evaluating attributes
A parse tree of left recursive grammar
A Y A.a=g(f(X.x),Y.y)
parse tree of non-left-recursive grammar
X X.x=f(X.x) A
X R.in=f(X.x) R A.a=g(f(X.x,Y.y)
Y R1.in=g(f(X.x),Y.y) R1 R.syn=g(f(X.x),Y.y)
R1.syn=g(f(X.x),Y.y)
S M1 A { s[ntop]=k(s[top-1],s[top]) }
M 1 { s[ntop]=1 }
A M2 B M 3 C { s[ntop]=h(s[top-4],s[top-3],s[top-2],s[top-1],s[top]) }
M 2 { s[ntop]=f(s[top]) }
M 3 { s[ntop]=g(s[top-2],s[top-1],s[top])}
Bb { s[ntop]=m(s[top-1],s[top]) }
Cc { s[ntop]=n(s[top-1],s[top]) }
B.i=f(1) C.i=g(1,f(1),m(..))
B C
B.s=m(f(1),b.s) C.s=n(g(..),c.s)
b c
S M1 L
L M2 L1 1 But since L will be reduced first by the bottom-up
L { print(s[top]) } parser, the translator cannot know the number of 1s.
M1 { s[ntop]=0 }
M2 { s[ntop]=s[top]+1 }
LLb LMLb
La La NOT LR-grammar
M
.L, $
S’
L . M L b, $
L . a, $
M .,a shift/reduce conflict