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

Lecture 07

Semantic analysis is the third phase of the compiler that ensures the semantic correctness of program declarations and statements, validating constructs according to language rules. It aims to catch errors like incompatible types and undeclared variables, producing an annotated syntax tree as output. The document also discusses syntax-directed translation, semantic rules, and the concepts of synthesized and inherited attributes in the context of programming languages.

Uploaded by

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

Lecture 07

Semantic analysis is the third phase of the compiler that ensures the semantic correctness of program declarations and statements, validating constructs according to language rules. It aims to catch errors like incompatible types and undeclared variables, producing an annotated syntax tree as output. The document also discusses syntax-directed translation, semantic rules, and the concepts of synthesized and inherited attributes in the context of programming languages.

Uploaded by

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

Semantic Analysis

Introduction to Semantic Analysis


What is Semantic Analysis?
Semantic analysis is the task of ensuring that the
declarations and statements of a program are semantically
correct, i.e, that their meaning is clear and consistent with
the way in which control structures and data types are
supposed to be used.

– Third phase of the compiler, following lexical analysis and syntax


analysis
– A stage in the compilation process that ensures the program's
meaning is logically correct.
– Validates constructs according to the language's rules.
– Conducted after syntax analysis and before code generation.
•Objective: Ensure the program makes logical sense.
•Input: Syntax tree from the parser.
•Output: Annotated syntax tree with semantic information.
Semantic Analysis
• Semantic analysis is the task of ensuring that the
declarations and statements of a program are
semantically correct, i.e, that their meaning is
clear and consistent with the way in which control
structures and data types are supposed to be used

Purpose: The purpose of semantic analysis is to


catch errors that the syntax cannot detect, such as
incompatible types, undeclared variables, and
inappropriate operations.
Role of Semantic Analysis in Compiler
Design
• Ensures that each operation is compatible
with the data types involved.
• Checks for the correct declaration and usage
of variables.
• Enforces scope rules and binding of variables
and functions.
Functions of Semantic Analysis:

• Type Checking –
Ensures that data types are used in a way
consistent with their definition.
• Label Checking –
A program should contain labels references.
• Flow Control Check –
Keeps a check that control structures are used
in a proper manner.(example: no break
statement outside a loop)
Types of Semantic Errors

• Type Mismatch: Occurs when operations are


performed on incompatible data types, e.g.,
adding a number to a string.
• Undeclared Variables: Using a variable without
declaring it.
• Scope and Binding Errors: Using variables outside
their scope or redefining variables.
• Function Call Errors: Incorrect number of
arguments or incompatible types in function calls.
Type Checking
Ensures that operations on variables are semantically valid
according to their types.
•Common Type Checking Tasks:
•Checking type compatibility in expressions (e.g., adding
int to string is not valid).
•Checking return types of functions.
•Ensuring correct type assignments (e.g., assigning a float
to an int).
•Example Error:
c
int x; x = "Hello"; // Type mismatch error: cannot assign
string to int
Scope Resolution
•Local Scope: Variables are accessible within a specific
function or block.
•Global Scope: Variables are accessible throughout the
entire program.
Common Errors:
•Undeclared variables: Using a variable before it is declared
in the scope.
•Variable shadowing: A local variable has the same name as
a global variable.
•Example:
int x = 5; // Global x
void func() {
int x = 10; // Local x shadows global x
printf("%d", x); // Output will be 10 }
Example of Semantic Analysis in
Action
Consider the following code snippet: c
int x = 10;
float y = "hello"; // Type mismatch error
z = x + y; // Undeclared variable error for 'z'
•Explanation:
•Type Mismatch Error: Attempting to assign a string
("hello") to a float type variable y.
•Undeclared Variable Error: Using z without
declaring it.
Example
int main() {
int a = 5;
int b = "hello"; // Type error
int c = a + d; // Undeclared variable error
return 0;
}

This code would fail semantic analysis due to:


•Type mismatch (b cannot hold a string as it is declared as an int).
•Use of an undeclared variable (d is not defined).
Semantic Analysis helps detect logical errors before runtime,
making the program more robust and ensuring adherence to the
language’s rules.
Syntax-Directed Translation (SDT)

• Syntax-Directed Translation (SDT) is a method of


implementing the semantics of programming
languages. It uses the structure of the syntax tree
or parse tree to guide semantic actions, such as
type checking, symbol table management, or
intermediate code generation.

Grammar + semantic rule = SDT


Syntax-Directed Translation
In a syntax-directed definition, each production A→α is
associated with a set of semantic rules of the form:
b=f(c1,c2,…,cn)
where f is a function and b can be one of the followings:

🡺 b is a synthesized attribute of A and c1,c2,…,cn are


attributes of the grammar symbols in the production (
A→α ).
OR
🡺 b is an inherited attribute one of the grammar symbols in α
(on the right side of the production), and c1,c2,…,cn are
attributes of the grammar symbols in the production ( A→α ).

1
2
Syntax-Directed Translation
1. We associate information with the programming language
constructs by attaching attributes to grammar symbols.

2. Values of these attributes are evaluated by the semantic rules


associated with the production rules.

3. 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
– in fact, they may perform almost any activities.

4. An attribute may hold almost any thing.


– a string, a number, a memory location, a complex record.
1
3
Example : Syntax-Directed Translation

1
4
Syntax-Directed Definitions and Translation Schemes
1. When we associate semantic rules with productions, we
use two notations:
– Syntax-Directed Definitions (abstract)
– Translation Schemes (detail)

A. 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.

B. 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. 1
5
Syntax-Directed Definitions and Translation
Schemes
• Conceptually with both the syntax directed translation and
translation scheme we
– Parse the input token stream
– Build the parse tree
– Traverse the tree to evaluate the semantic rules at the parse tree nodes.

Input string parse tree dependency graph evaluation


order for
semantic rules

Conceptual view of syntax directed translation

1
6
Syntax-Directed Definitions
1. 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.
2. The value of an attribute at a parse tree node is defined by the
semantic rule associated with a production at that node.
3. 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
4. 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 17
Syntax-Directed Definitions
Examples:
Synthesized attribute : E→E1+E2 { E.val =E1.val + E2.val}
Inherited attribute :A→XYZ {Y.val = 2 * A.val}

1. Semantic rules set up dependencies between attributes which can


be represented by a dependency graph.

2. This dependency graph determines the evaluation order of these


semantic rules.

3. 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.

18
Syntax-Directed Definition
In a syntax-directed definition, each production A→α is
associated with a set of semantic rules of the form:
b=f(c1,c2,…,cn)
where f is a function and b can be one of the followings:

🡺 b is a synthesized attribute of A and c1,c2,…,cn are


attributes of the grammar symbols in the production (
A→α ).
OR
🡺 b is an inherited attribute one of the grammar symbols
in α (on the right side of the production), and c1,c2,…,cn are
attributes of the grammar symbols in the production ( A→α
).

19
Syntax-Directed Definition -- Example
Production Semantic Rules
L→En print(E.val)
E → E1 + T E.val = E1.val + T.val
E→T E.val = T.val
T → T1 * T.val = T1.val * F.val
FT→F T.val = F.val
F→(E) F.val = E.val
F → digit F.val = digit.lexval
1. Symbols E, T, and F are associated with a synthesized attribute val.
2. The token digit has a synthesized attribute lexval (it is assumed that it is
evaluated by the lexical analyzer).
3. Terminals are assumed to have synthesized attributes only. Values for attributes
of terminals are usually supplied by the lexical analyzer.
4. The start symbol does not have any inherited attribute unless otherwise stated.

2
0
Syntax-Directed Definitions (SDD)
Example

Production Rule: Semantic Rules


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 → id { F.val = lookup(id) }
Implementation of Syntax directed translation
Syntax direct translation is implemented by constructing a parse
tree and performing the actions in a left to right depth first order.
SDT is implementing by parse the input and produce a parse tree
as a result.
Example

Production Semantic Rules


S→E$ { printE.VAL }
E→E+E {E.VAL := E.VAL + E.VAL }
E→E*E {E.VAL := E.VAL * E.VAL }
E → (E) {E.VAL := E.VAL }
E→I {E.VAL := I.VAL }
I → I digit {I.VAL := 10 * I.VAL + LEXVAL }
I → digit { I.VAL:= LEXVAL}
Parse Tree for SDT
Attributes

•Attribute: A characteristic that determines the value of a


grammatical symbol.
•Semantic Functions: Also known as attribute computation
functions, they compute the values of attributes
associated with grammar productions.
•Predicate Functions: Functions that define a grammar's
static semantic rules and parts of its syntax.
Attribute Grammar
• So, a semantic rule b=f(c1,c2,…,cn) indicates that the
attribute b depends on attributes c1,c2,…,cn.

• In a syntax-directed definition, a semantic rule may


just evaluate a value of an attribute or it may
have some side effects such as printing values.

• An attribute grammar is a syntax-directed definition in


which the functions in the semantic rules cannot have
side effects (they can only evaluate values of
attributes).
25
Synthesized Attributes.
• These attributes get values from the attribute values of
their child nodes.
They are defined by a semantic rule associated with
the production at a node such that the production has
the non-terminal as its head.
• An example
S → ABC
S is said to be a synthesized attribute if it takes values
from its child node (A, B, C).
• An example
E → E + T { E.value = E.value + T.value }
Parent node E gets its value from its child node.
Inherited Attributes.
• These attributes take values from their parent and/or
siblings.
They are defined by a semantic rule associated with
the production at the parent such that the
production has the non-terminal in its body.
They cannot be evaluated by a pre-order traversal of
the parse tree since they depend on both left and
right siblings.
• An example;
S → ABC
• A can get its values from S, B and C.
B can get its values from S, A and C
C can get its values from A, B and S
Expansion and Reduction
Expansion : When a non-terminal is expanded to terminals as per
a grammatical rule

Reduction : When a terminal is reduced to its corresponding


non-terminal according to grammar rules. Syntax trees are parsed
top-down and left to right. Whenever reduction occurs, we apply
its corresponding semantic rules (actions).
Inherited attributes
• An inherited value at a node in a parse tree is defined in
terms of attributes at the parent and/or siblings of the
node.
• Convenient way for expressing the dependency of a
programming language construct on the context in which
it appears.
• We can use inherited attributes to keep track of whether
an identifier appears on the left or right side of an
assignment to decide whether the address or value of the
assignment is needed.
• Example: The inherited attribute distributes type information
to the various identifiers in a declaration.

2
9
Syntax-Directed Definition – Inherited Attributes
Production Semantic Rules
D→TL L.in = T.type T.type
T → int = integer T.type =
T → real real
L → L1 L1.in = L.in,addtype(id.entry,L.in)
id L → addtype(id.entry,L.in)
id
1. Symbol T is associated with a synthesized attribute type.

2. Symbol L is associated with an inherited attribute in.

3
0
Syntax-Directed Definition -- Example
Production Semantic Rules
L→En 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
1. Symbols E, T, and F are associated with a synthesized attribute val.
2. The token digit has a synthesized attribute lexval (it is assumed that
it is evaluated by the lexical analyzer).
3. Terminals are assumed to have synthesized attributes only. Values for
attributes of terminals are usually supplied by the lexical analyzer.
4. The start symbol does not have any inherited attribute unless
otherwise stated.
31
Inherited attributes
• An inherited value at a node in a parse tree is defined in
terms of attributes at the parent and/or siblings of the node.

• Convenient way for expressing the dependency of a


programming language construct on the context in which it
appears.

• We can use inherited attributes to keep track of whether an


identifier appears on the left or right side of an assignment to
decide whether the address or value of the assignment is
needed.

• Example: The inherited attribute distributes type information


to the various identifiers in a declaration.

32
Syntax-Directed Definition – 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)

1. Symbol T is associated with a synthesized attribute type.

2. Symbol L is associated with an inherited attribute in.

33
Example Attribute Grammar
Production Attribute Rule

𝑛𝑢𝑚𝑏𝑒𝑟 → 𝑠𝑖𝑔𝑛 𝑙𝑖𝑠𝑡 𝑙𝑖𝑠𝑡. 𝑝𝑜𝑠 = 0


if 𝑠𝑖𝑔𝑛. 𝑛𝑒𝑔:
𝑛𝑢𝑚𝑏𝑒𝑟. 𝑣𝑎𝑙 = −𝑙𝑖𝑠𝑡. 𝑣𝑎𝑙
else:
𝑛𝑢𝑚𝑏𝑒𝑟. 𝑣𝑎𝑙 = −𝑙𝑖𝑠𝑡. 𝑣𝑎𝑙

𝑠𝑖𝑔𝑛 → + 𝑠𝑖𝑔𝑛. 𝑛𝑒𝑔 = false

𝑠𝑖𝑔𝑛 → − 𝑠𝑖𝑔𝑛. 𝑛𝑒𝑔 = true

𝑙𝑖𝑠𝑡 → 𝑏𝑖𝑡 𝑏𝑖𝑡. 𝑝𝑜𝑠 = 𝑙𝑖𝑠𝑡. 𝑝𝑜𝑠


𝑙𝑖𝑠𝑡. 𝑣𝑎𝑙 = 𝑏𝑖𝑡. 𝑣𝑎𝑙

𝑙𝑖𝑠𝑡0 → 𝑙𝑖𝑠𝑡1𝑏𝑖𝑡 𝑙𝑖𝑠𝑡1. 𝑝𝑜𝑠 = 𝑙𝑖𝑠𝑡0. 𝑝𝑜𝑠 + 1


𝑏𝑖𝑡. 𝑝𝑜𝑠 = 𝑙𝑖𝑠𝑡0. 𝑝𝑜𝑠
CS 𝑙𝑖𝑠𝑡0Swarnendu
. 𝑣𝑎𝑙 = 𝑙𝑖𝑠𝑡1. 𝑣𝑎𝑙 + 𝑏𝑖𝑡. 𝑣𝑎𝑙
335 Biswas

𝑏𝑖𝑡 → 0 𝑏𝑖𝑡. 𝑣𝑎𝑙 = 0

𝑏𝑖𝑡 → 1 𝑏𝑖𝑡. 𝑣𝑎𝑙 = 2𝑏𝑖𝑡.𝑝𝑜𝑠


Abstract Syntax Tree (AST)
• Condensed form of a parse tree used for representing language
constructs
• ASTs do not check for string membership in the language for a grammar
• ASTs represent relationships between language constructs, do not bother
with derivations
if−then−else

𝑆 → if 𝑃 then 𝑆1else 𝑆2
𝐵 𝑆1 𝑆2

• Parse trees are also called concrete syntax trees

CS Swarnendu
335 Biswas
Parse Tree and Abstract
Syntax Tree
Parse Tree Abstract Syntax Tree

𝐸𝑥𝑝𝑟 +

𝐸𝑥𝑝𝑟 + 𝑇𝑒𝑟𝑚
− name

𝐸𝑥𝑝𝑟 − 𝑇𝑒𝑟𝑚 𝐹𝑎𝑐𝑡𝑜𝑟


name name
𝑇𝑒𝑟𝑚 𝐹𝑎𝑐𝑡𝑜𝑟 name

𝐹𝑎𝑐𝑡𝑜𝑟 name

name

CS Swarnendu
335 Biswas
• Abstract Syntax Trees(ASTs).
• These are a reduced form of a parse tree.
They don't check for string membership in the
language of the grammar.
They represent relationships between language
constructs and avoid derivations.
• An example
The parse tree and abstract syntax tree for the
expression
a := b * c + d is.
Abstract Syntax Trees(ASTs).

The parse tree


The abstract syntax tree
For Example: 2*(4+5)

Semantic action is given as follows

Production Semantic Rules

E -> E + T E1.trans = E2.trans


+ T.trans
E -> T E.trans = T.trans

T -> T * F T1.trans = T2.trans *


F.trans
T -> F T.trans = F.trans

F -> int F.trans = int.value

F -> ( E ) F.trans = E.trans


AST
Parse
Tree 𝑛𝑢𝑚𝑏𝑒𝑟

𝑠𝑖𝑔𝑛 𝑙𝑖𝑠𝑡

− 𝑙𝑖𝑠𝑡 𝑏𝑖𝑡

𝑙𝑖𝑠𝑡 𝑏𝑖𝑡

𝑏𝑖𝑡

1 0 1

CS
335
Annotated Parse Tree
1. A parse tree showing the values of attributes at each
node is called an annotated parse tree.
2. Values of Attributes in nodes of annotated parse-tree are
either,
– initialized to constant values or by the lexical analyzer.
– determined by the semantic-rules.

3. The process of computing the attributes values at the


nodes is called annotating (or decorating) of the parse
tree.

4. Of course, the order of these computations depends on


the dependency graph induced by the semantic rules.

42
Annotated Parse Tree -- Example
Input: 5+3*4 L

E.val=17 n

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

43
Annotated Parse Tree
𝑛𝑢𝑚𝑏𝑒𝑟

• A parse tree showing the


value(s) of its 𝑠𝑖𝑔𝑛 𝑙𝑖𝑠𝑡

attribute(s) is called an
annotated parse tree − 𝑙𝑖𝑠𝑡 𝑏𝑖𝑡

𝑙𝑖𝑠𝑡 𝑏𝑖𝑡

𝑏𝑖𝑡

1 0 1

CS
335
Annotated Parse Tree
𝑛𝑢𝑚𝑏𝑒𝑟

• A parse tree showing the 𝑠𝑖𝑔𝑛 𝑙𝑖𝑠𝑡 𝑝𝑜𝑠 = 0 1


value(s) of its
2
attribute(s) is called an
− 𝑝𝑜𝑠 =1 𝑙𝑖𝑠𝑡 2 𝑝𝑜𝑠 = 0 𝑏𝑖𝑡
annotated parse tree
3 3
𝑝𝑜𝑠 = 2 𝑙𝑖𝑠𝑡 𝑝𝑜𝑠 =1 𝑏𝑖𝑡

4 𝑝𝑜𝑠 = 2 𝑏𝑖𝑡

1 0 1

CS
335
Annotated Parse Tree
𝑣𝑎𝑙 =?

𝑛𝑢𝑚𝑏𝑒𝑟

• A parse tree showing 𝑛𝑒𝑔 = 𝑡𝑟𝑢𝑒 𝑠𝑖𝑔𝑛 𝑙𝑖𝑠𝑡 𝑝𝑜𝑠 = 0


the value(s) of its
attribute(s) is
𝑛𝑒𝑔 = 𝑡𝑟𝑢𝑒 − 𝑝𝑜𝑠 =1 𝑙𝑖𝑠𝑡 𝑝𝑜𝑠 = 0 𝑏𝑖𝑡
called an annotated
parse tree
𝑝𝑜𝑠 = 2 𝑙𝑖𝑠𝑡 𝑝𝑜𝑠 =1 𝑏𝑖𝑡

𝑝𝑜𝑠 = 2 𝑏𝑖𝑡

1 0 1

CS
335
Annotated Parse Tree
𝑣𝑎𝑙 = −5

𝑛𝑢𝑚𝑏𝑒𝑟

𝑣𝑎𝑙 = 5
• A parse tree showing 𝑛𝑒𝑔 = 𝑡𝑟𝑢𝑒 𝑠𝑖𝑔𝑛 𝑙𝑖𝑠𝑡 𝑝𝑜𝑠 = 0
the value(s) of its
attribute(s) is 𝑣𝑎𝑙 = 1
𝑛𝑒𝑔 = 𝑡𝑟𝑢𝑒 − 𝑝𝑜𝑠 =1 𝑙𝑖𝑠𝑡 𝑣𝑎𝑙 = 4 𝑝𝑜𝑠 = 0 𝑏𝑖𝑡
called an annotated
parse tree 𝑣𝑎𝑙 = 4
𝑣𝑎𝑙 = 0
𝑝𝑜𝑠 = 2 𝑙𝑖𝑠𝑡 𝑝𝑜𝑠 =1 𝑏𝑖𝑡

𝑝𝑜𝑠 = 2 𝑣𝑎𝑙 = 4
𝑏𝑖𝑡

1 0 1

CS
335
Dependency Graph
• If an attribute 𝑏 depends on an attribute 𝑐 then the semantic rule for
𝑏 must be evaluated after the semantic rule for 𝑐
• The dependencies among the nodes are depicted by a directed graph
called dependency graph

CS
335
Dependency Graph
• Suppose 𝐴. 𝑎 = 𝑓 𝑋. 𝑥, 𝑌. 𝑦 is a semantic rule for 𝐴 → 𝑋𝑌
𝐴 𝐴. 𝑎
Parse tree Dependency
graph
𝑋 𝑌 𝑋. 𝑥 𝑌. 𝑦

• Suppose 𝑋. 𝑥 = 𝑓(𝐴. 𝑎, 𝑌. 𝑦) is a semantic rule for 𝐴 → 𝑋𝑌


𝐴 𝐴. 𝑎

𝑋 𝑌 𝑋. 𝑥 𝑌. 𝑦

CS
335
Dependency Graph
• Directed Graph
• Shows interdependencies between attributes.
• If an attribute b at a node depends on an attribute c, then the
semantic rule for b at that node must be evaluated after the
semantic rule that defines c.
• Construction:
– Put each semantic rule into the form b=f(c1,…,ck) by introducing
dummy synthesized attribute b for every semantic rule that
consists of a procedure call.
– E.g.,
• L→En print(E.val)
• Becomes: dummy = print(E.val)

– 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.

50
Dependency Graph Construction
• Example
• Production Semantic Rule
E→E1 + E2 E.val = E1.val + E2.val

E . val

E1. val + E2 . Val


• E.val is synthesized from E1.val and E2.val
• The dotted lines represent the parse tree that is not part of the
dependency graph.

5
1
Dependency Graph
D → T L L.in =
T.type
T → int T.type = integer
T → real T.type = real
L → L1 L1.in = L.in,
id addtype(id.entry,L.in)

L→ addtype(id.entry,L.in)
id

15
Dependency Graph
Input: 5+3*4 L

E.val=17 n

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

53
Dependency Graph
D → T L 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)

54
Syntax Trees
Syntax-Tree
– an intermediate representation of the compiler’s input.
– A condensed form of the parse tree.
– Syntax tree shows the syntactic structure of the program while
omitting irrelevant details.
– Operators and keywords are associated with the interior nodes.
– Chains of simple productions are collapsed.
Syntax directed translation can be based on
syntax tree as well as parse tree.

55
Syntax Tree-Examples
Expression: if B then S1 else S2
+ if - then - else

5 * B S1 S2
Statement:
3 4 • Node’s label indicates what kind
• Leaves: identifiers or constants of a statement it is
• Internal nodes: labelled with • Children of a node correspond to
operations the components of the
• Children: of a node are its statement
operands

56
Constructing Syntax Tree for
Expressions-
Example: a-4+c +

1. p1:=mkleaf(id,entrya);
2. p2:=mkleaf(num,4); - id
3. p3:=mknode(-,p1,p2)
4. p4:=mkleaf(id,entryc); to entry for c

5. p5:= mknode(+,p3,p4); id num 4

• The tree is constructed to entry for a

bottom up.

57
A syntax Directed Definition for
Constructing Syntax Tree
1. It uses underlying productions of the grammar to schedule the
calls of the functions mkleaf and mknode to construct the syntax
tree
2. Employment of the synthesized attribute nptr (pointer) for E and T
to keep track of the pointers returned by the function calls.
PRODUCTION SEMANTIC RULE
E → E1 + T E.nptr = mknode(“+”,E1.nptr ,T.nptr)
E → E1 - T E.nptr = mknode(“-”,E1.nptr ,T.nptr)
E→T E.nptr = T.nptr
T → (E) T.nptr = E.nptr
T → id T.nptr = mkleaf(id, id.lexval)
T → num T.nptr = mkleaf(num, num.val)

58
S-Attributed Definitions
1. Syntax-directed definitions are used to specify syntax-directed
translations.
2. To create a translator for an arbitrary syntax-directed definition can be
difficult.
3. We would like to evaluate the semantic rules during parsing (i.e. in a
single pass, we will parse and we will also evaluate semantic rules
during the parsing).
4. We will look at two sub-classes of the syntax-directed definitions:
– S-Attributed Definitions: only synthesized attributes used in the
syntax-directed definitions.
– All actions occur on the right hand side of the production.
– L-Attributed Definitions: in addition to synthesized attributes, we
may also use inherited attributes in a restricted fashion.
5. To implement S-Attributed Definitions and L-Attributed Definitions we
can evaluate semantic rules in a single pass during the parsing.
6. Implementations of S-attributed Definitions are a little bit easier than
implementations of L-Attributed Definitions
59
Bottom-Up Evaluation of S-Attributed
Definitions
• A translator for an S-attributed definition can often be
implemented with the help of an LR parser.
• From an S-attributed definition the parser generator can
construct a translator that evaluates attributes as it parses the
input.
• We put the values of the synthesized attributes of the grammar
symbols a stack that has extra fields to hold the values of
attributes.
– The stack is implemented by a pair of arrays val & state
– If the ith state symbol is A the val[i] will hold the value of the
attribute associated with the parse tree node corresponding to
this A.

60
Annotated
Parse Tree 𝑒𝑥𝑝𝑟. 𝑐𝑜𝑑𝑒 = "95 − 2 + "

𝑒𝑥𝑝𝑟. 𝑐𝑜𝑑𝑒 = "95 − " "+" 𝑡𝑒𝑟𝑚. 𝑐𝑜𝑑𝑒 = "2"

"2"
𝑒𝑥𝑝𝑟. 𝑐𝑜𝑑𝑒 = "9" "−" 𝑡𝑒𝑟𝑚. 𝑐𝑜𝑑𝑒 = "5"

𝑡𝑒𝑟𝑚. 𝑐𝑜𝑑𝑒 = "9" "5"

"9"

CS Swarnendu
335 Biswas
S-Attributed Definition
• An SDD that involves only synthesized attributes is called
S-attributed definition
• Each rule computes an attribute for the head nonterminal from
attributes taken from the body of the production

• Semantic rules in a S-attributed definition can be


evaluated by a bottom-up or postorder traversal of the
parse tree
• An S-attributed SDD can be implemented naturally in conjunction
CS with an LR Swarnendu
335 Biswas
parser
L-Attributed Definitions
• Each attribute must be either
I. Synthesized
II. Suppose 𝐴 → 𝑋1𝑋2 … 𝑋𝑛 and Production Semantic Rules

𝑋𝑖. 𝑎 is an inherited attribute. ′ 𝑇′. 𝑖𝑛ℎ = 𝐹. 𝑣𝑎𝑙


𝑋𝑖 . 𝑎 can be computed using 𝑇 → 𝐹𝑇
𝑇. 𝑣𝑎𝑙 = 𝑇′. 𝑠𝑦𝑛
a) Only inherited attributes from
𝐴, or 𝑇′. 𝑖𝑛ℎ = 𝑇′. 𝑖𝑛ℎ × 𝐹. 𝑣𝑎𝑙
𝑇′ →∗ 𝐹𝑇′ 1
b) Either inherited or
1
𝑇 . 𝑠𝑦𝑛 = 𝑇′. 𝑠𝑦𝑛

1
synthesized attributes
associated with 𝑇′ → 𝜖 𝑇′. 𝑠𝑦𝑛 = 𝑇′. 𝑖𝑛ℎ
𝑋1, … , 𝑋𝑖−1, or
𝐹 → digit 𝐹. 𝑣𝑎𝑙 = digit. 𝑙𝑒𝑥𝑣𝑎𝑙
c) Inherited or synthesized
CS attributes associated with 𝑋𝑖.Swarnendu
335 Biswas
S-Attributed Definition

6
4
Draw the Example 3*5+4n
Tree L

E val=19
Print(19)
E val=15

T val=15
T val=4
T val=3
F val=4
F val=3 F val=5
n
digit
* + lexval =4
digit digit
lexval =3 lexval =5
L-Attributed Definitions
• When translation takes place during parsing, order of
evaluation is linked to the order in which the nodes of a
parse tree are created by parsing method.
• A natural order can be obtained by applying the procedure of visit

to the root of a parse tree.

• We call this evaluation order depth first order.


• L-attributed definition is a class of syntax directed definition

whose attributes can always be evaluated in depth first order( L

stands for left since attribute information flows from left to right).
L-Attributed Definitions
A syntax-directed definition is L-attributed if each inherited attribute
of Xj, where 1≤j≤n, on the right side of A → X1X2...Xn depends
only on

1. The attributes of the symbols X1,...,Xj-1 to the left of Xj in the

production

2. The inherited attribute of A

Every S-attributed definition is L-attributed, since the restrictions apply


only to the inherited attributes (not to synthesized attributes).
A syntax Directed Definition for Constructing
Syntax Tree
1. It uses underlying productions of the grammar to schedule the calls
of the functions mkleaf and mknode to construct the syntax tree
2. Employment of the synthesized attribute nptr (pointer) for E and T
to keep track of the pointers returned by the function calls.
PRODUCTIONSEMANTIC RULE
E → E1 + T E.nptr = mknode(“+”,E1.nptr ,T.nptr)
E → E1 - T E.nptr = mknode(“-”,E1.nptr ,T.nptr)
E→T E.nptr = T.nptr
T→ T.nptr = E.nptr
(E) T.nptr = mkleaf(id, id.lexval)
T → id T.nptr = mkleaf(num, num.val)
T → num

6
8
S.NO Synthesized Attributes Inherited Attributes

An attribute is said to be Synthesized attribute if An attribute is said to be Inherited attribute if its


1. its parse tree node value is determined by the parse tree node value is determined by the
attribute value at child nodes. attribute value at parent and/or siblings node.

The production must have non-terminal as its The production must have non-terminal as a
2.
head. symbol in its body.

A synthesized attribute at node n is defined only A Inherited attribute at node n is defined only in
3. in terms of attribute values at the children of n terms of attribute values of n’s parent, n itself,
itself. and n’s siblings.

It can be evaluated during a single bottom-up It can be evaluated during a single top-down and
4.
traversal of parse tree. sideways traversal of parse tree.

Synthesized attributes can be contained by both Inherited attributes can’t be contained by both, It
5.
the terminals or non-terminals. is only contained by non-terminals.

Inherited attribute is used by only L-attributed


SDT.
Synthesized attribute is used by both
6.
S-attributed SDT and L-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


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)


Comparison Between L-Attributed and S-Attributed

You might also like