Unit v Symantic Analysis
Unit v Symantic Analysis
Manisha Mali
[email protected]
Compiler (front-end)
character
(back-end)
token intermediate
stream form
abstract intermediate
syntax tree form
annotated target
AST language
4 Manisha Mali
Semantic Analysis/Checking
Semantic analysis: the final part of the analysis half of compilation
afterwards comes the synthesis half of compilation
Purposes:
perform final checking of legality of input program, “missed” by lexical and
syntactic checking
name resolution, type checking,break stmt in loop, ...
“understand” program well enough to do synthesis
Typical goal: relate assignments to & references of particular variable
5 Manisha Mali
Semantic Analysis
Semantic analysis is applied by a compiler to discover the
meaning of a program by analyzing its parse tree or abstract
syntax tree.
A program without grammatical errors may not always be
correct program.
pos = init + rate * 60.0
6
Manisha Mali
Semantic Analysis
Static semantic checks (done by the compiler) are performed at compile time
Type checking
Every variable is declared before used
Identifiers are used in appropriate contexts
Check subroutine call arguments
Check labels
Dynamic semantic checks are performed at run time, and the compiler produces code
that performs these checks
Array subscript values are within bounds
int A[10]; for(i=0;i<20;i++) scanf(“%d”,&A[i]);
Arithmetic errors, e.g. division by zero
Pointers are not dereferenced unless pointing to valid object Int *a; float *a;
A variable is used but hasn't been initialized
int a, b, c ; c=a+b; printf(“%d”,c);
When a check fails at run time, an exception is raised
7
Manisha Mali
Semantic Analysis and Strong Typing
A language is strongly typed "if (type) errors are always detected"
Errors are either detected at compile time or at run time
Examples of such errors are listed on previous slide
Languages that are strongly typed are Ada, Java, ML, Haskell
Languages that are not strongly typed are Fortran, Pascal, C/C++,
Lisp
Strong typing makes language safe and easier to use, but
potentially slower because of dynamic semantic checks
In some languages, most (type) errors are detected late at run time
which is harmful to reliability e.g. early Basic, Lisp, Prolog, some
script languages
8
Manisha Mali
Semantic Analyzer
A semantic analyzer checks the source program for semantic errors and
collects the type information for the code generation.
Type-checking is an important part of semantic analyzer.
Normally semantic information cannot be represented by a context-free
language used in syntax analyzers.
Context-free grammars used in the syntax analysis are integrated with
attributes (semantic rules)
the result is a syntax-directed translation,
Attribute grammars
Ex:
newval := oldval + 12
The type of the identifier newval must match with type of the expression (oldval+12)
9 Manisha Mali
Type Checking
A compiler has to do semantic checks in addition to syntactic checks.
Semantic Checks
Static – done during compilation
Dynamic – done during run-time
Type checking is one of these static checking operations.
we may not do all type checking at compile-time.
Some systems also use dynamic type checking too.
A type system is a collection of rules for assigning type expressions to the parts of a
program.
A type checker implements a type system.
A sound type system eliminates run-time type checking for type errors.
A programming language is strongly-typed
In practice, some of type checking operations are done at run-time (so, most of
the programming languages are not strongly-typed).
Ex: int x[100]; … x[i] most of the compilers cannot guarantee that i will
10 Manisha Mali
be between 0 and 99
Static Type Checking
Static checking examples:
Type checks.
Report an error if an operator is applied to an incompatible
operand
int a; char c; a=c;
Flow-of-control checks.
Statements that causes flow of control to leave a construct must
have some
place to which to transfer the flow of control
Uniqueness checks.
There are situations where an object must be defined exactly once.
labels, identifiers
Name-related checks.
Sometimes the same names may be appeared two or more times.
Beginning and end of a construct
11 Manisha Mali
Type Expression
The type of a language construct is denoted by a type expression.
A type expression can be:
A basic type
a primitive data type such as integer, real, char, boolean, …
type-error to signal a type error
void : no type
A type name
a name can be used to denote a type expression.
A type constructor applies to other type expressions.
arrays: If T is a type expression, then array(I,T) is a type expression where I denotes
index range. Ex: array(0..99,int) , int a[100];
products: If T1 and T2 are type expressions, then their Cartesian product T1 x T2 is a
type expression. Ex: int x int
pointers: If T is a type expression, then pointer(T) is a type expression. Ex:
pointer(int), int A; int *A; float *A;
12 Manisha Mali
Type Expression
functions: We may treat functions in a programming language as mapping from a domain type D to
a range type R. So, the type of a function can be denoted by the type expression D→R where D are
R type expressions. Ex: int→int represents the type of a function which takes an int value as
parameter, and its return type is also int.
Function f(a,b: integer) : integer
o Integer integer → pointer(integer)
Ex. Function Declaration [int test (int, float, char)]
Function Definition [int test (int X, float Y, char Z)]
Function Call [int P = test(5, 3.7, ‘A’)]
Records: The record type constructor will be applied to a tuple formed from field names and field
types.
Type row = record
address : integer;
lexeme: array[1..15] of char
end;
Var table: array[1..101] of row;
Declares the type name row representing the type expression
record( (address integer) (lexeme array(1..15,char) )
13 Manisha Mali
A Simple Type Checking System
P → D;E
D → D;D
D → id:T { addtype(id.entry,T.type) }
T → char { T.type=char }
T → int { T.type=int }
T → real { T.type=real }
T → ↑T1 { T.type=pointer(T1.type) }
T → array[intnum] of T1 { T.type=array(1..intnum.val,T1.type) }
14 Manisha Mali
Type Checking of Expressions
E → id { E.type=lookup(id.entry) }
E → charliteral { E.type=char }
E → intliteral { E.type=int }
E → realliteral { E.type=real }
16 Manisha Mali
Type Checking of Functions
E E1 ( E2 ) { if (E2.type=s and E1.type=st) then E.type=t
else E.type=type-error }
17 Manisha Mali
Syntax-Directed Translation
1. Grammar symbols are associated with attributes to associate information with the
programming language constructs that they represent.
2. Values of these attributes are evaluated by the semantic rules associated with the
production rules.
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.
E.Val return
E.Val + T.val
digit.lexval digit.lexval
E.Val return
E.Val + T.val
digit.lexval=5 digit.lexval=3
E.Val return
E.Val + T.val
digit.lexval=5 digit.lexval=3
E.Val return
E.Val + T.val
digit.lexval=5 digit.lexval=3
E.Val return
E.Val=5 + T.val=12
digit.lexval=5 digit.lexval=3
E.Val=17 return
E.Val=5 + T.val=12
digit.lexval=5 digit.lexval=3
E.val=17 return
E.val=5 + T.val=12
digit.lexval=5 digit.lexval=3
E.val=17
E.val=5 T.val=12
digit.lexval=5 digit.lexval=3
1. Symbols E, T, and F are associated with synthesized attributes loc and code.
2. The token id has a synthesized attribute name (it is assumed that it is evaluated by the lexical
analyzer).
3. It is assumed that || is the string concatenation operator.
D L.in=real
id id.entry=p
id
to entry for c
id num 4
to entry for a
41 Manisha Mali, Dept. Computer Engg., VIIT 27-Oct-20
Syntax Dir. Definition for Assignment Statements
PRODUCTION Semantic Rule
S id := E { S.nptr = mknode (‘assign’, mkleaf(id, id.entry), E.nptr) }
E - E1 {E.nptr = mknode(‘uminus’,E1.nptr) }
E ( E1 ) {E.nptr = E1.nptr }
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).
44
27-Oct-20
Manisha Mali, Dept. Computer Engg., VIIT
45