0% found this document useful (0 votes)
261 views102 pages

Syntax-Directed Translation in Compilers

The document discusses syntax-directed definitions and syntax-directed translation for associating semantic actions with parsing. It provides examples of calculating values during a parse (calculator), converting infix to postfix notation, and generating code. Attributes are computed and associated with grammar symbols, with semantic rules defining computations for production rules.

Uploaded by

Deepak Mishra
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)
261 views102 pages

Syntax-Directed Translation in Compilers

The document discusses syntax-directed definitions and syntax-directed translation for associating semantic actions with parsing. It provides examples of calculating values during a parse (calculator), converting infix to postfix notation, and generating code. Attributes are computed and associated with grammar symbols, with semantic rules defining computations for production rules.

Uploaded by

Deepak Mishra
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

✬ ✩

Compiler Design 1

SDD, Attribute Grammar and SDT

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 2

Translation

• So far we have talked about parsing of a


language. But our main goal is translation.
• Semantic actions to translate the source
language to target language often go
hand-in-hand with parsing. It is called
syntax-directed translation.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 3

Translation

• To perform semantic actions along with


parsing (reduction for example), we may
associate computation with the production
rules. Computed values are propagated as
attributes of non-terminals.
• Otherwise the parse tree may be built
explicitly and semantic actions are
performed while traversing the tree.
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 4

Example

Consider the following production rule of the


classic expression grammar: E → E1 + T a .
We consider three different translations:
• implementation of a simple calculator,
• conversion of an infix expression to a postfix
expression,
• general purpose code generation.
a We

✫ ✪
have used subscript to differentiate between two instances of E.

Lect 9 Goutam Biswas


✬ ✩
Compiler Design 5

Example: Calculator

We have already seen that the only attribute of


E and T are values corresponding to the
sub-trees of E and T . Let us call the attribute
to be val.
The semantic action associated with the given
production rule is,
E → E1 + T {E·val = E1 ·val + T ·val}a .
a In bison this gets translated to $$ = $1 + $3.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 6

Note

The action may take place when E1 + T is


reduced to E. The computed value is saved as
the attribute of E. There is no other side-effect.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 7

Note

But in the calculator if we want to keep a


provision of storing a value as a named object
(variable), we need a symbol table where the
variable names and their values are stored.
In this case the semantic action of
ES → id := E will changes the state of
computation (side effect) by entering the E·val
in the symbol table corresponding to [Link].

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 8

Example: Infix to Postfix Conversion

The problem is to convert an infix arithmetic


expression to a postfix expression. Both input
and output are strings of characters.
So the attribute of each non-terminal can be a
string of characters (char *). Let the name of
the field be exp. The semantic action associated
with the production rule is as follows:

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 9

Example: Infix to Postfix

E → E1 + T
{
[Link]=(char*)malloc(strlen([Link])+
strlen([Link])+4);
strcpy([Link], [Link]); strcat([Link], " ");
strcat([Link], [Link]);
strcat([Link], " + ");
free([Link]); free([Link]);
}
Again there is no side-effect
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 10

Example: Code Generation

We assume that the computed values


corresponding to the expressions E1 and T are
stored in temporary locationsa .
The main attribute of a non-terminal in this
case is the address or index of the locationb in
the symbol table.
a Compiler defines temporary variables or virtual registers for this purpose
and enters them in the symbol table.
b Note that the location has not yet been bound to memory or physical register.

The address may be an index of the symbol table.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 11

Example: Code Generation

E → E1 + T
{
[Link] = newLoc();
codeGen(assignPlus, [Link], [Link], [Link]);
}
where assignPlusa means
[Link] = [Link] + [Link].
a This
is an example of an intermediate code generated from the source lan-
guage expression.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 12

Note

This action has a side-effect as it makes an


entry of the new location in the symbol table.
It also adds the corresponding intermediate
code in the code stream.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 13

Associating Information

We associate information to language


constructs by attaching attributes to the
grammar symbols. Computation of these
attributes are associated with the production
rules in the form of semantic rules.
Initial attribute values are supplied by the
scanner.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 14

Definition

A syntax-directed definition is a context-free


grammar where attributes are associated with
the grammar symbols and semantic rules for
computing the attributes are associated with
the production rules. These grammars are also
called attribute grammars when the definition
does not have any side-effect. There is no strict
order of evaluation of the attributes, but there
should not be any circularity.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 15

Definition

A syntax-directed translation is an executable


specification of SDD. Fragments of programs
are associated to different points in the
production rules. The order of execution is
important in this case.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 16

Example

A → {Action1 } B {Action2 } C {Action3 }


Action1 : takes place before parsing of the
input corresponding to the non-terminal B.
Action2 : takes place after consuming the input
for B, but before consuming the input for C.
Action3 : takes place at the time of reduction of
BC to A or after consuming the input
corresponding to BC.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 17

Note

• Embedded action may create some problem


in parser generator like Bison.
• Bison replaces the embedded action in a
production rule by an ε-production and
associates the embedded action with the new
rule.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 18

Note

• But this may change the nature of the


grammar. As an example, the grammar
S → A|B, A → aba, B → abb is LALR. But if
an embedded action is introduced as shown,
S → A|B, A → a {action} ba, B → abb.
Bison modifies the grammar to
S → A|B, A → aM ba, B → abb, M →
ε {action} , and the grammar is no longer
LALR.
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 19

General Approach for SDT

Construct the complete parse tree. Compute


the attributes of non-terminals by traversing
the tree. Explicit construction of a tree is costly
in terms of time and space.
There are SDDs that do not require explicit
construction of the parse tree. We shall
consider two of them - S-attributed and
L-attributed definitions.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 20

A Complete Example

Consider the following grammar (augmented) of


binary strings:

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 21

0 : S′ → N $
1: N → SL
2: S → +
3: S → −
4: L → LB
5: L → B
6: B → 0
7: B → 1
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 22

Note

• We wish to translate a signed binary string


to a signed decimal string.
• We first construct the LR(0) automaton of
the grammar and find that the grammar is
SLR.
• We associate attributes to the non-terminals.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 23

LR(0) Automaton

q0 : S ′ → •N $ N → •SL S → •+
S → •−
q1 : S ′ → N • $
q2 : N → S • L L → •LB L → •B
B → •0 B → •1
q3 : S → +•
q4 : S → −•
q5 : N → SL• L → L • B B → •0
B → •1
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 24

LR(0) Automaton

q6 : L → B•
q7 : B → 0•
q8 : B → 1•
q9 : L → LB•

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 25

SLR Parsing Table

S Action Goto
+ − 0 1 $ N S L B
0 s3 s4 1 2
1 Acc
2 s7 s8 5 6
3 r6 r6
4 r7 r7
5 s7 s8 r1 9

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 26

SLR Parsing Table

S Action Goto
+ − 0 1 $ N S L B
6 r5 r5 r5
7 r6 r6 r6
8 r7 r7 r7

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 27

Attributes of Non-Terminals

Following are the attributes of different


non-terminals:
Non-terminal Attribute Type
N val int
S sign char
L val int
B val int
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 28

Definition or Action

0 : S′ → N Accept
1 : N → SL if ([Link] == ’-’) [Link]= - [Link];
else [Link] = [Link];
2: S → + [Link] = ’+’;
3: S → − [Link] = ’-’;
4 : L → L1 B [Link] = 2*[Link]+[Link];
5: L → B [Link] = [Link];
6: B → 0 [Link] = 0;
7: B → 1 [Link] = 1;

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 29

Example: Parsing & Value Stack

Type Stack → Input→ Action/Value


Parsing $0 +101$ shift
Value $
Parsing $03 101$ reduce
Value $+
Parsing $02 101$ shift
Value $S [Link]=’+’
Parsing $028 01$ reduce
Value $S1
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 30

Example: Parsing & Value Stack

Type Stack → Input→ Action/Value


Parsing $026 01$ reduce
Value $SB [Link] = 1
Parsing $025 01$ shift
Value $SL [Link] = [Link]
Parsing $0257 1$ reduce
Value $SL0
Parsing $0259 1$ reduce
Value $SLB [Link] = 0
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 31

Example: Parsing & Value Stack

Type Stack → Input→ Action/Value


Parsing $025 1$ shift
Value $SL [Link] = 2*[Link] + [Link]
Parsing $0258 $ reduce
Value $SL1
Parsing $0259 $ reduce
Value $SLB [Link]=1
Parsing $025 $ reduce
Value $SL [Link] = 2*[Link] + [Link]
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 32

Example: Parsing & Value Stack

Type Stack → Input→ Action/Value


Parsing $01 $ Accept
Value $N [Link] = +[Link]

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 33

Decorated Parse Tree

N [Link]=[Link]

S L1 [Link]=2*[Link] + [Link]

+ L2 B [Link]=1
[Link]=2*[Link]+[Link]
[Link]=0
[Link]=B.valL3 B 1

[Link]=1 B 0

✫ ✪
1
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 34

Synthesized Attribute

• In this example the value of an attribute of a


non-terminal is either coming from the
scannera or it is computed from the
attributes of its children.
• This type of attribute is known as a
synthesized attribute.
a Attribute of a terminal comes from the scanner.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 35

S-Attributed

• An attributed grammar is called


S-attributed if every attribute is synthesized.
• Attributes in such a grammar can be easily
computed during a bottom-up parsing.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 36

Note

Attribute of a non-terminal depends on the


nature of translation. But it may also depend
on the nature of the grammar.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 37

Exercise

Following grammar of 2’s complement numerals


is to be translated to a signed decimal integer.

1: N → L
2: L → LB
3: L → B
4: B → 0
5: B → 1
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 38

Exercise

Associate attributes to the non-terminals and


give rules for semantic actions. Write bison
specification for the grammar.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 39

Example

Consider a right-recursive grammar of signed


binary strings:

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 40

0 : S′ → N
1: N → SL
2: S → +
3: S → −
4: L → BL
5: L → B
6: B → 0
7: B → 1
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 41

Attributes of Non-Terminals

We need a new attribute of L to remember the bit


position:

Non-terminal Attribute Type


N val int
S sign char
L val int
pos int
B val int

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 42

Action for Rules

0 : S′ → N Accept
1 : N → SL if ([Link] == ’-’) [Link]=- [Link];
else [Link] = [Link];
2: S → + [Link] = ’+’;
3: S → − [Link] = ’-’;
4 : L → BL1 if([Link])
[Link]=pow(2,[Link])+[Link];
else [Link]=[Link];
[Link]=[Link]+1;

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 43

Actions for Production Rules

5 : L → B [Link] = [Link]; [Link] = 1


6: B → 0 [Link] = 0;
7: B → 1 [Link] = 1;

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 44

Example

Consider the following grammar for variable


declaration:
1: D → T L;
2 : T → int
3 : T → double
4 : L → L , id
5 : L → id
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 45

Parse Tree

The parse tree for the string double id, id; is


as follows:

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 46

T L ;

double L , id

id
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 47

Note

When an id is reduced to the non-terminal L,


it is inserted in the symbol table along with its
type informationa . The type information is not
available from any subtree rooted at L. It has
to be inherited from T via the root D.
a The type information is important for space allocation, representation, op-
erations, correctness and other purposes.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 48

SDDefinition

1 : D → T L; [Link] = [Link]
2: T → int [Link] = INT
3: T → double [Link] = DOUBLE
4 : L → L1 , id [Link] = [Link]
addSym([Link], [Link])
5 : L → id addSym([Link], [Link])

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 49

Inherited Attribute

Let B be a non-terminal at a parse tree node


N . Let M be the parent of N . An inherited
attribute B.i is defined by the semantic rule
associated with the production rule of M
(parent).
Inherited attribute at the node N is defined in
terms of M , N and N ’s siblings.
In the previous example the non-terminal L gets
the attribute from T as an inherited attribute.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 50

S-Attributed Definitions

An SDD is S-attributed if every attribute is


synthesized. The attribute grammar may be
called S-attributed grammar.
This definition can be implemented in a
LR-parser as the reduction traverse the
parse-tree in postorder.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 51

L-Attributed Definitions

An SDD is called L-attributed (‘L’ for left) if


each attribute is either
• synthesized, or
• inherited with the following restrictions: if
A → α1 α2 · · · αn be a production rule, and
αk has an inherited attribute ‘a’ computed in
this rule, then the computation may involve
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 52

L-Attributed Grammar

• inherited attribute of A (parent), or


• attributes (inherited or synthesized) of
α1 , α2 , · · · , αk−1 (symbols to the left of αk ),
• attributes of αk , provided no dependency
cyclea is formed.
aA → B { A.s = B.i; B.i = A.s + k }.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 53

Rules

The type definition mentioned earlier is L-attributed.

1 : D → T L; [Link] = [Link]
2: T → int [Link] = INT
3: T → double [Link] = DOUBLE
4 : L → L1 , id [Link] = [Link]
addSym([Link], [Link])
5 : L → id addSym([Link], [Link])

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 54

Note

The question is how to propagate the type


information in a parser generated by bison?
The non-terminal T gets the value of
synthesized type attribute when a T -production
rule is reduced.
But that cannot be propagated as an attribute
of the non-terminal L as this non-terminal is
not present in the stack.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 55

Solution I

A very ad hoc solution is to use a global


variable to hold the type value.

T → int type = INT


T → double type = DOUBLE
L → L1 , id addSym([Link], type)
L → id addSym([Link], type)

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 56

Solution II

We introduce a different attribute of L, a list of


symbol table entries corresponding to different
identifiers, and initialize their types at the end.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 57

1 : D → T L; initType([Link], [Link])
2 : T → int [Link] = INT
3 : T → double [Link] = DOUBLE
4 : L → L1 , id [Link] = L [Link] +
mklist(addSym([Link]))
5 : L → id [Link] =
mklist(addSym([Link]))
Read ‘+’ as append in the list.
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 58

Solution III

We can device another solution from the value


stack. For that we consider the states of LR(0)
automaton of the grammar.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 59

LR(0) Automaton

q0 : S → •D D → •T L; T → •int
T → •double
q1 : S → D•
q2 : D → T • L L → •L, id L → •id
q3 : T → int•
q4 : S → double•
q5 : D → T L•; L → L•, id
q6 : L → id•

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 60

LR(0) Automaton

q7 : L → L, •id
q8 : L → L, id•
q9 : D → T L; •

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 61

Example: Parsing & Value Stack

Type Stack → Input→ Action/Value


Par $0 int id, id;$ shift
Val $
Par $03 id, id;$ reduce
Val $int
Par $02 id, id;$ shift
Val $T [Link]=INT
Par $026 , id;$ reduce
Val $T id
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 62

Example: Parsing & Value Stack

Type Stack → Input→ Action/Value


Par $025 , id;$ reduce
Val $T L addSym([Link],[Link])
How does L gets the type information. Note that in
bison L ≡ $$ and id ≡ $1. But the type information is
available in T in the stack, below the handle.

Type Stack → Input→ Action/Value


Par $0257 id;$ shift
Val $T L ,
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 63

Example: Parsing & Value Stack

Type Stack → Input→ Action/Value


Par $02578 ;$ reduce
Val $T L , id
Par $025 ;$
Val $T L addSym([Link],[Link])
Again the type information is available just below the
handle.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 64

Note

In Bison the attribute below the handle can be


accessed. In this case the non-terminal T
corresponds to $0 and its type attribute is
$[Link].

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 65

Note

Often a natural grammar is transformed to


facilitate some type of parsing, and the parse
tree does not match with the abstract syntax
tree of the language.
As an example the left recursion is removed for
LL(1) parsing. How does the original
S-attributed grammar gets modified after the
removal of left-recursion? We consider the
following example.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 66

S-Attributed Expression Grammar

S → E$ { print [Link] }
E → E1 + T { [Link] = [Link] + [Link]}
E → T { [Link] = [Link]}
T → T1 ∗ F { [Link] = [Link] * [Link]}
T → F { [Link] = [Link]}
F → (F ) { [Link] = [Link]}
F → ic { [Link] = [Link]}

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 67

Equivalent LL(1) Grammar

S → E$
E → T E′
E ′ → +T E ′
E′ → ε
T → FT′
T ′ → ∗F T ′
T′ → ε
F → (E)
F → ic
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 68

Decorated Parse Tree of 2 + 3 + 4

E0 .s = E1 .s + T1 .s E0
E1 .s = E2 .s + T2 .s
E1 T1 T1 .s = 4
+
T2 .s = 3
T2 F1 F1 .s = 4
E2 .s = 2 E2 +
F2 .s = 3
F2
T3 .s = 2 T3 ic [Link]=4

F3 .s = 2 F3 [Link]=3 ic
4

[Link]=2 ic 3

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 69

Parse Tree of LL(1) Grammar

E0

T3 .s = 2 T3 E1′
T2 .s = 3
+ E2′
F3 .s = 2 F3 T2
T1 .s = 4
+ E3′
[Link]=2 ic F2 .s = 3 F2 T1
F1 .s = 4 ε
[Link]=3 ic F1
2

[Link]=4 ic
3

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 70

Note

• Two arguments of ‘+’ are in different


subtrees. It is necessary to pass the value of
T3 .s to the subtree of E1′ .
• It is also necessary for left-associativity of
‘+’, to propagate the computed value down
the tree say from E1′ to E2′ .
• We achieve this by inherited attributes E ′ .i
and T ′ .i of the non-terminals E ′ and T ′ .
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 71

Parse Tree of LL(1) Grammar

E0

T3 .s = 2 T3 E1′ E1′ .i = T3 .s
T2 .s = 3 E2′ .i = E1′ .i + T2 .s
+ E2′
F3 .s = 2 F3 T2
T1 .s = 4
+ E3′ E3′ .i = E2′ .i + T1 .s
[Link]=2 ic F2 .s = 3 F2 T1
F1 .s = 4 ε
[Link]=3 ic F1
2

[Link]=4 ic
3

✫ ✪
4

Lect 9 Goutam Biswas


✬ ✩
Compiler Design 72

Note

But it is also necessary to propagate the


computed value towards the root. This is done
through the synthesized attributes of E ′ and T ′
- E ′ .s, T ′ .s.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 73

Decorated Parse Tree of LL(1) Grammar

E0′ .s = E1′ .s
E0
E1′ .s = E2′ .s
T3 .s = 2 T3 E1′ E1′ .i = T3 .s
T .s = 3 E2′ .i = E1′ .i + T2 .s
+ 2 E2′
F3 .s = 2 F3 T2 E2′ .s = E3′ .s
T1 .s = 4
+ E3′ E3′ .i = E2′ .i + T1 .s
[Link]=2 ic F2 .s = 3 F2 T1
E3′ .s = E3′ .i
F1 .s = 4 ε
[Link]=3 ic F1
2

[Link]=4 ic
3

✫ ✪
4

Lect 9 Goutam Biswas


✬ ✩
Compiler Design 74

L-Attributed LL(1) Expression Grammar

E → T { E’.ival = [Link] } E ′
{ [Link] = E’.sval }
E ′ → +T { E1’.ival = E’.ival + [Link] } E1′
{ E’.sval = E1’.sval }
E ′ → ε { E’.sval = E’.ival }

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 75

L-Attributed LL(1) Expression Grammar

T → F { T’.ival = [Link] } T ′
{ [Link] = T’.sval }
T ′ → ∗F { T1’.ival = T’.ival * [Link] } T1′
{ T’.sval = T1’.sval }
T ′ → ε { T’.sval = T’.ival }

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 76

L-Attributed LL(1) Expression Grammar

F → (E) { [Link] = [Link] }


F → ic { [Link] = [Link] }

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 77

LL(1) Parsing Table

Non Terminal
Term. + ∗ ( ) ic $
E E → T E′ E → T E′
T T → FT′ T → FT′
F F → (E) F → ic
E′ E ′ → +T E ′ E′ → ε E′ → ε
T′ T′ → ε T ′ → ∗F T ′ T′ → ε T′ → ε

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 78

Example

Consider the leftmost derivation and the parse


tree decorated with attributes. corresponding
to the input 2 + 3 * 4.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 79

Left-most Derivation

1 E 10 → ic + ic ∗ ic T ′ E ′
2 → T E′ 11 → ic + ic ∗ ic ε E ′
3 → F T ′E ′ 12 → ic + ic ∗ ic
4 → ic T ′ E ′
5 → ic ε E ′
6 → ic + T E ′
7 → ic + F T ′ E ′
8 → ic + ic T ′ E ′
9 → ic + ic ∗ F T ′ E ′

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 80

Start
Parsing Stack Input Parsing Stack Input
$E ic + ic * ic $ $ E’ T’ F ic * ic $

$ E’ T ic + ic * ic $ $ E’ T’ ic * ic $

$ E’ T’ F ic + ic * ic $ $ E’ T’ * ic $

$ E’ T’ ic ic + ic * ic $ $ E’ T’ F * ic $

$ E’ T’ + ic * ic $ $ E’ T’ F ic $

$ E’ + ic * ic $ $ E’ T’ ic ic $

$ E’ T + + ic * ic $ $ E’ T’ $

$ E’ T ic * ic $ $ E’ $

End $ $

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 81

Decorated Parse Tree

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 82

E0 .s = 14
E0
E1′ .i = 2
T1 .s = 2 T1 E1′ E1′ .s = 14

F1 .s = 2 F1 T1′
T1′ .i = 2 E2′ .i = 14
+ T2 E2′
T1′ .s = 2 E2′ .s = 14
T2 .s = 12
[Link]=2 ic
ε
F2 T2′ .i = 3 T2′
F2 .s = 3 T2′ .s = 12
ε
2
[Link]=3 ic ∗
F2 .s = 4 F3 T3′
T3′ .i = 12
T3′ .s = 12
3 ε
[Link]=4 ic

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 83

Implementation of L-Attributed Translation

The important question is how to implement


L-attributed translation with the top-down
parsing. Following is a general scheme.
• A simple parser stack holds records
corresponding to terminals and
non-terminals.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 84

Implementation of L-Attributed Translation

• But to implement L-attributed translations,


it should also hold records containing pointer
to action (code), synthesize attributes and
inherited attributes.
• For a non-terminal A, the inherited
attributes are kept in the record
corresponding to A itself.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 85

Implementation of L-Attributed Translation

• The pointer to the code to evaluate the


inherited attributes of A are naturally kept
above the record of A.
• Synthesized attributes of A are kept below
the record of A and its inherited attribute.
This record may also contain pointer to
some code to copy the synthesized attributes
in records down the stack (below a fixed
depth).
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 86

An Example

Consider the following rule of the L-attributed


expression grammar:

E → T { E’.ival = [Link] } E ′
{ [Link] = E’.sval }
The stack contains following records before the
E is expanded.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 87

Parsing Stack with Attribute Records

Parsing Stack Input


$ [Link]=? E ic + ic * ic $

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 88

An Example

After the replacement of the non-terminal E,


the stack looks like:
Parsing Stack Input
$ [Link]=? E’.sv=? E’ E’.iv=? [Link]=? T ic + ic * ic $

[Link]=E’.sv E’.iv=[Link]

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 89

An Example

Parsing Stack Input


$ [Link]=? E’.sv=? E’ E’.iv=? [Link]=? [Link]=? F ic + ic * ic $

[Link]=E’.sv E’.iv=[Link]

Parsing Stack Input


$ [Link]=? E’.sv=? E’ E’.iv=? [Link]=? [Link]=? ic ic + ic * ic $

[Link]=E’.sv E’.iv=[Link] 2

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 90

An Example

Parsing Stack Input


$ [Link]=? E’.sv=? E’ E’.iv=? [Link]=2 [Link]=2
+ ic * ic $

[Link]=E’.sv E’.iv=[Link]

After three pops


Parsing Stack Input
$ [Link]=? E’.sv=? E’ E’.iv=2
+ ic * ic $

[Link]=E’.sv

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 91

Another Example

L-attributed grammars come naturally with


flow-control statements. Following is an
example with if-then-else statement.

IS → if BE then S1 else S2 .

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 92

Attributes of Statement

• Every statement has a natural synthesized


attribute, [Link], holding the code
corresponding to S.
• Also a statement S has a continuation, the
next instruction to be executed after
execution of S. This may be handled as a
jump target (label). But this label is an
inherited attribute of S, [Link], propagated
in the subtree of S.
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 93

Attributes of Boolean Expression

• The boolean expression also has a


synthesized attribute [Link].
• But it has two inherited attributes, [Link],
a jump target (label) where the control is
transfered if the boolean expression is
evaluated to true. This is the beginning of
S1 .
Similarly there is [Link], a label at the
beginning of S2 .
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 94

SDD for if-then-else

IS → if BE l1=newLabel(), l2=newLabel()
then S1 [Link] = l1, [Link]=l2
else S2 . S1 .next = S2 .next = [Link]
[Link] = [Link] + l1’:’ +
S1 .code + l2’:’ + S2 .code

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 95

L-Attributed SDT for if-then-else

IS → if {l1=newLabel(),l2=newLabel()
[Link] = l1, [Link]=l2}
BE {S1 .next = [Link] }
then S1 {S2 .next = [Link] }
else S2 .
{[Link] = [Link] + l1’:’ +
S1 .code + l2’:’ + S2 .code}
✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 96

Note

Afterward we shall see how this is managed in


an actual implementation using back-patching.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 97

SDD for Boolean Expression and

BE → BE1 and BE2 BE1 .true=l=newLabel()


BE1 .false = [Link]
BE2 .true = [Link]
BE2 .false = [Link]
[Link] = BE1 .code +
l’:’ + BE2 .code

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 98

L-Attributed SDT for Boolean Expression and

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 99

BE → { BE1 .true=l=newLabel()
BE1 .false = [Link] }
BE1 and
{ BE2 .true = [Link]
BE2 .false = [Link] }
BE2
{ [Link] = BE1 .code +
l’:’ + BE2 .code }

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 100

Note

Not all definitions can be implemented during


parsing. Consider the following definition to
convert infix-expression to prefix expression.

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 101

Rules

1 : E → { putchar(’+’); } E1 + T
2: E → T
3: T → { putchar(’*’); } T1 ∗ F
4: T → F
5 : F → (E)
6 : F → ic {printf(" \%d ", [Link]);}

✫ ✪
Lect 9 Goutam Biswas
✬ ✩
Compiler Design 102

Note

It is not possible to activate any one of the putchar()


operations while parsing without seeing ‘+’ or ‘*’. But if
the whole parse tree is availablea New leaf nodes
corresponding to actions can be added to internal nodes.
Finally a preorder traversal in the modified tree will do
the job.
a The whole parse tree is available only after the parsing is complete.

✫ ✪
Lect 9 Goutam Biswas

You might also like