0% found this document useful (0 votes)
53 views54 pages

Semantic Analyzer: - The Result Is A Syntax-Directed Translation, - Attribute Grammars

The document discusses semantic analysis which checks for semantic errors and collects type information. It covers type checking, attribute grammars, syntax-directed translation, attributes, and syntax-directed definitions which associate semantic rules with productions to perform actions like code generation.

Uploaded by

Aaradhya Mahajan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
53 views54 pages

Semantic Analyzer: - The Result Is A Syntax-Directed Translation, - Attribute Grammars

The document discusses semantic analysis which checks for semantic errors and collects type information. It covers type checking, attribute grammars, syntax-directed translation, attributes, and syntax-directed definitions which associate semantic rules with productions to perform actions like code generation.

Uploaded by

Aaradhya Mahajan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 54

Semantic Analyzer

• A semantic analyzer checks the source program for semantic errors and
collects the type information for the code generation.
• Type-checking is an important part of semantic analyzer.
• Normally semantic information cannot be represented by a context-free
language used in syntax analyzers.
• Context-free grammars used in the syntax analysis are integrated with
attributes (semantic rules)
– the result is a syntax-directed translation,
– Attribute grammars
• Ex:
newval := oldval + 12

• The type of the identifier newval must match with type of the expression (oldval+12)

UCS802 Compiler Construction 1


Syntax-Directed Translation
• Grammar symbols are associated with attributes to associate
information with the programming language constructs that they
represent.
• Values of these attributes are evaluated by the semantic rules
associated with the production rules.
• Evaluation of these semantic rules:
– may generate intermediate codes
– may put information into the symbol table
– may perform type checking
– may issue error messages
– may perform some other activities
– in fact, they may perform almost any activities.

UCS802 Compiler Construction 2


Attributes
• Attribute values may represent
– Numbers (literal constants)
– Strings (literal constants)
– Memory locations, such as a frame index of a local variable or function argument
– A data type for type checking of expressions
– Scoping information for local declarations
– Intermediate program representations
• Synthesized Attributes
– A synthesized attribute for a nonterminal A at a parse tree node N is defined by a semantic
rule associated with a production at N.
– A synthesized attribute at node N is defined only in terms of attribute values at the children
of N and N itself
• Inherited Attributes
– An inherited attribute for a nonterminal B at a parse tree node N is defined by a semantic
rule associated with a production at the parent node of N.
– An inherited attribute at node N is defined only in terms of attribute values at the N’s
Parent, N itself and N’s siblings 3
Syntax-Directed Definitions and Translation Schemes
• When we associate semantic rules with productions, we use two
notations:
– Syntax-Directed Definitions
– Translation Schemes
• Syntax-Directed Definitions:
– give high-level specifications for translations
– hide many implementation details such as order of evaluation of semantic actions.
– We associate a production rule with a set of semantic actions, and we do not say when they
will be evaluated.
• Translation Schemes:
– indicate the order of evaluation of semantic actions associated with a production rule.
– In other words, translation schemes give a little bit information about implementation
details.

UCS802 Compiler Construction 4


Syntax-Directed Definitions
• A syntax-directed definition is a generalization of a context-free
grammar in which:
– Each grammar symbol is associated with a set of attributes.
– This set of attributes for a grammar symbol is partitioned into two subsets called
synthesized and inherited attributes of that grammar symbol.
– Each production rule is associated with a set of semantic rules.
• Semantic rules set up dependencies between attributes which can be
represented by a dependency graph.
• This dependency graph determines the evaluation order of these
semantic rules.
• Evaluation of a semantic rule defines the value of an attribute. But a
semantic rule may also have some side effects such as printing a value.

UCS802 Compiler Construction 5


Annotated Parse Tree
• A parse tree showing the values of attributes at each node is called
an annotated parse tree.
• The process of computing the attributes values at the nodes is called
annotating (or decorating) of the parse tree.
• Of course, the order of these computations depends on the
dependency graph induced by the semantic rules.

UCS802 Compiler Construction 6


Syntax-Directed Definition
• In a syntax-directed definition, each production A→α is associated
with a set of semantic rules of the form:
b=f(c1,c2,…,cn) where f is a function,
and b can be one of the followings:
è b is a synthesized attribute of A and c1,c2,…,cn are attributes of the
grammar symbols in the production ( A→α ).
OR
è b is an inherited attribute one of the grammar symbols in α (on the
right side of the production), and c1,c2,…,cn are attributes of the
grammar symbols in the production ( A→α ).

UCS802 Compiler Construction 7


Attribute Grammar
• So, a semantic rule b=f(c1,c2,…,cn) indicates that the attribute b
depends on attributes c1,c2,…,cn.
• In a syntax-directed definition, a semantic rule may just evaluate
a value of an attribute or it may have some side effects such as
printing values.

• An attribute grammar is a syntax-directed definition in which the


functions in the semantic rules cannot have side effects (they can
only evaluate values of attributes).

UCS802 Compiler Construction 8


Syntax-Directed Definition -- Example
Production Semantic Rules
L → E return print(E.val)
E → E1 + T E.val = E1.val + T.val
E→T E.val = T.val
T → T1 * F T.val = T1.val * F.val
T→F T.val = F.val
F→(E) F.val = E.val
F → digit F.val = digit.lexval

• Symbols E, T, and F are associated with a synthesized attribute val.


• The token digit has a synthesized attribute lexval (it is assumed that it is
evaluated by the lexical analyzer).

UCS802 Compiler Construction 9


Annotated Parse Tree -- Example
Input: 5+3*4 L

E.val=17 return

E.val=5 + T.val=12

T.val=5 T.val=3 * F.val=4

F.val=5 F.val=3 digit.lexval=4

digit.lexval=5 digit.lexval=3

UCS802 Compiler Construction 10


Annotating a Parse Tree With Depth-First
Traversals

procedure visit(n : node);


begin
for each child m of n, from left to right do
visit(m);
evaluate semantic rules at node n
end

UCS802 Compiler Construction 11


Dependency Graph
• Dependency Graph predicts the
flow of information among the
attribute instances in a particular Input: 5+3*4
parse tree; L
• An edge from one attribute instance
to another means that the value of E.val=17
the first is needed to compute the
second.
E.val=5 T.val=12

T.val=5 T.val=3 F.val=4

F.val=5 F.val=3 digit.lexval=4

digit.lexval=5 digit.lexval=3
UCS802 Compiler Construction 12
A Dependency Graph
• If an attribute b at a node in a parse tree depends on an attribute c, then
the semantic rule for b at that node must be evaluated after the semantic
rule that defines c.
• The interdependencies among the inherited and synthesized attributes at
the node in the parse tree can be depicted with by a graph, called
dependency graph

UCS802 Compiler Construction 13


Syntax-Directed Definition – Example2
Production Semantic Rules
E → E1 E.loc=newtemp(), E.code=E1.code
E → E1 + T E.loc=newtemp(), E.code = E1.code || T.code || add E1.loc,T.loc,E.loc
E→T E.loc = T.loc, E.code=T.code
T → T1 * F T.loc=newtemp(), T.code = T1.code || F.code || mult T1.loc,F.loc,T.loc
T→F T.loc = F.loc, T.code=F.code
F→(E) F.loc = E.loc, F.code=E.code
F → id F.loc = id.name, F.code=“”

• Symbols E, T, and F are associated with synthesized attributes loc and


code.
• The token id has a synthesized attribute name (it is assumed that it is
evaluated by the lexical analyzer).
• It is assumed that || is the string concatenation operator.
Translation Scheme UCS802 Compiler Construction 14
a:=b + c * d
S.code=‘t1:=c*d t3=b+t1 a=t3’
S
E.loc=‘t3’
E.code=‘t1:=c*d t3=b+t1’

id.loc=‘a’ id := E
E.loc=‘t1’
E.loc=‘b’
E.code=‘ ‘ E + E E.code=‘t1:=c*d ‘

E.loc=‘d’

id.loc=‘b’ id E * E E.code=‘ ‘

E.loc=‘c’
E.code=‘ ‘

id.loc=‘c’ id id id.loc=‘d’

E → E1 + T E.loc=newtemp(), E.code = E1.code || T.code || add E1.loc,T.loc,E.loc


E→T E.loc = T.loc, E.code=T.code
T → T1 * F T.loc=newtemp(), T.code = T1.code || F.code || mult T1.loc,F.loc,T.loc
T→F T.loc = F.loc, T.code=F.code
F→(E) F.loc = E.loc, F.code=E.code
F → id F.loc = id.name, F.code=“”
UCS802 Compiler Construction 15
Syntax-Directed Definition – Inherited Attributes

Production Semantic Rules


D→TL L.in = T.type
T → int T.type = integer
T → real T.type = real
L → L1 , id L1.in = L.in, addtype(id.entry,L.in)
L → id addtype(id.entry,L.in)

• Symbol T is associated with a synthesized attribute type.


• Symbol L is associated with an inherited attribute in.

UCS802 Compiler Construction 16


A Dependency Graph – Inherited Attributes
Input: real p q

D T.type=real L.in=real

T L L1.in=real addtype(q,real)

real L id addtype(p,real) id.entry=q

id id.entry=p

parse tree dependency graph

UCS802 Compiler Construction 17


S-Attributed Definitions
• Syntax-directed definitions are used to specify syntax-directed translations.
• To create a translator for an arbitrary syntax-directed definition can be difficult.
• We would like to evaluate the semantic rules during parsing (i.e. in a single pass, we
will parse and we will also evaluate semantic rules during the parsing).
• We will look at two sub-classes of the syntax-directed definitions:
– S-Attributed Definitions: only synthesized attributes used in the syntax-directed
definitions.
– L-Attributed Definitions: in addition to synthesized attributes, we may also use inherited
attributes in a restricted fashion.
• To implement S-Attributed Definitions and L-Attributed Definitions are easy (we can
evaluate semantic rules in a single pass during the parsing).
• Implementations of S-attributed Definitions are a little bit easier than implementations
of L-Attributed Definitions

UCS802 Compiler Construction 18


Bottom-Up Evaluation of S-Attributed Definitions
• We put the values of the synthesized attributes of the grammar symbols into a parallel
stack.
– When an entry of the parser stack holds a grammar symbol X (terminal or non-terminal),
the corresponding entry in the parallel stack will hold the synthesized attribute(s) of the
symbol X.
• We evaluate the values of the attributes during reductions.

A ® XYZ A.a=f(X.x,Y.y,Z.z) where all attributes are synthesized.

stack parallel-stack
top ® Z Z.z
Y Y.y
X X.x è top ® A A.a
. . . .
UCS802 Compiler Construction 19
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).

UCS802 Compiler Construction 20


Canonical LR(0) Collection for The Grammar
.. L I1: L’→L . . .
.
I0: L’→ L I7: L →Er I11: E →E+T * 9

.. .. .
r T
L→ Er T →T *F
E
..
E→ E+T I2: L →E r + I8: E →E+ T F 4

..
E→ T E →E +T T → T*F (
5
T→
T→
F→..
T*F
F
(E)
T I3: E →T ..
T →T *F
T→ F
F → (E)
F→ d
.. d
6

F→ d
F I4: T →F . *

.
. I9: T →T* F
..
F
I12: T →T*F .
..
( I5: F → ( E) F → (E)
(
E→ E+T E F→ d 5

..
E→ T d
6
T→
T→
F→..
T*F
F
(E)
T
3
I10: F →(E )
E →E +T
.. +
) I13: F →(E) .
F
F→ d 4 8

. (
d 5
I6: F →d d
6

UCS802 Compiler Construction 21


Bottom-Up Evaluation -- Example
• At each shift of digit, we also push digit.lexval into val-stack.
stack val-stack input action semantic rule
0 5+3*4r s6 d.lexval(5) into val-stack
0id6 5 +3*4r F→id F.val=id.lexval – do nothing
0F4 5 +3*4r T→F T.val=F.val – do nothing
0T3 5 +3*4r E→T E.val=T.val – do nothing
0E2 5 +3*4r s8 push empty slot into val-stack
0E2+8 5- 3*4r s6 d.lexval(3) into val-stack
0E2+8id6 5-3 *4r F→id F.val=d.lexval – do nothing
0E2+8F4 5-3 *4r T→F T.val=F.val – do nothing
0E2+8T11 5-3 *4r s9 push empty slot into val-stack
0E2+8T11*9 5-3- 4r s6 d.lexval(4) into val-stack
0E2+8T11*9id6 5-3-4 r F→id F.val=d.lexval – do nothing
0E2+8T11*9F12 5-3-4 r T→T*F T.val=T1.val*F.val
0E2+8T11 5-12 r E→E+T E.val=E1.val*T.val
0E2 17 r s7 push empty slot into val-stack
0E2r7 17- $ L→Er print(17), pop empty slot from val-stack
0L1 17 $ acc
UCS802 Compiler Construction 22
Top-Down Evaluation (of S-Attributed Definitions)
Productions Semantic Rules
A→B print(B.n0), print(B.n1)
B → 0 B1 B.n0=B1.n0+1, B.n1=B1.n1
B → 1 B1 B.n0=B1.n0, B.n1=B1.n1+1
B→e B.n0=0, B.n1=0

where B has two synthesized attributes (n0 and n1).

UCS802 Compiler Construction 23


Top-Down Evaluation (of S-Attributed Definitions)
• Remember that: In a recursive predicate parser, each non-terminal
corresponds to a procedure.

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→e
else error(“unexpected token”);
}

UCS802 Compiler Construction 24


Top-Down Evaluation (of S-Attributed Definitions)
procedure A() {
int n0,n1; Synthesized attributes of non-terminal B
call B(&n0,&n1); are the output parameters of procedure B.
print(n0); print(n1);
} All the semantic rules can be evaluated
procedure B(int *n0, int *n1) { at the end of parsing of production rules
if (currtoken=0)
{int a,b; consume 0; call B(&a,&b); *n0=a+1; *n1=b;}
else if (currtoken=1)
{ int a,b; consume 1; call B(&a,&b); *n0=a; *n1=b+1; }
else if (currtoken=$) {*n0=0; *n1=0; } // $ is end-marker
else error(“unexpected token”);
}

UCS802 Compiler Construction 25


L-Attributed Definitions
• S-Attributed Definitions can be efficiently implemented.
• We are looking for a larger (larger than S-Attributed Definitions) subset
of syntax-directed definitions which can be efficiently evaluated.
è L-Attributed Definitions

• L-Attributed Definitions can always be evaluated by the depth first visit


of the parse tree.
• This means that they can also be evaluated during the parsing.

UCS802 Compiler Construction 26


L-Attributed Definitions
• A syntax-directed definition is L-attributed if each inherited attribute
of Xj, where 1£j£n, on the right side of A → X1X2...Xn depends only
on:
1. The attributes of the symbols X1,...,Xj-1 to the left of Xj in the
production and
2. the inherited attribute of A

• Every S-attributed definition is L-attributed, the restrictions only apply


to the inherited attributes (not to synthesized attributes).

UCS802 Compiler Construction 27


A Definition which is NOT L-Attributed
Productions Semantic Rules
A→LM L.in=l(A.i), M.in=m(L.s), A.s=f(M.s)
A→QR R.in=r(A.in), Q.in=q(R.s), A.s=f(Q.s)

• This syntax-directed definition is not L-attributed because the semantic


rule Q.in=q(R.s) violates the restrictions of L-attributed definitions.
• When Q.in must be evaluated before we enter to Q because it is an
inherited attribute.
• But the value of Q.in depends on R.s which will be available after we
return from R. So, we are not be able to evaluate the value of Q.in
before we enter to Q.

UCS802 Compiler Construction 28


Translation Schemes
• In a syntax-directed definition, we do not say anything about the
evaluation times of the semantic rules (when the semantic rules
associated with a production should be evaluated?).

• A translation scheme is a context-free grammar in which:


– attributes are associated with the grammar symbols and
– semantic actions enclosed between braces {} are inserted within
the right sides of productions.

• Ex: A → { ... } X { ... } Y { ... }

Semantic Actions
UCS802 Compiler Construction 29
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.

UCS802 Compiler Construction 30


Translation Schemes for S-attributed Definitions
• If our syntax-directed definition is S-attributed, the construction of
the corresponding translation scheme will be simple.
• Each associated semantic rule in a S-attributed syntax-directed
definition will be inserted as a semantic action into the end of the
right side of the associated production.

Production Semantic Rule


E → E1 + T E.val = E1.val + T.val è a production of
a syntax directed definition

ß
E → E1 + T { E.val = E1.val + T.val } è the production of the corresponding
translation scheme

UCS802 Compiler Construction 31


A Translation Scheme Example
• A simple translation scheme that converts infix expressions to the
corresponding postfix expressions.

E→TR
R → + T { print(“+”) } R1
R→e
T → id { print(id.name) }

a+b+c è ab+c+

infix expression postfix expression

UCS802 Compiler Construction 32


A Translation Scheme Example (cont.)
E

T R

id {print(“a”)} + T {print(“+”)} R

id {print(“b”)} + T {print(“+”)} R

id {print(“c”)} e

The depth first traversal of the parse tree (executing the semantic actions in that order)
will produce the postfix representation of the infix expression.
UCS802 Compiler Construction 33
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).
UCS802 Compiler Construction 34
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.

UCS802 Compiler Construction 35


A Translation Scheme with Inherited Attributes
D → T id { addtype(id.entry,T.type), L.in = T.type } L
T → int { T.type = integer }
T → real { T.type = real }
L → id { addtype(id.entry,L.in), L1.in = L.in } L1
L→e

• This is a translation scheme for an L-attributed definitions.

UCS802 Compiler Construction 36


Predictive Parsing (of Inherited Attributes)
procedure D() {
int Ttype,Lin,identry;
call T(&Ttype); consume(id,&identry);
addtype(identry,Ttype); Lin=Ttype;
call L(Lin); a synthesized attribute (an output parameter)
}
procedure T(int *Ttype) {
if (currtoken is int) { consume(int); *Ttype=TYPEINT; }
else if (currtoken is real) { consume(real); *Ttype=TYPEREAL; }
else { error(“unexpected type”); } an inherited attribute (an input parameter)
}
procedure L(int Lin) {
if (currtoken is id) { int L1in,identry; consume(id,&identry);
addtype(identry,Lin); L1in=Lin; call L(L1in); }
else if (currtoken is endmarker) { }
else { error(“unexpected token”); }
}
UCS802 Compiler Construction 37
Eliminating Left Recursion from Translation Scheme
• A translation scheme with a left recursive grammar.

E → E1 + T { E.val = E1.val + T.val }


E → E1 - T { E.val = E1.val - T.val }
E→T { E.val = T.val }
T → T1 * F { T.val = T1.val * F.val }
T→F { T.val = F.val }
F → ( E ) { F.val = E.val }
F → digit { F.val = digit.lexval }

• 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
UCS802 Compiler Construction 38
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).

ß eliminate left recursion


inherited attribute of the new non-terminal
synthesized attribute of the new non-terminal

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 → e { R.syn = R.in }

UCS802 Compiler Construction 39


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)

e R1.syn=g(f(X.x),Y.y)

UCS802 Compiler Construction 40


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 → e { 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 → e { B.syn = B.in }
F → ( E ) { F.val = E.val }
F → digit { F.val = digit.lexval }

UCS802 Compiler Construction 41


Translation Scheme - Intermediate Code Generation
E → T { A.in=T.loc } A { E.loc=A.loc }
A → + T { A1.in=newtemp(); emit(add,A.in,T.loc,A1.in) }
A1 { A.loc = A1.loc}
A → e { A.loc = A.in }
T → F { B.in=F.loc } B { T.loc=B.loc }
B → * F { B1.in=newtemp(); emit(mult,B.in,F.loc,B1.in) }
B1 { B.loc = B1.loc}
B → e { B.loc = B.in }
F → ( E ) { F.loc = E.loc }
F → id { F.loc = id.name }
Syntax-Directed Definition

UCS802 Compiler Construction 42


Predictive Parsing – Intermediate Code Generation
procedure E(char **Eloc) {
char *Ain, *Tloc, *Aloc;
call T(&Tloc); Ain=Tloc;
call A(Ain,&Aloc); *Eloc=Aloc;
}
procedure A(char *Ain, char **Aloc) {
if (currtok is +) {
char *A1in, *Tloc, *A1loc;
consume(+); call T(&Tloc); A1in=newtemp(); emit(“add”,Ain,Tloc,A1in);
call A(A1in,&A1loc); *Aloc=A1loc;
}
else { *Aloc = Ain }
}

UCS802 Compiler Construction 43


Predictive Parsing (cont.)
procedure T(char **Tloc) {
char *Bin, *Floc, *Bloc;
call F(&Floc); Bin=Floc;
call B(Bin,&Bloc); *Tloc=Bloc;
}
procedure B(char *Bin, char **Bloc) {
if (currtok is *) {
char *B1in, *Floc, *B1loc;
consume(+); call F(&Floc); B1in=newtemp(); emit(“mult”,Bin,Floc,B1in);
call B(B1in,&B1loc); Bloc=B1loc;
}
else { *Bloc = Bin }
}
procedure F(char **Floc) {
if (currtok is “(“) { char *Eloc; consume(“(“); call E(&Eloc); consume(“)”); *Floc=Eloc }
else { char *idname; consume(id,&idname); *Floc=idname }
}

UCS802 Compiler Construction 44


Bottom-Up Evaluation of Inherited Attributes
• Using a top-down translation scheme, we can implement any
L-attributed definition based on a LL(1) grammar.
• Using a bottom-up translation scheme, we can also implement any
L-attributed definition based on a LL(1) grammar (each LL(1) grammar
is also an LR(1) grammar).
• In addition to the L-attributed definitions based on LL(1) grammars,
we can implement some of L-attributed definitions based on LR(1)
grammars (not all of them) using the bottom-up translation scheme.

UCS802 Compiler Construction 45


Removing Embedding Semantic Actions
• In bottom-up evaluation scheme, the semantic actions are evaluated
during the reductions.
• During the bottom-up evaluation of S-attributed definitions, we have a
parallel stack to hold synthesized attributes.
• Problem: where are we going to hold inherited attributes?
• A Solution:
– We will convert our grammar to an equivalent grammar to guarantee to the
followings.
– All embedding semantic actions in our translation scheme will be moved into the
end of the production rules.
– All inherited attributes will be copied into the synthesized attributes (most of the
time synthesized attributes of new non-terminals).
– Thus we will be evaluate all semantic actions during reductions, and we find a
place to store an inherited attribute.

UCS802 Compiler Construction 46


Removing Embedding Semantic Actions
To transform our translation scheme into an equivalent translation scheme:
1. Remove an embedding semantic action Si, put a new non-
terminal Mi instead of that semantic action.
2. Put that semantic action Si into the end of a new
production rule Mi®e for that non-terminal Mi.
3. That semantic action Si will be evaluated when this new
production rule is reduced.
4. The evaluation order of the semantic rules are not
changed by this transformation.

UCS802 Compiler Construction 47


Removing Embedding Semantic Actions
A® {S1} X1 {S2} X2 ... {Sn} Xn

ß remove embedding semantic actions


A® M1 X1 M2 X2 ... Mn Xn
M1®e {S1}
M2®e {S2}
.
.
Mn®e {Sn}

UCS802 Compiler Construction 48


Removing Embedding Semantic Actions
E→TR
R → + T { print(“+”) } R1
R→e
T → id { print(id.name) }

ß remove embedding semantic actions


E→TR
R → + T M R1
R→e
T → id { print(id.name) }
M → e { print(“+”) }
UCS802 Compiler Construction 49
Translation with Inherited Attributes
• Let us assume that every non-terminal A has an inherited attribute A.i, and every
symbol X has a synthesized attribute X.s in our grammar.
• For every production rule A® X1 X2 ... Xn ,
– introduce new marker non-terminals M1,M2,...,Mn and
– replace this production rule with A® M1 X1 M2 X2 ... Mn Xn
– the synthesized attribute of Xi will not be changed.
– the inherited attribute of Xi will be copied into the synthesized attribute of Mi by the new semantic
action added at the end of the new production rule Mi®e.
– Now, the inherited attribute of Xi can be found in the synthesized attribute of Mi (which is immediately
available in the stack.

A ® {B.i=f1(...)} B {C.i=f2(...)} C {A.s= f3(...)}


ß
A ® {M1.i=f1(...)} M1 {B.i=M1.s} B {M2.i=f2(...)} M2 {C.i=M2.s} C {A.s= f3(...)}
M1®e {M1.s=M1.i}
M2®e {M2.s=M2.i}

UCS802 Compiler Construction 50


Translation with Inherited Attributes
S ® {A.i=1} A {S.s=k(A.i,A.s)}
A ® {B.i=f(A.i)} B {C.i=g(A.i,B.i,B.s)} C {A.s= h(A.i,B.i,B.s,C.i,C.s)}
B ® b {B.s=m(B.i,b.s)}
C ® c {C.s=n(C.i,c.s)}

ß
S ® {M1.i=1} M1 {A.i=M1.s} A {S.s=k(M1.s,A.s)}
A ® {M2.i=f(A.i)} M2 {B.i=M2.s} B
{M3.i=g(A.i,M2.s,B.s)} M3 {C.i=M3.s} C
{A.s= h(A.i, M2.s,B.s, M3.s,C.s)}
B ® b {B.s=m(B.i,b.s)}
C ® c {C.s=n(C.i,c.s)}
M1®e {M1.s=M1.i}
M2®e {M2.s=M2.i}
M3®e {M3.s=M3.i}

UCS802 Compiler Construction 51


Actual Translation Scheme
S ® {M1.i=1} M1 {A.i=M1.s} A {S.s=k(M1.s,A.s)}
A ® {M2.i=f(A.i)} M2 {B.i=M2.s} B {M3.i=g(A.i,M2.s,B.s)} M3 {C.i=M3.s} C {A.s= h(A.i, M2.s,B.s, M3.s,C.s)}
B ® b {B.s=m(B.i,b.s)}
C ® c {C.s=n(C.i,c.s)}
M1®e {M1.s= M1.i}
M2®e {M2.s=M2.i}
M3®e {M3.s=M3.i}

S ® M1 A { s[ntop]=k(s[top-1],s[top]) }
M1® e { s[ntop]=1 }
A ® M2 B M3 C { s[ntop]=h(s[top-4],s[top-3],s[top-2],s[top-1],s[top]) }
M2® e { s[ntop]=f(s[top]) }
M3® e { s[ntop]=g(s[top-2],s[top-1],s[top])}
B®b { s[ntop]=m(s[top-1],s[top]) }
C®c { s[ntop]=n(s[top-1],s[top]) }

UCS802 Compiler Construction 52


Evaluation of Attributes
S
S.s=k(1,h(..))
A.i=1
A
A.s=h(1,f(1),m(..),g(..),n(..))

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

UCS802 Compiler Construction 53


Evaluation of Attributes
stack input s-attribute stack
bc$
M1 bc$ 1
M1 M2 bc$ 1 f(1)
M1 M2 b c$ 1 f(1) b.s
M1 M2 B c$ 1 f(1) m(f(1),b.s)
M1 M2 B M3 c$ 1 f(1) m(f(1),b.s) g(1,f(1),m(f(1),b.s))
M1 M2 B M3 c $ 1 f(1) m(f(1),b.s) g(1,f(1),m(f(1),b.s)) c.s
M1 M2 B M3 C $ 1 f(1) m(f(1),b.s) g(1,f(1),m(f(1),b.s)) n(g(..),c.s)
M1 A $ 1 h(f(1),m(..),g(..),n(..))
S $ k(1,h(..))

UCS802 Compiler Construction 54

You might also like