0% found this document useful (0 votes)
17 views

Compiler Unit 3 & 4-1

Syntax-directed translation (SDT) is an extension of context-free grammars that embeds program fragments called semantic actions within production bodies. SDT builds a parse tree for an input token stream and then evaluates semantic rules at each node by traversing the tree. Semantic rules can generate code, populate symbol tables, perform checks, and more. Syntax-directed definitions associate attributes and rules with grammar symbols to define dependencies between attributes represented as a graph.

Uploaded by

Bhavya Singla
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views

Compiler Unit 3 & 4-1

Syntax-directed translation (SDT) is an extension of context-free grammars that embeds program fragments called semantic actions within production bodies. SDT builds a parse tree for an input token stream and then evaluates semantic rules at each node by traversing the tree. Semantic rules can generate code, populate symbol tables, perform checks, and more. Syntax-directed definitions associate attributes and rules with grammar symbols to define dependencies between attributes represented as a graph.

Uploaded by

Bhavya Singla
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 47

COMPILER CONSTRUCTION

UNIT-3
(Syntax-directed Translations)
Syntax-directed translation (SDT)
§ an extension of context-free grammar
(CFG) which acts as a notational
framework for the generation of
intermediate code.
§ It embeds program fragments (called
semantic actions) within the production
bodies.
§ For example,

2
Syntax-directed translation (SDT)
§ In SDT, by convention, we use curly
braces to enclose semantic actions.
§ In syntax-directed translation, we pass the
token stream as input, build the parse tree
for the input token stream, and then
evaluate the semantic rules at the nodes
of parse tree by traversing the parse tree.

Conceptual View of Syntax Directed Translation

3
Syntax-directed translation (SDT)
§ The evaluation of semantic rules by
syntax-directed translation may:
• generate an intermediate code
• save information in the symbol table
• perform semantic checking
• issue error messages, or
• perform some other activities.

4
Syntax-directed definition
§ It is a context-free grammar together with
attributes and rules.
§ Attributes are associated with grammar symbols
and rules are associated with productions.
§ X.a : denote the value of a at a particular parse-
tree node labeled X.
§ Attributes may be of any kind: numbers, types,
table references or strings.
§ Semantic rules are used to set up dependencies
between attributes that will be represented
by a graph. 5
Synthesized Attributes
§ A synthesized attribute for a non-terminal A at a
parse tree node I is defined by a semantic rule
associated with the production at I and the
production must have A as its head.
§ A synthesized attribute at node I has its value
defined only in terms of attribute values of its
child nodes and I itself.

6
Synthesized Attributes
§ For example, consider the grammar for a desk
calculator:

§ In SDD, each non-terminal has a single


synthesized attribute, called “val”, and digit has a
synthesized attribute “lexval” (the lexical value
for the digit which is an integer value returned by
the lexical analyzer). 7
Synthesized Attributes
§ So, semantic rules for this grammar can be
written as given as:

8
Synthesized Attributes
§ Since the entire attribute values of the symbols
as head are defined in terms of attributes at their
child nodes, it means all attributes involved are
synthesized attributes and the corresponding
SDD is known as S-attributed definition.

9
Inherited Attributes
§ An inherited attribute for a non-terminal A at a
parse tree node I is defined by a semantic rule
associated with the production at the parent of I,
and the production must have A as a symbol in
its body.
§ The value of an inherited attribute at node I can
only be defined in terms of attribute
values of I’s parents, I’s siblings, and I itself.
§ Inherited attributes are convenient for expressing
the dependency of a programming language
construct on the context on which it appears.
10
Inherited Attributes
§ An inherited attribute can be used to keep track
of whether an identifier appears on the left side
or right side of an assignment operator in order
to determine whether the address or the value of
the identifier is required.
§ For example, consider the following grammar:

11
Inherited Attributes
§ The syntax-directed definitions that use inherited
attributes can be written as:

12
Inherited Attributes
§ The syntax-directed definitions that use inherited
attributes can be written as:

§ The semantic rule B.inh = A.type sets inherited


attributes B.inh to the type in the declaration.
13
Evaluation orders for SDD’s
§ A dependency graph is used to determine the order of
computation of attributes
§ Dependency graph
• For each parse tree node, the parse tree has a node
for each attribute associated with that node
• If a semantic rule defines the value of synthesized
attribute A.b in terms of the value of X.c then the
dependency graph has an edge from X.c to A.b
• If a semantic rule defines the value of inherited
attribute B.c in terms of the value of X.a then the
dependency graph has an edge from X.c to B.c

14
Ordering the evaluation of attributes
§ If dependency graph has an edge from M to N
then M must be evaluated before the attribute of
N
§ Thus the only allowable orders of evaluation are
those sequence of nodes N1,N2,…,Nk such that
if there is an edge from Ni to Nj then i<j
§ Such an ordering is called a topological sort of a
graph

15
S-Attributed definitions
§ An SDD is S-attributed if every attribute is
synthesized

§ We can have a post-order traversal of parse-tree


to evaluate attributes in S-attributed definitions

§ S-Attributed definitions can be implemented


during bottom-up parsing without the need to
explicitly create parse trees

16
L-Attributed definitions
§ A SDD is L-Attributed if the edges in
dependency graph goes from Left to Right but
not from Right to Left.

§ More precisely, each attribute must be either


§ Synthesized
§ Inherited

17
L-Attributed definitions
§ If there is a production A->X1X2…Xn and there is
an inherited attribute Xi.a computed by a rule
associated with this production, then the rule may
only use:
1. Inherited attributes associated with the head
A
2. Either inherited or synthesized attributes
associated with the occurrences of symbols
X1,X2,…,Xi-1 located to the left of Xi
3. Inherited or synthesized attributes associated
with this occurrence of Xi itself, but in such a
way that there is no cycle in the graph.
18
Annotated Parse Tree
§ An annotated parse tree is a parse tree that
displays the values of the attributes at each
node.
§ It is used to visualize the SDD specified
translations.
§ To construct an annotated parse tree, first the
SDD rules are applied to construct a parse tree
and then the same SDD rules are applied to
evaluate the attributes at each node of the parse
tree.

19
Annotated Parse Tree
§ For example, an annotated parse tree for an
expression 3 + 5 * 2 by considering the following
productions and semantic rules:

20
Annotated Parse Tree

21
Types of Attributes
§ Inherited attributes: An
attribute is inherited at a
parse tree node if its
value is computed at a
parent or sibling node.

§ Synthesized attributes:
An attribute is
synthesized at a parse
tree node if its value is
computed at that node
or one of its children.

22
Dependency Graph
§ A dependency graph represents the flow of
information between the attribute instances in a
parse tree.
§ It is used to depict the interdependencies among
the inherited and synthesized attributes at
the nodes in a parse tree.
§ When the value of an attribute needs to compute
value of another attribute, then an edge from first
attribute instance to another is created to
indicate the dependency among the
attribute instances.
23
Dependency Graph
§ To construct a dependency graph for a parse
tree, we first make each semantic rule in the
form x: = f(y1,y2,y3,...,yk)
by introducing a dummy synthesized attribute x
for each semantic rule that consists of a
procedure call.
§ We then create a node for each attribute in the
graph and an edge from node y to the node x, if
attribute x depends on attribute y.

24
Dependency Graph Example
§ Construct a dependency graph for the input
string 7 + 8, by considering the following
grammar:

25
Dependency Graph Example
§ A synthesized attribute val is used for each of the
non-terminals A and B and a synthesized
attribute lexval is used for the terminal digit.

§ The non-terminal A¢ has two attributes, an


inherited attribute inh and a synthesized attribute
syn.

26
Dependency Graph Example
§ Syntax Directed Definition for the given grammar:

27
Dependency Graph Example
§ Annotated Parse Tree for 7 + 8:

28
Dependency Graph Example
§ We use this parse tree to construct a
dependency graph:

29
Symbol Tables
A symbol table is a major data structure used in a
compiler:
vAssociates attributes with identifiers used in a
program
vFor instance, a type attribute is usually associated
with each identifier
vA symbol table is a necessary component
Ø Definition (declaration) of identifiers appears once in a
program
Ø Use of identifiers may appear in many places of the
program text

30
Symbol Tables
• Identifiers and attributes are entered by the analysis
phases:
v When processing a definition (declaration) of
an identifier
v In simple languages with only global variables
and implicit declarations:
Ø The scanner can enter an identifier into a symbol
table if it is not already there
v In block-structured languages with scopes and
explicit declarations:
Ø The parser and/or semantic analyzer enter
identifiers and corresponding attributes
31
Symbol Tables
• Symbol table information is used by the analysis and
synthesis phases:
v To verify that used identifiers have been
defined (declared)
v To verify that expressions and assignments are
semantically correct - type checking
v To generate intermediate or target code

32
Symbol Table Interface
•The basic operations defined on a symbol table
include:
* allocate - to allocate a new empty symbol table
* free - to remove all entries and free the storage of a
symbol table
* insert - to insert a name in a symbol table and return a
pointer to its entry
* lookup - to search for a name and return a pointer to
its entry
* set_attribute - to associate an attribute with a given
entry
* get_attribute - to get an attribute associated with a
given entry
33
Basic Implementation Techniques
First consideration is how to insert and lookup names

Variety of implementation techniques


Unordered List
vSimplest to implement
vImplemented as an array or a linked list
vLinked list can grow dynamically - alleviates
problem of a fixed size array
vInsertion is fast O(1), but lookup is slow for large
tables - O(n) on average

34
Basic Implementation Techniques
Ordered List
vIf an array is sorted, it can be searched using
binary search - O(log2 n)
vInsertion into a sorted array is expensive -
O(n) on average
vUseful when set of names is known in
advance - table of reserved words
Binary Search Tree
vCan grow dynamically
vInsertion and lookup are O(log2 n) on average

35
Basic Implementation Techniques
Hash Tables and Hash Functions
vA hash table is an array with index range: 0 to TableSize –1
vMost commonly used data structure to implement symbol tables
vInsertion and lookup can be made very fast - 0(1)
vA hash function maps an identifier name into a table index
* A hash function, h(name), should depend solely on name
* h(name) should be computed quickly
*h should be uniform and randomizing in distributing names
* All table indices should be mapped with equal probability
* Similar names should not cluster to the same table index
36
Semantic analysis motivation
n Syntactically correct programs may still
contain errors
n Lexical analysis does not distinguish between
different variable names (same ID token)
n Syntax analysis does not correlate variable
declaration with variable use, does not keep
track of types

int a; int a;
a = “hello”; b = 1;
Assigning
undeclared
Assigning variable
wrong type 37
Goals of semantic analysis
n Check “correct” use of programming
constructs
n Provide information for subsequent phases
n Correctness specified by semantic rules
v Scope rules

v Type-checking rules

v Specific rules

n Semantic analysis ensures only partial


correctness of programs
v Runtime checks (pointer dereferencing,
array access) may affect

38
Example of semantic rules
n A variable must be declared before used
n A variable should not be declared multiple times
n A variable should be initialized before used
n Non-void method should contain return statement
along all execution paths
n break/continue statements allowed only in loops
n this keyword cannot be used in static method
n main method should have specific signature

n Type rules are important class of semantic rules


n In an assignment statement, the variable and
assigned expression must have the same type
n In a condition, test expression must have boolean
type
39
Scope and Visibility
n Scope (visibility) of identifier: portion of
program where identifier can be referred
to
n Lexical scope: textual region in the
program
n Statement block
n Method body
n Class body
n Module / package / file
n Whole program (multiple modules) 40
Symbol Table
n Captures scope information

n Each entry in symbol table contains


n The name of an identifier
n Its kind (variable/method/field…)
n Type (int/float/char…)
n Additional properties, e.g, final, public

n One symbol table for each scope

41
Scope Nesting
Scope nesting mirrored in hierarchy of symbol tables

Symbol Kind Type Properties Global


names of all classes

Symbol Kind Type Properties Class


fields and methods

Symbol Kind Type Properties Method


formals + locals

Symbol Kind Type Properties Block


variables defined in block

42
Scope Example
class Foo {
int value;
int test() {
int b = 3; scope of
return value + b; local variable b
}
void setValue(int c) { scope of
value = c; field value
{ int d = c; scope of
c = c + d; local variable scope of formal
value = c; in statement parameter c scope of
} block d method test
}
}

class Bar extends Foo {


int value;
void setValue(int c) {
value = c; scope of value
test(); scope of c
}
43
}
Symbol Table creation


(Foo)
Symbol Kind Type Properties
value field int …
test method -> int
setValue method int -> void

(Test) (setValue)
Symbol Kind Type Properties Symbol Kind Type Properties
b var int … c var int …

(block1)
Symbol Kind Type Properties
d var int …

44
Checking scope rules
(Foo)
Symbol Kind Type Properties
value field int …
test method -> int
setValue method int -> void

(Test) (setValue)
Symbol Kind Type Properties Symbol Kind Type Properties
b var int … c var int …

void setValue(int c) {
(block1)
value = c;
{ int d = c; lookup(value) Symbol Kind Type Properties
c = c + d; d var int …
value = c;
}
}
45
Catching semantic errors
Error !
(Foo)
Symbol Kind Type Properties
value field int …
test method -> int
setValue method int -> void

(Test) (setValue)
Symbol Kind Type Properties Symbol Kind Type Properties
b var int … c var int …

void setValue(int c)
{ (block1)

value = c; lookup(myValue) Symbol Kind Type Properties

{ int d = c; d var int …

c = c + d;
myValue = c;
}
} 46
Symbol table construction
via AST traversal globals
Symbol kind
root
foo class

ClassDecl foo
name=foo Symbol kind

test method
setValue method

MethodDecl MethodDecl
name=test name=setValue test setValue
Symbol Symbol

b var c var

block1
VarDecl Stmt Stmt Block Symbol

id=b
d var

VarDecl Stmt Stmt


id=d
47
AST: Abstract syntax tree

You might also like