Mod 1 - Syntax Directed Translation
Mod 1 - Syntax Directed Translation
1
Syntax-Directed Translation
We associate information with the programming language constructs by
attaching attributes to grammar symbols.
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
2
Syntax-Directed Definitions & Translation Schemes
A. Syntax-Directed Definitions:
– High level specifications
B. Translation Schemes:
– Low level specification
– Give a little bit information about implementation details such as order of evaluation of
semantic actions associated with a production rule
3
Syntax-Directed Translation
• Conceptually with both the syntax directed translation and translation
scheme we can
– Parse the input token stream
– Build the parse tree
– Traverse the tree to evaluate the semantic rules at the parse tree nodes.
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.
The value of an attribute at a parse tree node is defined by the semantic rule
associated with a production at that node.
The value of a synthesized attribute at a node is computed from the values of
attributes at the children in that node of the parse tree
The value of an inherited attribute at a node is computed from the values of
attributes at the siblings and parent of that node of the parse tree 5
Syntax-Directed Definitions
Examples:
Synthesized attribute : E→E1+E2 { E.val =E1.val + E2.val}
Inherited attribute :A→XYZ {Y.val = 2 * A.val}
Semantic rule may also have some side effects such as printing a
value.
6
Annotated Parse Tree
b=f(c1,c2,…,cn)
attributes c1,c2,…,cn.
9
Syntax-Directed Definition -- Example
Synthesized attributes depend only on the attributes of children. They are the
most common attribute type.
11
Inherited attributes
12
Inherited attributes
13
Syntax-Directed Definition – Inherited Attributes
14
Annotated parse tree
Input: real p,q,r annotated parse
tree
parse tree D
D
T L T.type=real L1.in=real
15
Evaluating an SDD at the Nodes of a Parse Tree
Using the rules to evaluate all of the attributes at each of the nodes of
the parse tree
A parse tree showing the value(s) of the attribute(s) is called an
annotated parse tree
16
This SDD uses a combination of synthesized and inherited attributes.
A.s (head) is defined in terms of B.i (body nonterminal). Hence, it is
synthesized.
B.i (body non-terminal) is defined in terms of A.s (head). Hence, it is
inherited.
There exists a circular dependency between their evaluations.
In practice, subclasses of SDDs required for our purpose do have an order.
17
Syntax-Directed Definition -- Example
18
Syntax-Directed Definition – Inherited Attributes
19
Annotated parse tree
Input: real p,q,r annotated parse
tree
parse tree D
D
T L T.type=real L1.in=real
20
Annotated Parse Tree for 3*5
21
Evaluation Order for SDD’s
22
A dependency graph shows the flow of information among the
attribute instances in a particular parse tree; an edge from one
attribute instance to another means that the value of the first is needed
to compute the second.
Edges express constraints implied by the semantic rules.
Each attribute is associated to a node
23
Dependency Graph Construction
for i= 1 to n do
24
Dependency Graph Construction
• Example
• Production Semantic Rule
E→E1 + E2 E.val = E1.val + E2.val
E . val
25
Dependency Graph – 3*5
26
Dependency Graph
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)
27
Ordering the Evaluation of Attributes
A dependency graph characterizes the possible order in which we can evaluate
the attributes at various nodes of a parse tree.
If there is an edge from node M to N, then attribute corresponding to M first
be evaluated before evaluating N.
Thus the only allowable orders of evaluation are N1, N2, ..., Nk such that if
sort.
Evaluation Order
• a4=real;
• a5=a4;
• addtype(id3.entry,a5);
• a7=a5;
• addtype(id2.entry,a7);
• a9=a7;
• addtype(id1.entry,a5);
29
Evaluating Semantic Rules
Parse Tree methods
– At compile time evaluation order obtained from the topological sort of
dependency graph.
– Fails if dependency graph has a cycle
Rule Based Methods
– Semantic rules analyzed by hand or specialized tools at compiler construction
time
– Order of evaluation of attributes associated with a production is pre-determined at
compiler construction time
Oblivious Methods
– Evaluation order is chosen without considering the semantic rules.
– Restricts the class of syntax directed definitions that can be implemented.
– If translation takes place during parsing order of evaluation is forced by parsing
method.
30
S-attributed definition
A syntax directed translation that uses synthesized attributes exclusively is said to be
a S-attributed definition.
A parse tree for a S-attributed definition can be annotated by evaluating the semantic
rules for the attributes at each node, bottom up from leaves to the root.
Evaluation is simple using post-order traversal.
postorder(N)
{
for (each child C of N, from the left) postorder(C);
evaluate attributes associated with node N;
}
31
L-Attributed Definitions
Dependency-graph edges can go from left to right, but not from right to
left(hence "L-attributed").
Each attribute must be either Synthesized, or Inherited, but with the rules limited
as follows.
• Suppose that there is a production A X1 X2 • • • Xn, and that there is an
inherited attribute Xi.a computed by a rule associated with this production.
Then the rule may use only:
(a) Inherited attributes associated with the head A.
(b) Either inherited or synthesized attributes associated with the occurrences of symbols X1
(c) Inherited or synthesized attributes associated with this occurrence of Xi itself, but only
in such a way that there are no cycles in a dependency graph formed by the attributes
of this Xi.
Example for L-attributed SDD
33
A Definition which is not L-Attributed
Depth-first traversal
L-attributed definitions are the set of SDDs whose attributes can
be evaluated in a DEPTH-FIRST traversal of the parse tree.
dfvisit( node n ) {
for each child m of n, in left-to-right order, do {
evaluate the inherited attributes of m
dfvisit( m )
}
evaluate the synthesized attributes of n
}
35
Semantic Rules with Controlled Side Effects
may put information into the symbol table, may perform type checking and
– a code generator might enter the type of an identifier into a symbol table.
• Attribute grammars have no side effects and allow any evaluation order
37
Example - incidental side effect
Modify the desk calculator to print a result. Instead of the rule L.val
= E.val, which saves the result in the synthesized attribute L.val
Semantic rules that are executed for their side effects, such as
print(E.val), will be treated as the definitions of dummy synthesized
attributes associated with the head of the production.
The modified SDD produces the same translation under any topological
sort, since the print statement is executed at the end, after the result is
computed into E.val.
38
Productions 4 and 5 have a rule in which a function addType is called
with two arguments:
1. id.entry, a lexical value that points to a symbol-table object, and
2. L.inh, the type being assigned to every identifier on the list.
The function addType properly installs the type L.inh as the type of the
represented identifier.
This side effect, adding the type info to the table, does not affect the
evaluation order.
39
Numbers 1 through 10 represent the nodes of the dependency graph.
Nodes 1, 2, and 3 represent the attribute entry associated with each of
the leaves labeled id.
Nodes 6, 8, and 10 are the dummy attributes that represent the
application of the function addType to a type and one of these entry
values.
40
Applications of Syntax-Directed Translation
Type checking
41
Syntax Trees
Syntax-Tree
– an intermediate representation of the compiler’s input.
42
Parse Tree vs Syntax Tree
43
Syntax Tree-Examples
Expression: Statement:
+ if B then S1 else S2
if - then - else
5 *
B S1 S2
3 4
• Leaves: identifiers or constants • Node’s label indicates what kind
• Internal nodes: labelled with of a statement it is
operations • Children of a node correspond to
• Children: of a node are its the components of the statement
operands
44
Construction of Syntax Trees
Nodes of a syntax tree can be implemented by objects with a suitable
number of fields.
Each object will have an op field that is the label of the node.
The objects will have additional fields as follows:
– If the node is a , an additional field holds the lexical value for the . A
constructor function Leaf(op, val) creates a object. Alternatively, if nodes
are viewed as records, then returns a pointer to a new record for a .
– If the node is an interior node, there are as many additional fields as the
node has children in the syntax tree. A constructor function Node takes
two or more arguments: Node(op,c1,c2,... ,ck) creates an object with first
field op and k additional fields for the k children
45
46
Constructing Syntax Tree for Expressions
Example: a-4+c
47
48
int [2][3]
49
Syntax-Directed Translation Schemes
– semantic actions enclosed between braces {} are inserted within the right sides of
productions.
We can construct an SDT in which each action is placed at the end of the
production and is executed along with the reduction of the body to the head of that
production.
SDT's with all actions at the right ends of the production bodies are called postfix
SDT's.
Parser-Stack Implementation of Postfix SDT's
The attribute(s) of each grammar symbol can be put on the stack in a place
The best plan is to place the attributes along with the grammar symbols in
The three grammar symbols X YZ are on top of the stack; perhaps they are about to be
reduced according to a production like A XYZ.
If one or more attributes are of unbounded size - say, they are character strings - then
it would be better to put a pointer to the attribute's value in the stack record and
store the actual value in some larger, shared storage area that is not part of the stack.
Translation Schemes for S-attributed Definitions
If the attributes are all synthesized, and the actions occur at the ends of the
productions, then we can compute the attributes for the head when we reduce
the body to the head.
If we reduce by a production such as A XYZ, then we have all the attributes
of X, Y, and Z available, at known positions on the stack.
After the action, A and its attributes are at the top of the stack, in the position
of the record for X.
The "trick" for eliminating left recursion is to take two productions replace
them by productions that generate the same strings using a new nonterminal R
(for "remainder") of the first production:
Eliminating Left Recursion - Example
Eliminating Left Recursion - Example
SDT's for L-Attributed Definitions
– Place the action for computing synthesized attribute for the head at the end of the
body of production
Example 1
This example is motivated by languages for typesetting mathematical
formulas.
Eqn is an early example of such a language.
It illustrates how the techniques of compiling can be used in language
processing for applications other than programming languages.
Corresponding to the following four productions, a box can be either
1. Two boxes, connected, with the first, B1, to the left of the other, B2.
2. A box and a subscript box. The second box appears in a smaller size, lower, and
to the right of the first box.
3. A parenthesized box, for grouping of boxes and subscripts.
4. A text string, that is, any string of characters.
The function new generates new labels.
The variables L1 and L2 hold labels that we need in the code.
We use || as the symbol for concatenation of intermediate-code fragments.The value of S.code thus begins with the label L1, then the code for condition C, another label L2, and the code for S1.
S1
Example 2
3. The inherited attribute C.true labels the beginning of the code that must be executed
if C is true.
4. The inherited attribute C.false labels the beginning of the code that must be executed
if C is false.
2. Build the parse tree, add actions, and execute the actions in preorder - L-attributed
definition.
3. Use a recursive-descent parser with one function for each nonterminal - function
for nonterminal A receives the inherited attributes of A as arguments and returns the
synthesized attributes of A.
b) Check that each terminal appears on the input when it is required. We shall assume that
no backtracking is needed, but the extension to recursive- descent parsing with
backtracking can be done by restoring the input position upon failure
c) Preserve, in local variables, the values of all attributes needed to compute inherited
attributes for nonterminals in the body or synthesized attributes for the head nonterminal.
Swhile ( { L1=new();L2=new();C.false=S.next;C.true=L2; }
C ) { S1.next==L1; }
S1 { S.code=label||L1||C.code||label||L2|| S1.code; }
Recursive-descent typesetting of boxes
On-The-Fly Code Generation
The construction of long strings of code that are attribute values – undesirable - time it
could take to copy or move
we can instead incrementally generate pieces of the code into an array or output file
by executing actions in an SDT.
1. There is a main attribute for one or more nonterminals, - e.g.: S.code and C.code
b) The main attributes of nonterminals appear in the rule in the same order as the
nonterminals themselves appear in the production body.
On-the-fly recursive-descent code generation for
while-statements
L-Attributed SDD's and LL Parsing
We can then perform the translation during LL parsing by extending the parser stack
to hold actions and certain data items needed for attribute evaluation.
b) Computes attributes in the same way as a, but makes those attributes be synthesized
attributes of M.
Example
ABC
A{ B.i = f(A.i);} BC
LR parsing stack after reduction of Є to M