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 ExampleDesk 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, idL1.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 afor 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 := mkleaf(id, pa);P2 := mkleaf(num, 4);p3 := mknode('-', p1, p2);p4 := mkleaf(id, pc);p5 := 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 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 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 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.
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) val[ntop] := val[top-1]
(7) F digit
Bottom-Up Evaluation Example (2)
Input State Val Rule
3*5+4\n --- ---
*5+4\n 3 3
*5+4\n F 3 (7)
*5+4\n T 3 (5)
5+4\n T* 3_
+4\n T*5 3_5
+4\n T*F 3_5 (7)
+4\n T 3_5 (4)
…
Input State Val Rule
…
+4\n E 15 (3)
4\n E+ 15_
\n E+4 15_4
\n E+F 15_4 (7)
\n E+T 15_4 (5)
\n E 19 (2)
E\n 19_
L 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 nend
L-attributed Definitions
• A syntax-directed definition is L-attributed:– If each inherited attribute of Xj, for production A X1X2…Xn (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
A L M
L.i := l(A.i)
M.i := m(L.s)
A.s := f(M.s)
A Q R
R.i := r(A.i)
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 Semantic Rules
S BB.ps := 10
S.ht := B.ht
B 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
Typesetting Example (2)
S {B.ps := 10}B {S.ht := B.ht}
B {B1.ps := B.ps}B1 {B2.ps := B.ps}B2 {B.ht := max(B1.ht, B2.ht)}
B {B1.ps := B.ps}B1
sub {B2.ps := shrink(B.ps)}B2 {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 E1 + T {E.val := E1.val + T.val}E E1 – T {E.val := E1.val – T.val}E T {E.val := T.val}T (E) {T.val := E.val}T 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 ExampleE 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)}
E T {R.i := T.np} R {E.np R.S}R + T {R1.i := mknode('+', R.i, T.np)} R1 {R.s := R1.s}R - T {R1.i := mknode(‘-', R.i, T.np)} R1 {R.s := R1.s}R ε {R.s := R.i}T (E) {T.np := E.np}T id {T.np := mkleaf(id, id.entry)}T 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 Examplefunction 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;
endelse 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 {L.in := T.type} LT int {T.type := integer}T real {T.type := real}L {L1.in := L.in} L1, id {addtype(id.entry, L.in)}L id {addtype(id.entry, L.in)}
Copy Rule Example (2)
Input State Production Used
real p, q, r ---
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 D T L
Copy Rule Example (3)
Production Code Fragment
D T L ;
T int val[ntop] := integer
T real val[ntop] := real
L L, id addtype(val[top], val[top-3])
L id addtype(val[top], val[top-1])
Limitation of Copy Rules
• 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]
Production Semantic Rules
S aAC C.i := A.s
S bABC C.i := A.s
C c C.s := g(C.i)
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 RR + T {print('+')} R | - T {print('-')} R | εT num {print(num.val)}
E T RR + T M R | - T N R | εM ε {print('+')}N ε {print('+')}T num {print(num.val)}
Using Markers and Copy Rules
Production Semantic Rules
S aAC C.i := A.s
S bABC C.i := A.s
C c C.s := g(C.i)
Production Semantic Rules
S aAC C.i := A.s
S bABMC M.i := A.s; C.i := M.s
M ε M.s := M.i
C c C.s := g(C.i)
Using Markers for Other Rules
Production Semantic Rules
S aAC C.i := f(A.s)
Production Semantic Rules
S aANC N.i := A.s; C.i := N.s
N ε 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 : TT integer | realL L, id | id
D id LL , id L | : TT integer | real
Top Related