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

Semantic Analysis in Compiler Design

The document discusses semantic analysis in compiler design. It defines semantic analysis as the last step in the front-end compilation where the source code is checked for errors. The key tasks of semantic analysis are to check for correctly declared variables and types, type-consistent computations, and catch errors missed by lexical analysis and parsing. Semantic analysis ensures programs follow language semantics for control structures and data types. It represents the program as object code or an intermediate representation.
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)
493 views46 pages

Semantic Analysis in Compiler Design

The document discusses semantic analysis in compiler design. It defines semantic analysis as the last step in the front-end compilation where the source code is checked for errors. The key tasks of semantic analysis are to check for correctly declared variables and types, type-consistent computations, and catch errors missed by lexical analysis and parsing. Semantic analysis ensures programs follow language semantics for control structures and data types. It represents the program as object code or an intermediate representation.
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

Compiler Design CSC 503

Semantic Analysis
Acknowledgements
Majority of texts, diagrams and tables in the slide is based
on the text book Compilers: Principles, Techniques, and
Tools by Aho, Sethi, Ullman and Lam.
Semantic Analysis in Compiler
• Semantic Analysis is the last step in the front-end compilation.
• Front-end is the stage of the compilation where the source code is checked for
errors.
• The Lexical Analyzer is implemented as a Tokenizer and its goal is to read the
source code character by character, groups characters that are part of the same
Token, and reject characters that are not allowed in the language.
• For example, if the source code contains the following sequence of characters
'w' 'h' 'i' 'l' 'e'
• the Tokenizer will group them in a unique token while, which is very likely to be
the beginning of a loop.
• On the other hand, if the Tokenizer sees the following sequence
• '?' '=' '!'
• it’s quite likely that it will reject the whole source code because that sequence is
not allowed.
Semantic Analysis in Compiler
• The second step is Parsing. More precisely, the output of the Lexical Analysis is a
sequence of Tokens and the Parser has to evaluate whether this sequence of Token
makes sense or not.
• For example, one rule in the Grammar may say that a Token “while” must be
followed by an open parenthesis (. This is probably because the boolean condition
of the while loop must be enclosed into a pair of parentheses, a common scenario
in many languages.
• Continuing with this simple example, if the sequence of Tokens does not contain
an open parenthesis after the while Token, then the Parser will reject the source
code.
• So, to recap:
• Lexical Analysis catches errors at the character (alphabetic) level.
• Parsing catches errors at the token (grammatical) level.
• The goal of Semantic Analysis is to catch all possible errors that went unnoticed
through Lexical Analysis and Parsing.
Semantic Analysis in Compiler
int x = 0;
Object y = null;
String z = x + y;

Semantic Analysis always takes care of the following.


• Check that identifiers are declared before to be used in computations.
• Check that reserved keywords are not misused.
• Check that types are correctly declared, if the language is explicitly typed.
• Check that computations are type-consistent, wherever possible.
Role of Semantic Analysis
• Semantic analysis ensures that the declarations and statements of a
program are to be semantically correct with the way in which control
structures and data types are supposed to be used.
• A semantic analyzer uses information stored in the syntax tree and
symbol table to check the source program's semantic consistency
according to the language definition.
• The output of this stage is a representation of the program in either
object code in the case of one pass compilers or intermediate
representation of the program in the case of other compilers.
Static & Dynamic Semantics
• Semantic consistency that cannot be handled at the parsing stage is handled here.
• Parsers cannot handle context-sensitive features of programming languages.
• The following static semantics of programming languages can be checked by
semantic analyzer.
• Variables are declared before use
• Types matched on both sides of assignments
• Parameter types and number match in declaration and use
• The following dynamic semantic of programming languages can be checked at
runtime.
• Whether an overflow occur during arithmetic operation
• Whether array limits will be crossed during execution
• Whether recursion will cross stack limits
• Whether heap memory will be insufficient
Static Semantic
Static
Semantic:
Errors
Static Semantic
Dynamic
Semantics
Dynamic Semantics
Semantic Analysis
Attribute
Grammars
Attribute Computation Rules
Semantic Analysis
• The semantic analysis checks the semantic consistency of the source program
with language specifications.
• It saves the type information either in the syntax tree or in the symbol table for
making them available during intermediate code generation.
• The important task of semantic analysis is type checking, where it checks
whether the operator has matching operands or not.
• Another task of the semantic analyser is to convert one type of information to
another type for an identifier.
• To perform such tasks by the semantic analyser, the grammar that specifies the
language specifications in the source program needs to be translated into
another form, and this form is made of a combination of the grammar and
semantic rules.
• This combination is often called syntax directed definition (SDD), and the task
to convert the grammar into SDD is called syntax directed translation (SDT).
Semantic Errors
• Semantic errors, also called logic errors arise when a statement used in
a program is not meaningful, that is, it does not comply to the set of
rules (semantics) for that language being used. These errors can be
• Type mismatch.
• Multiple declaration of variables in a scope.
• Undeclared variables.
• Access of an out of scope variable.
• Actual and formal parameter mismatch.
• Misuse of reserved identifier.
Semantic Analysis
SDD and SDT Scheme
SDD and SDT Scheme
SDT Overview
SDD Overview
Semantic Analysis

• To obtain a syntax directed definition (SDD) for a grammar, semantic rules


can be imposed to each production provided in the grammar by introducing
different attributes that are to be associated with the non-terminals in the
production rules.
• Such elaboration of program constructs can be specified by different forms of
semantic rules with the help of a variety of attributes.
• Basically, the attributes are used to evaluate the nodes labelled by the non-
terminals in terms of children nodes or themselves in the parse trees.
• The attributes are associated with the non-terminals or the nodes in the
parse trees to specify the value of the attributes that are determined at such
nodes.
Syntax Directed Definitions
• A SDD is a CFG together with attributes and rules. Attributes are
associated with grammar symbols and rules are associated with
productions.
• SDD denotes the association of different types or same types of
attributes with the production rules in the CFG.
• SDD is used to produce the semantic rules corresponding to the
productions provided in the grammar.
• If a node is labelled by a non-terminal in the parse tree, then an
attribute can be associated with the node to determine the value of
the attribute at that node in terms of the children nodes of that
node or in terms of other type of dependency with other nodes in the
tree.
Synthesized & Inherited Attributes
• Synthesized Attribute:
• A synthesized attribute for a nonterminal A at a node N in parse tree, is defined
by a semantic rule associated with the production at N.
• A be the head of the production.
• A synthesized attribute at node N is defined only in terms of attribute values at
the children of N and at N itself.
• Inherited Attribute:
• An inherited attribute for a nonterminal B at a node N in parse tree, is defined by
a semantic rule associated with the production at the parent of N.
• The production must have B as a symbol in its body.
• An inherited attribute at node N is defined only in terms of attribute values at N's
parent, N itself, and N's siblings.
Example of SDD
Evaluation of an SDD
• To exhibit the semantic rules of the productions of a CFG through a parse tree,
the attribute values can be displayed at the nodes with which both synthesized
and inherited attributes or just one type of attribute are associated.
• The attribute values are determined at the corresponding nodes in terms of
children nodes or in terms of sibling nodes, or the nodes themselves.
• To evaluate a program construct using a SDD, the program construct needs to
be translated into the SDD characterized annotated parse tree and then
performed evaluation in the order of bottom-up or post order traversal of the
parse tree for synthesized attributes.
• To evaluate the program construct using inherited attributes to be associated
with the nodes in the parse tree and using the semantic rules of the grammar,
every node has to be evaluated by determining the values of the attributes at
those nodes.
• At each node, the attribute value is displayed after evaluation at that node or
the attribute value inherited from the parent node or inherited from sibling
nodes.
Evaluation of an SDD
• For SDD's with both inherited and synthesized attributes, there is no
guarantee that there is even one order in which to evaluate attributes at
nodes. For instance, consider non-terminals A and B, with synthesized and
inherited attributes A.s and B.i, respectively, along with the production and
rules
Example 1
Example 2
Example 2
Evaluation Orders for SDDs
• Dependency graphs are a useful tool for determining an evaluation
order for the attribute instances in a parse tree.
• While an annotated parse tree shows the values of attributes, a
dependency graph determine how those values can be computed.
• In addition to dependency graphs, we define two important classes of
SDD's:
• S-attributed
• L-attributed
Dependency Graphs
• A dependency graph shows the flow of information among the attribute
instances in a parse tree.
• An edge from one attribute instance to another means that the value of
the first is needed to compute the second.
• Dependency graphs can be used to determine the order of evaluation
using synthesized and inherited attributes and using the relationships
among the attribute instances.
• The flow of information among different attribute instances in the
dependency graph is denoted by solid edge lines, and these edges infer
the flow of evaluated values from one attribute instance to another.
Dependency Graphs
• The following sequence of knowledge can be opted to determine the
order of evaluation using a dependency graph in an annotated parse
tree.
• The dependency graph builds on an annotated parse tree, can contain a
number of nodes corresponding to the attributes attached at the nodes in the
parse tree.
• The semantic rule that defines production can use a synthesized attribute
attached to a non-terminal to evaluate the value (A.syn1) of the attribute in
terms of another attribute associated with another non-terminal or grammar
symbol (B.syn2).
• The inherited attribute inherits the synthesized attribute value via the edge of
the dependency graph.
Dependency Graphs
Types of SDDs: S-attributed and L-
attributed
• A linear order of attributed values is generated after imposing an
ordering of topological sort of dependency graph to the evaluated
attribute values.
• Let there be an edge of dependency graph from a node to another node.
• Then, it is necessary to evaluate the attribute value associated with the
first node and then the attribute associated with the second node to be
evaluated in terms of the attribute value associated with the first node.
• If any cycle exists in the dependency graph, then topological sort cannot
be determined, and at the same time, SDD on some parse tree cannot
be evaluated as well.
• To ensure the non-existent of any cycles in the dependency graph, we
can define two types of SDD for evaluation, viz. S-attributed and L-
attributed.
Types of SDDs: S-attributed and L-
attributed
• S-attributed: An SDD is S-attributed if every attribute is synthesized.
• L-attributed: Between the attributes associated with a production body,
dependency-graph edges can go from left to right, but not from right to
left (hence “L-attributed"). More precisely, each attribute must be either
• Synthesized
• Inherited, but with the rules limited as follows. Suppose that there is a production
→ … , and that there is an inherited attribute . computed by a
rule associated with this production. Then the rule may use only:
• Inherited attributes associated with the head A.
• Either inherited or synthesized attributes associated with the occurrences of symbols ,
,…, located to the left of .
• Inherited or synthesized attributes associated with this occurrence of itself, but only in
such a way that there are no cycles in a dependency graph formed by the attributes of .
SDD
Annotated Parse Tree
Dependency Graph
Any SDD containing the following production and rules cannot be L-
attributed:
SDD
Dependency Graph

You might also like