Ch6
Ch6
Yacc specification
Lex specification Type Code JVM specification
checking generation
3
Static Checking
• Typical examples of static checking are
– Type checks
– Flow-of-control checks
– Uniqueness checks
– Name-related checks
5
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
6
Flow-of-Control Checks
myfunc() myfunc()
{ … { …
break; // ERROR switch (a)
} { case 0:
…
myfunc() break; // OK
{ … case 1:
while (n) …
{ … }
if (i>10) }
break; // OK
}
}
7
Uniqueness Checks
myfunc()
{ int i, j, i; // ERROR
…
}
struct myrec
{ int name;
};
struct myrec // ERROR
{ int id;
};
8
Name-Related Checks
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
11
fun fun
struct
val next
int pointer
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
14
pointer = pointer
struct struct
val next val next
int pointer int
15
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
19
is a type
v := e : void to types :
(v) =
e1 : integer e2 : integer
e1 + e2 : integer
20
x := y + 2 : void
21
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
23
(v) = e:
v := e : void
e : boolean s:
if e then s :
S if E then S1 { S.type := (if E.type = boolean then S1.type
else type_error) }
25
e : boolean s:
while e do s :
s1 : void s2 : void
s1 ; s2 : void
S S1 ; S2 { S.type := (if S1.type = void and S2.type = void
then void else type_error) }
27
e1 : integer e2 : integer
e1 + e2 : integer
e1 : boolean e2 : boolean
e1 and e2 : boolean
e1 : array(s, ) e2 : integer
e1[e2] :
e : pointer()
e^ :
T T -> T EE(E)
Example:
v : integer;
odd : integer -> boolean;
if odd(3) then
v := 1;
33
Parametric type:
type constructor
34
e1 : function(, ) e2 :
e1(e2) :
%union
{ Type *typ;
}
%%
…
37
…
%%
%union
{ Node *rec;
}
%%
…
Checking L-Values and R-Values
40
in Yacc
expr : expr ‘+’ expr
{ if ($1->typ->type != Tint || $3->typ->type != Tint)
semerror(“non-int operands in +”);
$$->typ = mkint();
$$->islval = FALSE;
emit(…);
}
| expr ‘=’ expr
{ if (!$1->islval || $1->typ != $3->typ)
semerror(“invalid assignment”);
$$->typ = $1->typ;
$$->islval = FALSE;
emit(…);
}
| ID
{ $$->typ = lookup($1);
$$->islval = TRUE;
emit(…);
}
41
e1(e2) : β
length([“a”, “b”]) : integer
44
hd(x) : α1 append(tl(x), y) : list(α1)
cons(hd(x), append(tl(x), y)) : list(α2)
46
append([1, 2], [3]) : τ append([1, 2], [3]) : list(α)
τ = list(α)
α = integer
([1],[“a”]) : list(α) × list(α)
append([1], [“a”]) : τ append([1], [“a”]) : list(α)
Type error
48
Unification
An AST representation of append([], [1, 2])
apply
[] : list(φ) [ , ] : list(ψ)
1 : integer 2 : integer
50
Unification
An AST representation of append([], [1, 2])
apply