Professional Documents
Culture Documents
• Regrades
– No more than one deduction for each error
– But you have to prove it to us . . .
• Semantic analysis
– Last “front end” phase
– Catches all remaining errors
1
What Does Semantic Analysis Do? Scope
• Checks of many kinds . . . coolc checks: • Matching identifier declarations with uses
1. All identifiers are declared – Important static analysis step in most languages
2. Types – Including COOL!
3. Inheritance relationships
4. Classes defined only once
5. Methods in a class defined only once
6. Reserved identifiers are not misused
And others . . .
2
Static Scoping Example (Cont.) Dynamic Scope
• Cool identifier bindings are introduced by • Not all kinds of identifiers follow the most-
– Class declarations (introduce class names) closely nested rule
– Method definitions (introduce method names)
– Let expressions (introduce object id’s) • For example, class definitions in Cool
– Formal parameters (introduce object id’s) – Cannot be nested
– Attribute definitions (introduce object id’s) – Are globally visible throughout the program
– Case expressions (introduce object id’s)
3
More Scope (Cont.) Implementing the Most-Closely Nested Rule
• Method/attribute names have complex rules • Much of semantic analysis can be expressed as
a recursive descent of an AST
• A method need not be defined in the class in
which it is used, but in some parent class – Before: Process an AST node n
– Recurse: Process the children of n
– After: Finish processing the AST node n
• Methods may also be redefined (overridden)
• Example: the scope of let bindings is one • Consider again: let x: Int 0 in e
subtree of the AST: • Idea:
– Before processing e, add definition of x to current
let x: Int 0 in e definitions, overriding any other definition of x
– Recurse
– After processing e, remove definition of x and
restore old definition of x
4
A Fancier Symbol Table Class Definitions
• enter_scope() start a new nested scope • Class names can be used before being defined
• find_symbol(x) finds current x (or null)
• We can’t check class names
• add_symbol(x) add a symbol x to the table – using a symbol table
– or even in one pass
• check_scope(x) true if x defined in current
scope • Solution
• exit_scope() exit current scope – Pass 1: Gather all class names
– Pass 2: Do the checking
We will supply a symbol table manager for your • Semantic analysis requires multiple passes
project – Probably more than two
• Certain operations are legal for values of each • A language’s type system specifies which
type operations are valid for which types
– It doesn’t make sense to add a function pointer and • The goal of type checking is to ensure that
an integer in C operations are used with the correct types
– Enforces intended interpretation of values,
– It does make sense to add two integers because nothing else will!
5
Type Checking Overview The Type Wars
– Statically typed: All or almost all checking of types • Static typing proponents say:
is done as part of compilation (C, Java, Cool) – Static checking catches many programming errors at compile
time
– Avoids overhead of runtime type checks
– Dynamically typed: Almost all checking of types is
done as part of program execution (Scheme) • Dynamic typing proponents say:
– Static type systems are restrictive
– Untyped: No type checking (machine code) – Rapid prototyping difficult within a static type system
• The compiler infers types for expressions • The two are different, but the terms are
– Infers a type for every expression often used interchangeably
6
Rules of Inference Why Rules of Inference?
• We have seen two examples of formal notation • Inference rules have the form
specifying parts of a compiler If Hypothesis is true, then Conclusion is true
– Regular expressions
– Context-free grammars • Type checking computes via reasoning
If E1 and E2 have certain types, then E3 has a
• The appropriate formalism for type checking certain type
is logical rules of inference
• Rules of inference are a compact notation for
“If-Then” statements
• The notation is easy to read with practice If e1 has type Int and e2 has type Int,
then e1 + e2 has type Int
• Start with a simplified system and gradually
add features (e1 has type Int e2 has type Int)
e1 + e2 has type Int
• Building blocks
– Symbol is “and” (e1: Int e2: Int) e1 + e2: Int
– Symbol is “if-then”
– x:T is “x has type T”
Prof. Aiken CS 143 Lecture 9 39 Prof. Aiken CS 143 Lecture 9 40
7
Two Rules Two Rules (Cont.)
Example: 1 + 2 Soundness
i is an integer
` i:Object
8
Rule for New Two More Rules
[New]
` new T: T ` e1 : Bool
` e2 : T
[Loop]
` while e1 loop e2 pool: Object
A Problem A Solution
• What is the type of a variable reference? • Put more information in the rules!
Let O be a function from ObjectIdentifiers to The type environment is added to the earlier
Types rules:
i is an integer
[Int]
The sentence O ` i: Int
O ` e: T
is read: Under the assumption that variables O ` e1 : Int
have the types given by O, it is provable that
the expression e has the type T O ` e2
: Int
[Add]
O ` e1 e2 : Int
Prof. Aiken CS 143 Lecture 9 53 Prof. Aiken CS 143 Lecture 9 54
9
New Rules Let
• The type environment gives types to the free Now consider let with initialization:
identifiers in the current scope
O ` e0 :T0
• The type environment is passed down the AST
from the root towards the leaves O[T0/x] ` e1 : T1 [Let-Init]
O ` let x:T0 e0 in e1 : T1
• Types are computed up the AST from the
leaves towards the root
This rule is weak. Why?
Subtyping Assignment
• Define a relation on classes • Both let rules are sound, but more programs
– XX typecheck with the second one
– X Y if X inherits from Y
– X Z if X Y and Y Z • More uses of subtyping:
10
Initialized Attributes If-Then-Else
• The rule for case expressions takes a lub over • There is a problem with type checking method
all branches calls:
O ` e0 : T0
O ` e1 : T1
O
O `` ee00 :: T
T00
O[T1 //x
O[T / x1 1]] ``e1e:1 T 1’
: 1T [Case] [Dispatch]
O ` en : Tn
OO``ie0e.f(e 1 ,,en )
0.f(e1,...,e
:
n): ?
O[T / xn]] ``een: T
O[Tnn //x :T n’
n n n
• We need information about the formal
OO``icase
case ee00 of x11:T11
) e11;
…;;xxnn:T ) eenn;; esac
:Tnn lub(T11’,…,T
esac : lub(T ,,T
n )
n’)
parameters and return type of f
11
Notes on Dispatch The Dispatch Rule Revisited
• The method environment must be added to all • For some cases involving SELF_TYPE, we need
rules to know the class in which an expression
• In most cases, M is passed down but not appears
actually used • The full type environment for COOL:
– Only the dispatch rules use M – A mapping O giving types to object id’s
– A mapping M giving types to methods
O,M ` e1 : Int – The current class C
O,M ` e2 : Int [Add]
O,M ` e1 e2 : Int
Prof. Aiken CS 143 Lecture 9 71 Prof. Aiken CS 143 Lecture 9 72
12
Sentences Type Systems
The form of a sentence in the logic is • The rules in this lecture are COOL-specific
– More info on rules for self next time
O,M,C ` e :T – Other languages have very different rules
• General themes
– Type rules are defined on the structure of
Example: expressions
O,M,C ` e1 : int – Types of variables are modeled by an environment
O,M,C ` e2 : int [Add]
• Warning: Type rules are very compact!
O,M,C ` e1 e2 : int
Prof. Aiken CS 143 Lecture 9 73 Prof. Aiken CS 143 Lecture 9 74
13