Вы находитесь на странице: 1из 52

Topic: Syntax Directed

Translations

UNIT IV

Syntax-Directed Translations
Translation of languages guided by CFGs
Information associated with programming
language constructs
Attributes attached to grammar symbols
Values of attributes computed by semantic rules
associated with grammar productions

Two notations for associating semantic rules


Syntax-directed definitions
Translation schemes

Semantic Rules
Semantic rules perform various activities:
Generation of code
Save information in a symbol table
Issue error messages
Other activities

Output of semantic rules is the translation


of the token stream

Conceptual View

Implementations do not need to follow outline


literally
Many special cases can be implemented in a
single pass

SYNTAX DIRECTED
DEFINATIONS
A syntax directed defination is a
generailization of a context free grammar in
which each grammer symbol has an
associated set of attributes, partitioned into
two subsets called Synthesized attributes
and inherited attributes.

Attributes
Each grammar symbol (node in parse tree) has
attributes attached to it ex: astring,a number,a type,a
memory location etc.
Values of a Synthesized attributes at a node is comuted
from the values of attributes at the children of that node
in the parse tree.
Values of a Inherited attributes at a node is comuted
from the values of attributes at the siblings and parent of
that node.
A dependency graph represents dependencies between
attributes
A parse tree showing the values of attributes at each
node is an annotated parse tree

Semantic Rules
Each semantic rule for production A -> has the form
b := f(c1, c2, , ck)
f is a function
b may be a synthesized attribute of A or
b may be an inherited attribute of one of the grammar symbol on
the right side of the production
c1, c2, , ck are attributes belonging to grammar symbols of
production

An attribute grammar is one in which the functions in


semantic rule cannot have side effects
NOTE: a semantic rule may have side effects ex: printing a
value or updating a global variable.

S-attributed Definitions
Synthesized attributes are used
extensively in practice
S-attributed definition: A syntax-directed
definition using only synthesized attributes
Parse tree can be annotated by evaluation
nodes during a single bottom up pass

S-attributed Definition Example


Desk calculator
Production

Semantic Rules

L E n

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

Annotated Parse Tree Example

NOTE
In a syntax directed definations,terminals
are assumed to have
Synthesized attributes only,as the
definations does not provide any semantic
rules for terminals.values for attributes of
terminals are usually supplied by the
lexical analyser.Start symbol is assumed
not to have any inherited attribute
otherwise stated.

Inherited Attributes
Inherited Attributes:
Value at a node in a parse tree depends
on attributes of parent and/or siblings
Convenient for expressing dependencies of
programming language constructs on context

It is always possible to avoid inherited


attributes, but they are often convenient

Inherited Attributes Example


Production

Semantic Rules

D T L

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 Inherited Attributes

Dependency Graphs
Dependency graph:
Depicts interdependencies among
synthesized and inherited attributes
Includes dummy nodes for procedure calls

Numbered with a topological sort


If mi mj is an edge from mi to mj, then mi
appears before mj in the ordering
Gives valid order to evaluate semantic rules

Creating a Dependency Graph


for each node n in parse tree
for each attribute a of grammar symbol at n
construct a node in dependency graph for a
for each node n in parse tree
for each semantic rule b := f(c1, c2, , ck)
associated with production used at n
for i := 1 to k
construct edge from node for ci to node for b

Example(inherited attribute)

Syntax Trees
(Abstract) Syntax Trees
Condensed form of parse tree
Useful for representing language constructs
Operators and keywords appear as internal
nodes

Syntax-directed translation can be based


on syntax trees as well as parse trees

Syntax Tree Examples

Implementing Syntax Trees


Each node can be represented by a record
with several fields
Example: node representing an operator
used in an expression:
One field indicates the operator and others
point to records for nodes representing operands
The operator is referred to as the label of
the node

If being used for translation, records can


have additional fields for attributes

Syntax Trees for Expressions


Functions will create nodes for the syntax tree
mknode (op, left, right) creates an
operator node with label op and pointers left and
right which point to operand nodes
mkleaf(id, entry) creates an identifier node
with label id and a pointer to the appropriate symbol
table entry
Mkleaf(num, val) creates a number node with
label num and value val

Each function returns pointer to created node

Example: a - 4 + c

p1
P2
p3
p4
p5

:=
:=
:=
:=
:=

mkleaf(id, pa);
mkleaf(num, 4);
mknode('-', p1, p2);
mkleaf(id, pc);
mknode('+', p3, p4);

Constructing Trees for Expressions


Production

Semantic Rules

E E1 + T

E.np := mknode('+', E1.np, T.np)

E E1 T

E.np := mknode('-', E1.np, T.np)

E T

E.np := T.np

T (E)

T.np := E.np

T id

T.np := mkleaf(id, id.entry)

T num

T.np := mkleaf(num, value)

Directed Acyclic Graphs


Called a dag for short
Convenient for representing expressions
As with syntax trees:
Every subexpression will be represented by
a node
Interior nodes represent operators, children
represent operands

Unlike syntax trees, nodes may have


more than one parent
Can be created automatically (discussed in
textbook)

Example: a

+ a * (b c) + (b c) * d

Two sub-classes of the syntax-directed definitions:

S-Attributed Definitions: only


synthesized attributes used in the syntaxdirected 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 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

Bottom-Up Evaluation of SAttributed 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.

Bottom-Up Evaluation Example (1)

Production

Code Fragment

(1) L E \n

Print(val[top])

(2) E E1 + t

val[ntop] := val[top-2] + val[top]

(3) E T
(4) T T1 * F

val[ntop] := val[top-2] * val[top]

(5) T F
(6) F (E)
(7) F digit

val[ntop] := val[top-1]

Bottom-Up Evaluation Example (2)


Input

State

Val

3*5+4\n

---

---

Rule

Input

State

Val

Rule

+4\n E

*5+4\n 3

*5+4\n F

(7)

*5+4\n T

(5)

4\n E+

15

(3)

15_

\n E+4

15_4

3_

\n E+F

15_4

(7)

+4\n T*5

3_5

\n E+T

15_4

(5)

+4\n T*F

3_5

(7)

\n E

19

(2)

+4\n T

3_5

(4)

5+4\n T*

E\n

19_

19

(1)

Evaluating Attributes
Possible evaluation orders depend on
order that nodes are created by parser
Depth-first search is very common
evaluation order
L-attributed definitions use this technique
Information appears to flow left-to-right
Can handle all synthesized and some
inherited attributes

Depth-First Evaluation
procedure dfvisit(n: node);
begin
for each child m of n, from left to right
begin
evaluate inherited attributes of m
dfvisit(m)
end;
evaluate synthesized attributes of n
end

L-attributed Definitions
A syntax-directed definition is L-attributed:
If each inherited attribute of Xj, for production
A X1X2Xn (1 <= j <= n), depends on:
X1, X2, , Xj-1 to the left of XJ

in the production
The inherited attributes of A

Any synthesized attribute is OK

All S-attributed definitions are, by this


definition, L-attributed

Non-L-Attributed Example
Production

Semantic Rule
L.i := l(A.i)

A L M

M.i := m(L.s)
A.s := f(M.s)
R.i := r(A.i)

A Q R

Q.i := q(R.s)
A.s := f(q.s)

Translation Schemes
Semantic actions are inserted within the right
side of productions
Placement indicates order of evaluation
If we are dealing with both inherited and
synthesized attributes:
Each inherited attribute must be computed by action
before symbol appears on right side of production
No action may refer to a synthesized attribute of a
symbol to the right of the action
Any synthesized attribute of nonterminal on left must
be computed after computing all referenced attributes

Typesetting Example (1)


Production
S B

B B1 B2

B B1 sub B2
B text

Semantic Rules
B.ps := 10
S.ht := B.ht
B1.ps := B.ps

B2.ps := B.ps
B.ht := max(B1.ht, B2.ht)
B1.ps := B.ps
B2.ps := shrink(B.ps)
B.ht := disp(B1.ht, B2.ht)
B.ht := text.h * B.ps

Typesetting Example (2)


S

{B.ps := 10}
{S.ht := B.ht}

B1
B2

{B1.ps := B.ps}
{B2.ps := B.ps}
{B.ht := max(B1.ht, B2.ht)}

B
B1
sub
B2

{B1.ps := B.ps}
{B2.ps := shrink(B.ps)}
{B.ht := disp(B1.ht, B2.ht)}

B text {B.ht := text.h * B.ps}

Eliminating Left Recursion


Have seen simple and general solution for CFGs
Now we must take semantic actions and
attributes into account as well
First we will examine synthesized attributes
A A1 Y {A.a := g(A1.a, Y.y)
A X {A.a := f(X.x)}

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.s := R.i}

Evaluating Expressions Example


E
E
E
T
T

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


E1 T {E.val := E1.val T.val}
T {E.val := T.val}
(E) {T.val := E.val}
num {T.val := num.val}

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


R + T {R1.i := R.i + T.val} R1 {R.s := R1.s}
| - T {R1.i := R.i + T.val} R1 {R.s := R1.s}
| {R.s := R.i}
T (E) {T.val := E.val}
T num {T.val := num.val}

Creating Syntax Tree Example


E
E
E
T
T
T

E
R
R
R
T
T
T

E1 + T {E.np := mknode('+', E1.np, T.np)}


E1 T {E.np := mknode('-', E1.np, T.np)}
T {E.np := T.np}
(E) {T.np := E.np}
id {T.np := mkleaf(id, id.entry)}
num {T.np := mkleaf(num, value)}

T {R.i := T.np} R {E.np R.S}


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

Designing a Predictive Parser


LL(1) Grammars can be implemented using
relatively simple top-down parsing techniques
For each nonterminal A, construct function:
Parameter for each inherited attribute
Returns synthesized attribute (or attributes)

Code decides which production to use based on


next input symbol
Right side of production considered left to right:
For token X with synthesized attribute x, store X.x
For nonterminal B, generate c := B(b1,b2,,bk)
with call to function for B
Copy other actions into the parser

Syntax Tree Code Example


function R(i:syntax_tree_node):syntax_tree_node;
var np, i1, s1, s: syntax_tree_node;
begin
if lookahead = '+' then begin
/* Case for R + T R */
match('+');
np := T;
i1 := mknode('+', i, np);
s1 := R(il)
s := s1;
end
else if lookahead = '-' then begin
/* Case for R - T R */

else s := i; /* Case for R */


return s
end

Generalized Bottom-Up Evaluation


Can handle:
All synthesized attributes
All L-attributed definitions based on an LL(1)
grammar

Can handle some L-attributed definitions


based on LR(1) grammars
Relies on use of copy rules and markers

Copy Rules
Consider reduction: A X Y
Suppose X has synthesized attribute X.s
X.s will already be on stack before any
reductions take place in subtree below Y
Therefore, this value can be inherited by Y
Define attribute Y.i using a copy rule:
Y.i = X.s

Copy Rule Example (1)

D
T
T
L
L

T {L.in := T.type} L
int {T.type := integer}
real {T.type := real}
{L1.in := L.in} L1, id {addtype(id.entry, L.in)}
id {addtype(id.entry, L.in)}

Copy Rule Example (2)


Input
real p, q, r

State
---

Production Used

p, q, r real
p, q, r T

T real

,q, r T id
,q, r T L

L id

q, r T L ,
, r T L , id
, r T L

L L , id

r T L ,
T L , id
T L

L L , id

D T L

Copy Rule Example (3)


Production
D T L ;
T int

Code Fragment
val[ntop] := integer

T real
L L, id
L id

val[ntop] := real
addtype(val[top], val[top-3])
addtype(val[top], val[top-1])

Limitation of Copy Rules


Production
S aAC

Semantic Rules
C.i := A.s

S bABC

C.i := A.s

C c

C.s := g(C.i)

Reaching into stack for an attribute value only


works if the position of the value is predictable
Here, C inherits synthesized attribute A.s
There may or may not be a B between A and C
C.i may be in either val[top-1] or val[top-2]

Markers
Marker nonterminals generating are
inserted into the grammar
Each embedded action is replaced by a
marker with the action attached
Actions in the transformed translation
scheme terminate productions
Markers can often be used to move all
actions to the right side of productions

Markers Example
E T R
R + T {print('+')} R | - T {print('-')} R |
T num {print(num.val)}

E
R
M
N
T

T R
+ T M R | - T N R |
{print('+')}
{print('+')}
num {print(num.val)}

Using Markers and Copy Rules


Production
S aAC
S bABC
C c

Semantic Rules
C.i := A.s

Production
S aAC

Semantic Rules
C.i := A.s

S bABMC
M
C c

M.i := A.s; C.i := M.s


M.s := M.i
C.s := g(C.i)

C.i := A.s
C.s := g(C.i)

Using Markers for Other Rules


Production
S aAC

Semantic Rules
C.i := f(A.s)

Production
S aANC

Semantic Rules
N.i := A.s; C.i := N.s

N.s := f(N.i)

Avoiding Inherited Attributes


It is sometimes possible to avoid inherited
attributes by rewriting the underlying grammar
The goal is to replace inherited attributes with
synthesized attributes
D L : T
T integer | real
L L, id | id

D id L
L , id L | : T
T integer | real

Вам также может понравиться