0% found this document useful (0 votes)
14 views44 pages

Static Check and Type System

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)
14 views44 pages

Static Check and Type System

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/ 44

1

Static Checking and Type


Systems
2
3

The Structure of our Compiler


Revisited
Syntax-directed
Character Token static checker Java
stream Lexical analyzer
stream Syntax-directed bytecode
translator

Yacc specification
Lex specification Code JVM specification
Type
generati
checking
on
4

Static versus Dynamic Checking


• Static checking: the compiler enforces
programming language’s static semantics
– Program properties that can be checked at
compile time
• Dynamic semantics: checked at run time
– Compiler generates verification code to enforce
programming language’s dynamic semantics
5

Static Checking
• Typical examples of static checking are
– Type checks
– Flow-of-control checks
– Uniqueness checks
– Name-related checks
6

Type Checking, Overloading,


Coercion, Polymorphism
class X { virtual int m(); } *x;
class Y: public X { virtual int m(); } *y;
int op(int), op(float);
int f(float);
int a, c[10], d;

d = c + d; // FAIL
*d = a; // FAIL
a = op(d); // OK: static overloading (C++)
a = f(d); // OK: coersion of d to float
a = x->m(); // OK: dynamic binding (C++)
vector<int> v; // OK: template instantiation
7

Flow-of-Control Checks
myfunc() myfunc()
{ … { …
break; // ERROR switch (a)
} { case 0:

myfunc() break; // OK
{ … case 1:
while (n) …
{ … }
if (i>10) }
break; // OK
}
}
8

Uniqueness Checks
myfunc()
{ int i, j, i; // ERROR

}

cnufym(int a, int a) // ERROR


{ …
}

struct myrec
{ int name;
};
struct myrec // ERROR
{ int id;
};
9

Name-Related Checks

LoopA: for (int I = 0; I < n; I++)


{ …
if (a[I] == 0)
break LoopB; // Java labeled loop

}
10

One-Pass versus Multi-Pass


Static Checking
• One-pass compiler: static checking in C, Pascal,
Fortran, and many other languages is performed in
one pass while intermediate code is generated
– Influences design of a language: placement constraints

• Multi-pass compiler: static checking in Ada, Java,


and C# is performed in a separate phase,
sometimes by traversing a syntax tree multiple
times
11

Type Expressions
• Type expressions are used in declarations
and type casts to define or refer to a type
– Primitive types, such as int and bool
– Type constructors, such as pointer-to, array-of,
records and classes, templates, and functions
– Type names, such as typedefs in C and named
types in Pascal, refer to type expressions
12
13
14

Graph Representations for Type


Expressions
int *f(char*,char*)

fun fun

args pointer args pointer

pointer pointer int pointer int

char char char

Tree forms DAGs


15

Cyclic Graph Representations


Source program
struct Node
{ int val;
struct Node *next;
};

struct

val next

int pointer

Internal compiler representation of


the Node type: cyclic graph
16

Name Equivalence
• Each type name is a distinct type, even
when the type expressions that the names
refer to are the same
• Types are identical only if names match
• Used by Pascal (inconsistently)
type link = ^node; With name equivalence in Pascal:
var next : link; p ≠ next
last : link; p ≠ last
p : ^node; p = q = r
q, r : ^node; next = last
17

Structural Equivalence of Type


Expressions
• Two types are the same if they are
structurally identical
• Used in C/C++, Java, C#

pointer = pointer
struct struct
val next val next
int pointer int
18

Structural Equivalence of Type


Expressions (cont’d)
• Two structurally equivalent type
expressions have the same pointer address
when constructing graphs by sharing nodes
struct Node p &s
{ int val;
struct Node *next; *p s pointer
};
struct
struct Node s, *p;
p = &s; // OK val next
*p = s; // OK
int
p = s; // ERROR
19

Type Systems
• A type system defines a set of types and
rules to assign types to programming
language constructs
• Informal type system rules, for example “if
both operands of addition are of type
integer, then the result is of type integer”
• Formal type system rules: Post systems
20
21
22
23
24
25
26
27
28
29

A Simple Language Example


P→D;S E → true
D→D;D ⎟ false
⎟ id : T ⎟ literal
T → boolean ⎟ num
⎟ char ⎟ id
⎟ integer ⎟ E and E
⎟ array [ num ] of T ⎟E+E
⎟^T ⎟E[E]
S → id := E ⎟E^
⎟ if E then S
⎟ while E do S Pointer to T Pascal-like pointer
⎟S;S dereference operator
30

Simple Language Example:


Declarations

D → id : T { addtype(id.entry, T.type) }
T → boolean { T.type := boolean }
T → char { T.type := char }
T → integer { T.type := integer }
T → array [ num ] of T1 { T.type := array(1..num.val, T1.type) }
T → ^ T1 { T.type := pointer(T1)

Parametric types:
type constructor
31

Simple Language Example:


Checking Statements

S → id := E { S.type := (if id.type = E.type then void else type_error) }

Note: the type of id is determined by scope’s environment:


id.type = lookup(id.entry)
32

Simple Language Example:


Checking Statements (cont’d)

S → if E then S1 { S.type := (if E.type = boolean then S1.type


else type_error) }
33

Simple Language Example:


Statements (cont’d)

S → while E do S1 { S.type := (if E.type = boolean then S1.type


else type_error) }
34

Simple Language Example:


Checking Statements (cont’d)

S → S1 ; S2{ S.type := (if S1.type = void and S2.type = void


then void else type_error) }
35

Simple Language Example:


Checking Expressions

E → true { E.type = boolean }


E → false { E.type = boolean }
E → literal { E.type = char }
E → num { E.type = integer }
E → id { E.type = lookup(id.entry) }

36

Simple Language Example:


Checking Expressions (cont’d)

E → E1 + E2 { E.type := (if E1.type = integer and E2.type = integer


then integer else type_error) }
37

Simple Language Example:


Checking Expressions (cont’d)

E → E1 and E2 { E.type := (if E1.type = boolean and E2.type = boolean


then boolean else type_error) }
38

Simple Language Example:


Checking Expressions (cont’d)

E → E1 [ E2 ] { E.type := (if E1.type = array(s, t) and E2.type = integer


then t else type_error) }

Note: parameter t is set with the unification of


E1.type = array(s, t)
39

Simple Language Example:


Checking Expressions (cont’d)

E → E1 ^ { E.type := (if E1.type = pointer(t) then t


else type_error) }

Note: parameter t is set with the unification of


E1.type = pointer(t)
40

A Simple Language Example:


Functions

T → T -> T E→E(E)

Function type declaration Function call

Example:
v : integer;
odd : integer -> boolean;
if odd(3) then
v := 1;
41

Simple Language Example:


Function Declarations

T → T1 -> T2 { T.type := function(T1.type, T2.type) }

Parametric type:
type constructor
42

Simple Language Example:


Checking Function Invocations

E → E1 ( E2 ) { E.type := (if E1.type = function(s, t) and E2.type = s


then t else type_error) }
43

Type Conversion and Coercion


• Type conversion is explicit, for example
using type casts
• Type coercion is implicitly performed by
the compiler to generate code that converts
types of values at runtime (typically to
narrow or widen a type)
• Both require a type system to check and
infer types from (sub)expressions
44

You might also like