Compiler Design - Chapter 4 - Syntax Directed Translation
Compiler Design - Chapter 4 - Syntax Directed Translation
● Introduction
● Syntax Directed Definitions
● Form of a Syntax-Directed Definition
● Synthesized Attributes
● Dependency Graphs
● Inherited Attributes
● Evaluation Order
● S-Attributed grammars
● L-Attributed grammars
Introduction
● We associate information with a programming construct by
attaching attributes to the grammar symbols representing the
construct.
● Values for attributes are computed by “Semantic Rules”
associated with the grammar productions.
● There are two notations for associating semantic rules with
productions:
– syntax directed definitions, and
– translation schemes.
● Syntax-directed definitions are high-level specifications for
translations.
– They hide many implementation details and free the user from having
to specify explicitly the order in which translation takes place.
Introduction
● Translation schemes indicate the order in which
semantic rules are to be evaluated
– so they allow some implementation details to be shown.
● We use both notations for specifying semantic
checking, particularly the determination of types, and
for generateing intermediate code.
● Conceptually, with both syntax-directed definitioins and
translation schemes:
– we parse the input token stream,
– build the parse tree, and
– then traverse the tree as needed to evaluate the semantic
rules at the parse-tree nodes.
Introduction
Example 2: ...
Synthesized Attributes
Example 2: ...
● To see how the attribute values are computed,
– consider the leftmost bottommost interior node, which
corresponds to the use of the production F digit.
– The semantic rule corresponding to this production, F.val :=
digit.lexval,
● defines the attribute F.val at that node to have the value 3 because
the value of digit.lexval at the child of this node is 3.
– Similarly, at the parent of this F-node, the attribute T.val has
the value 3.
● The attribute values for the other nonterminals is
computed in similar manner.
Inherited Attributes
● An inherited attribute is one whose value at a node in a parse-
tree is defined in terms of attributes at the parent and/or siblings
of that node.
● Inherited attributes are convinient for expressing the dependence
of a programming language construct on the context in which it
appears.
● For example, we can use an inherited attribute to keep track of
whether
– an indentifier appears on the left or right side of an assignment,
– inorder to decide whether the address or the value of the identifier is
needed.
● Let us consider an example that an inherited attribute that
distributes type information to the various identifiers in a
declaration.
Inherited Attributes
Example 3: ...
● The semantic rule L.in := T.type, associated with
production D T L,
– Sets inherited attribute L.in to the type in the
declaration.
– The rules then pass this type down the parse tree
using the inherited attribute L.in.
– Rules associated with the productions for L call
procedure addtype to add the type of each identifier
to its entry in the symbol table (pointed to by
attribute entry).
Inherited Attributes
Example 3: ...
● The following figure shows the annotated parse-
tree for the sentence real id1 , id2, id3.
Inherited Attributes
Example 3: ...
– L-nodes gives the type of the identifiers id1, id2 and
id3.
– The values are determined by computing the value
of the attribute T.type at the left child of the root and
then evaluateing L.in top-down at the three L-nodes
in the right subtree of the root.
– At each L-node we also call the procedure addtype to
insert into the symbol table the fact that the identifier
at the right child of this node has type real.
Dependency Graphs
● If an attribute b at a node in a parse tree depends on attribute
c, then the semantic rule for b at that node must be evaluated
after the semantic rule that defines c.
● The interdependence among the inherited and synthesized
attributes at the nodes in a parse tree can be depicted by a
directed graph called a dependency graph.
● Before constructing a dependency graph for a parse tree,
– we put each semantic rule into the form b := f (c1, c2, ..., ck), by
introducing a dummy synthesized attribute b for each semantic rule
that consists of a procedure call.
● The graph has a node for each attribute and an edge to the
node for b from the node for c if attribute b depends on
attribute c.
Dependency Graphs
Example 4: ...
● Nodes in the dependency graphs are marked by numbers;
these numbers will be used below.
– There is an edge to node 5 for L.in form node 4 for T.type
because the inherited attribute L.in depends on the attribute
T.type according to the semantic rule L.in := T.type for the
production D TL.
– The two downward edges into nodes 7 and 9 arise because L1.in
depends on L.in according to the semantic rule L1.in := L.in for
the production L L1 , id.
– Each of the semantic rules addtype(id.entry, L.in) associated with
the L-productions leads to the creation of a dummy attribute.
– Nodes 6, 8, and 10 are constructed for these dummy attributes.
Evaluation Order
● A topological sort of a directed acyclic graph is any
ordering m1, m2, ..., mk of the nodes of the graph such that
edges go from nodes earlier in the ordering to later nodes;
– that is, if mi mj is an edge from mi to mj, then mi appears
before mj in the ordering.
● Any topological sort of a dependency graph gives a valid
order in which the semantic rules associated with the
nodes in a parse tree can be evaluated.
– That is, in the topological sort, the dependent attribute c1, c2, ...,
ck in a semantic rule b := f (c1, c2, ..., ck) are available at a node
before f is evaluated.
– Evaluation of the semantic rules in this order yields the
translation of the input string.
Evaluation Order
Example 5: ...
a4 := real;
a5 := a4;
addtype(id3.entry, a5)
a7 := a5;
addtype(id2.entry, a7)
a9 := a7;
addtype(id1.entry, a9)
● Evaluating this semantic rules stores the type real
in the symbol-table entry for each identifier.
Evaluation Order
● Several methods have been proposed for evaluating semantic
rules:
1.Parse tree methods: At compile time, these method obtain the
evaluation order from a topological sort of the dependency graph
constructed from the parse tree for each input.
● These method will fail to find an evaluation order only if the dependency graph
for a particular parse tree under consideration has a cycle.
2.Rule based methods: The order in which the attributes associated
with a production are evaluated is predetermined at compiler-
construction time.
● For this method, the dependency graph need not be constructed.
3.Oblivious methods: The evaluation order is chosen without
considering the semantic rules.
● This restricts the class of syntax directed definition that can be used.
● Rule based and oblivious methods need not explicitly construct
the dependency graph at compile time.
Construction of Syntax Tree
● The syntax-directed definitions can be used to
specify the construction of syntax trees and
other graphical representations of language
constructs.
● The use of syntax trees as an intermediate
representation allows translation to be
decoupled from parsing.
● The C compiler constructs a syntax tree for
declarations.
Syntax Tree
● An (abstract) syntax tree is a condensed form of parse
tree useful for representing language constructs.
●
The productions S if B then S1 else S2 might appear in