Sunteți pe pagina 1din 20

Chapter 5

Syntax-Directed Translation

Translation of languages guided by context-free


grammars.
Attach attributes to the grammar symbols. Values of the
attributes are computed by semantic rules associated
with the grammar productions.
Two notations:
-- Syntaxdirected definitions: Each production has a set of
semantic rules associated with it.
--Translation Schemes: Embed the semantic actions within
the productions.
Conceptually we parse the input token stream, build the
parse tree and then traverse the tree as needed to
evaluate the semantic rules. The rules may generate
code, save information in the symbol table, issue error
messages, etc.

In some cases we dont have to follow this outline


literally. We may evaluate the rules during parsing.
Synthesized attribute: The value of the attribute at a
parent node can be found from the attributes of its
children. It can be evaluated by traversing the tree
bottom-up.
Inherited attribute: The value of the attribute at a node
can be found from the attributes at its parent node and/or
its sibling nodes. Can be evaluated by traversing the tree
top-down.
S-attributed definition: A syntax-directed definition where
all attributes are synthesized (the S stands for
synthesized).

Example: Simple desk calculator


Production
L En
E E1 + T
ET
T T1 * F
TF
F (E)
F digit

Semantic Rules
print(E.val)
E.val := E1.val + T.val
E.val := T.val
T.val := T1.val * F.val
T.val := F.val
F.val := E.val
F.val := digit.lexval

Example: Annotated parse tree for


3*5+4n
L
n

E.Val = 19
E.Val = 15

T.Val = 4

T.Val = 15
T.Val = 3

F.Val = 3
digit.lexval = 3

F.Val = 4
F.Val = 5

digit.lexval = 5

digit.lexval = 4

Example
Using inherited
attributes to parse a
declaration and add
type information to
the symbol table.

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)

Annotated Parse Tree for real, id1,


id2, id3
D
T.Type = real

real

L.in = real

L.in = real

L.In = real

id1

id2

id3

If all attributes are synthesized then a bottom


up parser can evaluate the attributes while it
parses.
Add attribute fields to the nonterminals on the
stack.
Before each reproduction apply the semantic
rule associated with the production.
E.g. Assume the semantic rule associated with
the A XYZ production is : A.a := f (X.x, Y.y,
Z.z).

Before the reduction


the parser stack
looks like:
After the reduction the
parser stack looks
like:

A.A

X.X

Y.y

Z.Z

Many top-down and bottom-up translation methods can


be obtained by applying a depth-first visit procedure to
the root of the parse tree:
Procedure dfvisit(n : node);
Begin
for each child m of n, from left to right do
begin
evaluate inherited attributes of m;
dfvisit(m) end;
evaluate synthesized attributes of n
End.

This method works as long as the inherited attributes of


each child node just depend on attributes of the parent
node and the children to its left; there is no dependence
on attributes of children to the right.
A syntax-directed definition is L-attributed if each
inherited attribute of Xj on the right side of a production A
x1, X2,., Xn depends only on the attributes of X1,
X2,, Xj-1 to the left of Xj in the production and the
inherited attributes of A.
The L stands for left.
There are no restrictions on the synthesized attributes of
Xj so every S-attributed definition is L-attributed.

Top-Down Translation
E.g.
E E1 + T
{E.val := E1.val + T.val}
E E1 T
{E.val := E1.val T.val}
ET
{E.val := T.val}
T (E)
{T.val := E.val}
T num
{T.val := num.val}
To eliminate the left-recursion we add a
nonterminal R to the grammar with an inherited
attribute, R.i and a synthesized attribute, R.s.
The transformed translation scheme is:

E T {R.i := T.val} R {E.val := R.s}


R + T {R1.i := R.i + T.val} R1 {R.s := R1.s}
R - T {R1.i := R.i T.val} R1 {R.s := R1.s}
R {T.val := num.val}
In general suppose the translation scheme has the
folowing left-recursive structure:
A A1 Y {A.a := g (A1.a, Y.y)}
A X {A.a := f (X.x)}
f and g are arbitrary functions and A.a, A1.a, X.x and Y.y
are synthesized attributes.
Add a new nonterminal R, with a synthesized attribute
R.s and an inherited attribute, R.i.

To eliminate the left-recursion the translation


scheme is transformed to:
A X {R.i := f (X.x)} R {A.a := R.s}
R Y {R1.i := g (R.i, Y.y)} R1 {R.s :=
R1.s}
R {R.s := R.i}
E.g. A left recursive translation scheme for
generating syntax trees:
E E1 + T {E.nptr := mknode (+, E1.nptr,
T.nptr)}

E E1 - T {E.nptr := mknode (-, E1.nptr,


T.nptr)}
E T {E.nptr := T.nptr}
T (E) {T.npte := E.nptr}
T id {T.nptr := mkleaf (id, id.entry)}
T num {T.nptr := mkleaf (num,
num.value)}

Eliminating left recursion gives :


E T {R.i := T.nptr} r {E.nptr := R.s}
R + T {R1.i := mknode (+, R.i, T.nptr)}
R1 {R.s := R1.s}
R - T {R1.i := mknode (-, R.i, T.nptr)}
R1 {R.s := R1.s}
R {R.s := R.i}
T (E) {T.nptr := E.nptr}
T id {T.nptr := mkleaf (id, id.entry)}
T num {T.nptr := mkleaf (num, num.value)}

The technique to write predictive parsers using recursive


procedures can be modified to include the actions of a
translation scheme.
Use recursive functions instead of recursive procedures
to pass the values of attributes.
For each nonterminal write a recursive function.
The function accepts the values of the imherited
attributes in its formal parameters and returns the values
of the synthesized attributes.
If there are multiple synthesized attributes their values
can be returned in a record or a pointer to a record.

Example
Consider three
nonterminals E, R and T.
Write three recursive
functions.
E and T have no
arguments.
Function E handles the
production:
E T {R.i := T.nptr} R
{E.nptr := R.s}
function E : tree_node;
begin e := R (T) end;

Function Synthesized Inherited


Attributes
Attributes

E.Nptr

(none)

R.S

R>I

T.Nptr

(none)

Function R handles three productions:


R + T {R1.i := mknode (+, R.i, T.nptr)}
R1 {R.s := R1.s}
R - T {R1.i := mknode (-, R.i, T.nptr)}
R1 {R.s := R1.s}
R {R.s := R.i}

function R (I : tree_node) : tree-node;


var nptr, i1 : tree_node;
begin
if lookahead = + then begin
match (+); nptr := T;
i1 := mknode (+, I nptr);
R := R (i1) end
else if lookahead = - then begin
match (-); nptr := T;
i1 := mknode (-, I, nptr);
R := R (i1) end
else R := i end;

S-ar putea să vă placă și