0% found this document useful (0 votes)
53 views46 pages

3rd Phase Semantic Analysis

Uploaded by

mdsaif804403
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
53 views46 pages

3rd Phase Semantic Analysis

Uploaded by

mdsaif804403
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 46

Semantic Analysis

• Ultimate goal: generate machine code.


• Before we generate code, we must collect information about the program:
• Front end
– scanning (recognizing words) CHECK
– parsing (recognizing syntax) CHECK
– semantic analysis (recognizing meaning)
• There are issues deeper than structure. Consider:

int func (int x, int y);


int main () {
int list[5], i, j;
char *str; This code is syntactically
j = 10 + 'b'; correct, but will not work.
str = 8; What problems are there?
m = func("aa", j, list[12]);
return 0;
}
Languages are described by their syntaxes and
semantics

What is the meaning of Syntax?


It means the form or structure of the expressions, statements and program
units. The Syntax rules of a language specify which strings of characters
from the language’s alphabet are in the language.

What is the meaning of Semantics?


It means the meaning of the expressions, statements, and program units.
Semantic analysis

• Collecting type information may involve "computations"


– What is the type of x+y given the types of x and y?
• Tool: attribute grammars
– CFG
– Each grammar symbol has associated attributes
– The grammar is augmented by rules (semantic actions) that specify how the
values of attributes are computed from other attributes.
– The process of using semantic actions to evaluate attributes is called syntax-
directed translation.
– Examples:
• Grammar of declarations.
• Grammar of signed binary numbers.
Semantic analysis

• In Syntax Directed Definition, two attributes are used one is


Synthesized attribute and another is inherited attribute. An
attribute is said to be Synthesized attribute if its parse tree node
value is determined by the attribute value at child nodes whereas
An attribute is said to be Inherited attribute if its parse tree node
value is determined by the attribute value at parent and/or siblings
node.
Semantic analysis
• Syntax Directed Definitions (SDD) are formal methods of attaching
semantic information to the syntactic structure of a programming
language. SDDs improve the means of context-free high-level by
instances, adding a semantic rule set for every production of the grammar.
The rules described in these definitions state how to derive values such as
types, memory locations, or fragments of code from the structure of an
input object.

• Syntax Directed Translation (SDT) is the action of translating a high-


level language program into an intermediate language or machine
language according to the semantic rules imposed by SDDs. Semantic
actions in SDT, act in coordination with the parsing process in order to
provide the translation of the input code. These actions are declarative and
they are triggered during the parsing phase of the message to yield the
result.
Semantic analysis

• Syntax Directed Translation (SDT) The semantic actions are normally


included in the grammatical rules and can be either performed
synchronously or asynchronously with the parsing actions. Integrated
development systems such as SDT offer tools to compilers such as code
generation, lexical analysis, evaluation of expressions, definition,
grammar, and checking of types among other services.
• What are Annotated Parse Trees?
The parse tree containing the values of attributes at each node for given
input string is called annotated or decorated parse tree.

1. Features of Annotated Parse Trees


2. High level specification
3. Hides implementation details
4. Explicit order of evaluation is not specified
Synthesized and Inherited Attributes

An attribute is said to be:

Synthesized if its value at a parse-tree node is determined


from the attribute values at the children of the node.

Inherited if its value at a parse-tree node is determined by


the parent (by enforcing the parent’s semantic rules)
Synthesized and Inherited Attributes

• An attribute is a characteristic that determines the value of a grammatical


symbol. Semantic functions, also referred to as attribute computation
functions, are functions connected to grammar productions that compute the
values of attributes. Predicate functions are functions that state a specific
grammar's static semantic rules as well as portions of its syntax.

• When parsing values from their domain, attributes can be applied to them and
evaluated when conditions are met. The attributes can be roughly separated
into two groups:
1. Synthesized Attributes
2. Inherited Attributes
depending on how they receive their values.
Synthesized and Inherited Attributes
1. Synthesized Attributes

An attribute that lies on the left-hand side of a production is called a


synthesized attribute. These attributes derive their values from the child
nodes. Let's use the example of the language P->QR. If an attribute P
depends on attribute Q or R, it will be a synthesized attribute.

Example:
G → PQRS
Here, G is referred to be a synthesized attribute if it receives values from
its sibling nodes which are P, Q, R, and S.

G→G*P+Q
In this example, the parent node G takes its values from all the child nodes,
which are P and Q.
Synthesized and Inherited Attributes
2. Inherited Attributes

An inherited attribute belongs to a nonterminal on the right side of a


production. These characteristics borrow values from their siblings or
parents. As long as the production at the parent has the non-terminal in its
body, a semantic rule connected to the production at the parent defines
them.

Inherited attributes are useful when the parse tree's structure differs from
the source program's abstract syntax tree. Since they depend on both left
and right siblings, they cannot be evaluated by a pre-order traversal of the
parse tree.
Synthesized and Inherited Attributes

Example 1

G → PQRS
Here, G, Q, R, and S can provide values for P. G, P, R, and S can all
provide values for Q. G, P, Q, and S are sources of values for R. In the end,
G, P, Q, and R are input sources for S.

Example 2

E→E+S+T
In the above example, the value of S can be determined by E and T.
Similarly, the value of T can be determined with the help of E and S.
Synthesized Attributes
Example: Consider the following grammar

S --> E
E --> E1 + T
E --> T
T --> T1 * F
T --> F
F --> digit
The SDD for the above grammar can be written as follow
Synthesized Attributes
Let us assume an input string 4 * 5 + 6 for computing synthesized
attributes. The annotated parse tree for the input string is

For computation of attributes we start from leftmost


bottom node. The rule F –> digit is used to reduce
digit to F and the value of digit is obtained from
lexical analyzer which becomes value of F i.e. from
semantic action F.val = digit.lexval. Hence, F.val = 4
and since T is parent node of F so, we get T.val = 4
from semantic action T.val = F.val. Then, for T –> T1
* F production, the corresponding semantic action is
T.val = T1.val * F.val . Hence, T.val = 4 * 5 = 20
Inherited Attributes

A --> BCD { C.in = A.in, C.type = B.type }

Computation of Inherited Attributes


• Construct the SDD using semantic actions.
• The annotated parse tree is generated and attribute values are computed in top down manner.
Example: Consider the following grammar

S --> T L
T --> int
T --> float
T --> double
L --> L1, id
L --> id
Inherited Attributes

The SDD for the above grammar can be written as follow


Let us assume an input string int a, c for computing inherited attributes.
The annotated parse tree for the input string is
Inherited Attributes
The value of L nodes is obtained from T.type (sibling) which is basically
lexical value obtained as int, float or double. Then L node gives type of
identifiers a and c. The computation of type is done in top down manner or
preorder traversal. Using function Enter_type the type of identifiers a and c is
inserted in symbol table at corresponding id.entry.
Synthesized and Inherited Attributes

Example:
1. Let SDT be S-> BC {B.val = C.val}
this SDT is which attributed.

2. Consider the SDT given below


E-> E+E | E*E | id {print(+), print(*), print(id.name)}
The above SDT is…..

3. Consider the following grammar


L-> En
E->E1+T | T
T-> T1 * F | F
F-> (E) | digit
Synthesized and Inherited Attributes

Example:

3. Consider the following grammar


L-> En
E->E1+T | T
T-> T1 * F | F
F-> (E) | digit
A. Give a syntax directed definition & explain.
B. Explain the synthesized attribute
C. Explain the inherited attribute
D. Show the annotated parse tree for 1*2+3n.
E. Write and explain the SDD for constructing syntax tree.
F. Give the implementation of above grammar using SLR(1) parsing.
Syntax-Directed Translation
• Syntax-directed translation in compiler design. This topic needs to be
known to understand S-attributed SDT and L-attributed SDT better.

• Grammar rules enhanced by Syntax Directed Translation make it easier


to perform semantic analysis. SDT entails feeding the parse tree data
attached to the nodes as attributes from the bottom up or the top down.

• The primary method for Syntax-Directed Translation is to build a parse


tree or syntax tree, visit the tree's nodes in some sequence, and compute
the values of the attributes at each node. Constructing an explicit tree is
not always necessary when translating during parsing.

• Now, let us discuss S-attributed and L-attributed SDT.


S-Attributed SDT
S-Attributed SDT

• The S-attributed definition is a type of syntax-directed attributes in


compiler design that solely uses synthesized attributes. The symbol
attribute values in the production's body are used to calculate the
attribute values for the non-terminal at the head.

• The nodes of the parse tree can be ranked from the bottom up when
evaluating an S-attributed SDD's attributes. i.e., by conducting a post-
order traverse of the parse tree and evaluating the characteristics at a
node once the traversal finally leaves that node.
S-Attributed SDT
Example
The grammar is given below:
S→E
E → E1+T
E→T
T → T1*F
T→F
F → digit
The S-attributed SDT of the above grammar can be written in the following
way.
Production Semantic Rules

S→E S.val = 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 → digit F.val = digit. lexval
L-Attributed SDT
L-Attributed SDT

• L-attributed definitions are syntax-directed attributes in compiler design


in which the edges of the dependency graph for the attributes in the
production body can go from left to right and not from right to left. L-
attributed definitions can inherit or synthesize their attributes.

• If the traits are inherited, the calculation must come from the following:

• A quality that the production head inherited.


• By a production-related attribute, either inherited or synthesized, situated to the left of the
attribute being computed.
• An inherited or synthesized attribute is linked to the attribute in question in a way that
prevents cycles from forming in the dependency network.
• Let us see an example of L-attributed SDT.
L-Attributed SDT
Example
The grammar is given below:
G → TL
T → int
T → float
T → double
L → Ll, id
L → id.
The L-attributed SDT of the above grammar can be written in the
following way.
Production Semantic Rules

G→TL L.in = T.type


T → int T.type = int
T → float T.type = float
T → double T.type = double
L → L1, id L1.in = L.in ……Enter_type(id. entry, L.in)
L → id ………Entry_type(id. entry, L.in)
Example Attribute Grammar

String concat operator


Production Semantic Rule
expr → expr1 + term expr.t := expr1.t // term.t // “+”
expr → expr1 - term expr.t := expr1.t // term.t // “-”
expr → term expr.t := term.t
term → 0 term.t := “0”
term → 1 term.t := “1”
… …
term → 9 term.t := “9”
Example Annotated Parse Tree

expr.t = “95-2+”

expr.t = “95-” term.t = “2”

expr.t = “9” term.t = “5”

term.t = “9”

9 - 5 + 2
Attribute grammars

Example 1: Grammar of declarations

Production Semantic rule


D→TL L.in = T.type
T → int T.type = integer
T → char T.type = character
L → L1, id L1.in = L.in
addtype (id.index, L.in)
L → id addtype (id.index, L.in)
Attribute grammars

Example 2: Grammar of signed binary numbers

Production Semantic rule


N→SL if (S.neg)
print('-');
else print('+');
print(L.val);
S→+ S.neg = 0
S→– S.neg = 1
L → L1, B L.val = 2*L1.val+B.val
L→ B L.val = B.val
B→0 B.val = 0*20
B→1 B.val = 1*20
Attribute grammars

Example 3: Grammar of expressions


Creating an AST
The attribute for each non-terminal is a node of the tree.

Production Semantic rule


E → E1+E2 E.node = new PlusNode(E1.node,E2.node)
E → num E.node = num.yylval
E → (E1) E.node = E1.node
Syntax-Directed Definitions and Translation Schemes
• When we associate semantic rules with productions, we use two
notations:
– Syntax-Directed Definitions
– Translation Schemes
• Syntax-Directed Definitions:
– give high-level specifications for translations
– hide many implementation details such as order of evaluation of semantic actions.
– We associate a production rule with a set of semantic actions, and we do not say when they
will be evaluated.
• Translation Schemes:
– indicate the order of evaluation of semantic actions associated with a production rule.
– In other words, translation schemes give a little bit information about implementation
details.

6
Syntax-Directed Definitions and Translation Schemes
• With each production in a grammar, we give semantic rules or actions,
which describe how to compute the attribute values associated with
each grammar symbol in a production. The attribute value for a parse
node may depend on information from its children nodes below or its
siblings and parent node above.
• Evaluation of these semantic rules (using SDT one can perform
following with parser):
– may generate intermediate codes
– may put information into the symbol table
– may perform consistency check like type checking, parameter checking etc…
– may issue error messages
– may build syntax tree
– in fact, they may perform almost any activities.
• Procedure :
1) Input – Grammer
2) Output – Attached semantic rules 7
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.
– This set of attributes for a grammar symbol is partitioned into two subsets called
synthesized and inherited attributes of that grammar symbol.
– Each production rule is associated with a set of semantic rules.
• Semantic rules set up dependencies between attributes which can be
represented by a dependency graph.
• This dependency graph determines the evaluation order of these
semantic rules.
• Evaluation of a semantic rule defines the value of an attribute. But a
semantic rule may also have some side effects such as printing a value.

31
Annotated Parse Tree
• A parse tree showing the values of attributes at each node is called
an annotated parse tree.
• The process of computing the attributes values at the nodes is called
annotating (or decorating) of the parse tree.
• The order of these computations depends on the dependency graph
induced by the semantic rules.

• An attribute is said to be synthesized if its value at a parse tree node is


determined by the attribute values at the child nodes.
• An attribute is said to be inherited if its value at a parse tree node is
determined by the attribute values of the parent and/or siblings of that
node.

32
Example
Production Semantic Rules
L → E return 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

• Symbols E, T, and F are associated with a synthesized attribute val.


• The token digit has a synthesized attribute lexval (it is assumed that it is
evaluated by the lexical analyzer).
• Terminals attributes calculated at the time of lexical analysis phase
33
Annotated Parse Tree -- Example
Input: 5+3*4 L

E.val=17 return

E.val=5 + T.val=12

T.val=5 T.val=3 * F.val=4

F.val=5 F.val=3 digit.lexval=4

digit.lexval=5 digit.lexval=3

34
Example - Inherited Attributes

Production Semantic Rules


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)

• Symbol T is associated with a synthesized attribute type.


• Symbol L is associated with an inherited attribute in.

35
Translation Schemes
• In a syntax-directed definition, we do not say anything about the
evaluation times of the semantic rules (when the semantic rules
associated with a production should be evaluated?).

• A translation scheme is a context-free grammar in which:


– attributes are associated with the grammar symbols and
– semantic actions enclosed between braces {} are inserted within
the right sides of productions.

• Ex: A → { ... } X { ... } Y { ... }

Semantic Actions
36
Translation Schemes
• When designing a translation scheme, some restrictions should be
observed to ensure that an attribute value is available when a semantic
action refers to that attribute.
• These restrictions (motivated by L-attributed definitions) ensure that
a semantic action does not refer to an attribute that has not yet
computed.
• In translation schemes, we use semantic action terminology instead of
semantic rule terminology used in syntax-directed definitions.
• The position of the semantic action on the right side indicates when that
semantic action will be evaluated.

37
Depth-First Traversals

procedure visit(n : node);


begin
for each child m of n, from left to right do
visit(m);
evaluate semantic rules at node n
end
Depth-First Traversals (Example)

expr.t = “95-2+”

expr.t = “95-” term.t = “2”

expr.t = “9” term.t = “5”

term.t = “9”

9 - 5 + 2 Note: all attributes are


of the synthesized type
Translation Schemes
A translation scheme is a CF grammar embedded with semantic actions

rest → + term { print(“+”) } rest

Embedded
semantic action
rest

+ term { print(“+”) } rest


Example Translation Scheme

expr → expr + term { print(“+”) }


expr → expr - term { print(“-”) }
expr → term
term → 0 { print(“0”) }
term → 1 { print(“1”) }
… …
term → 9 { print(“9”) }
Example Translation Scheme (cont’d)

expr { print(“+”) }
expr + term
{ print(“2”) }
{ print(“-”) }
expr - term 2
{ print(“5”) }
term 5
{ print(“9”) }
9
Translates 9-5+2 into postfix 95-2+
What is Directed Acyclic Graph?
• A Directed Acyclic Graph (DAG) is a directed graph that contains
nodes connected by edges, with the property that the graph contains no
directed cycles. This means that it is impossible to start at any node and
follow a sequence of edges that eventually loops back to the starting
node.

• The absence of cycles makes DAGs useful in a variety of applications,


particularly in compiler design and optimization. For example, in a
compiler, a DAG can be used to represent the control flow and data
dependencies of a program, enabling the compiler to perform
optimizations such as common sub-expression elimination and loop
invariant code motion.
What is Directed Acyclic Graph?
• DAGs are also commonly used in scheduling problems, where the goal
is to schedule a set of tasks subject to constraints such as precedence
relations and resource availability. The tasks are represented as nodes
in the DAG, with edges representing the precedence relations between
tasks.

• In addition, DAGs are used in a variety of other applications, such as in


data processing pipelines, where each node in the graph represents a
processing step and the edges represent the flow of data between steps.

• The difference between DAG and syntax tree is that common


subexpression has more than one parent and in syntax tree common
subexpression would be represented as duplicated subtree.
What is Directed Acyclic Graph?
Example:

You might also like