Lecture #16, March 7, 2007
description
Transcript of Lecture #16, March 7, 2007
Cse321, Programming Languages and Compilers
104/21/23
Lecture #16, March 7, 2007
•Mutual Recursion
•Symbol Tables
•Class Hierarchies
•Type checkers that rebuild code
Cse321, Programming Languages and Compilers
204/21/23
Assignments
• Reading – Finish Chapter 4. Sections 4.4, 4.5, and 4.6 pages 188-208
– Read Section 5.7 on Symbol tables page 238-248
– Possible Quiz next Monday.
• Project 3 is due Monday March 19
Cse321, Programming Languages and Compilers
304/21/23
Mutual Recursion
• Mutual recursion is found in almost all real languages
• Mutual recursion requires different techniques– Multiple passes.
– One pass to build a temporary table with just the information about the mutually recursive entities
– Second pass to type the recursive entities where the current scope is extended with the temporary table.
» Inside this pass, the table is often extended even more to capture information about entities declared in a single one of the mutually recursive entities.
– Finally, the temporary table is exported to the scope in which the mutually recursive entities exist.
Cse321, Programming Languages and Compilers
404/21/23
Example in ML
val x = 56;
fun f x = x + 5;
fun even n =
if n=0
then true else odd (n-1)
and odd n =
if n=0
then false
else if n=1
then true
else even (n-1);
val main = even(f x)
x: int
x: int
f: int -> int
x: int
f: int -> int
even: int->bool
odd: int->bool
x: int
f: int -> int
even: int->bool
odd: int->bool
n: int
x: int
f: int -> int
even: int->bool
odd: int->bool
main: bool
Cse321, Programming Languages and Compilers
504/21/23
Concrete Exampleand Dec
= Valdec of (string*MLtype)*Exp
| Fundec of (string*MLtype*MLtype)*string*Exp
| Mutdec of Dec list
• Assume we represent declarations as above.• Every val and fun declaration contains
explicit information about their types (as is true in Mini-Java)
• Then the concrete syntax may look like:
val (x:int) = 56;
fun (f:int->int) (x:int) = x + 5;
Cse321, Programming Languages and Compilers
604/21/23
Type Checking Declarations
• Type checking will depend upon two attribute computations.
• Checking declarations will map an environment to a delta environment.
• New environment will be the old one plus the delta.
TCExp:Exp ->(string * MLtype)list ->MLtype
TCDec:Dec ->(string * MLtype)list ->(string * MLtype) list
x: int
f: int -> int
even: int -> bool
odd: int -> bool
fun (even:int ->bool) (n:int) = if n=0 then true else odd (n-1)and (odd:int -> bool) (n:int) = if n=0 then false else if n=1 then true else even (n-1);
Cse321, Programming Languages and Compilers
704/21/23
Non mutually recursive casesfun TCDec (Valdec((nm,t),exp)) cntxt =
let val bodyt = TCExp exp cntxt
in if typeeq(t,bodyt)
then [(nm,t)]
else unexpected exp bodyt t end
| TCDec (Fundec((f,dom,rng),x,body)) cntxt =
let val ft = Arrow(dom,rng)
val bodyt = TCExp body((x,dom)::cntxt)
(* f is not recursive unless inside a Mutdec *)
in if typeeq(bodyt,rng)
then [(f,ft)]
else unexpected body bodyt rng
end
Cse321, Programming Languages and Compilers
804/21/23
Mutually recursive case| TCDec (Mutdec ds) cntxt =
let fun pass1 [] cntxt = cntxt
| pass1 (Valdec(p,b)::ds) cntxt =
pass1 ds (p::cntxt)
| pass1 (Fundec((f,d,r),x,b)::ds) cntxt =
pass1 ds ((f,Arrow(d,r))::cntxt)
val temp = pass1 ds cntxt
val pass2 = map (fn d => TCDec d temp) ds
in List.concat pass2 end;
x: int
f: int -> int
odd: int->bool
even: int->boolx: intf: int -> int
even: int->bool
odd: int->bool
even: int->bool
odd: int->bool
cntxt temp pass2 result
Cse321, Programming Languages and Compilers
904/21/23
Symbol Tables
• Symbol Tables map names to information• Many kinds of Names
– Variables
– Procedure and function names
– Labels
– Data Structure names (Constructors in ML or named Struct in C)
– Types
• Many kinds of information– Type
– Physical location in source (line number)
– Size
– Storage class
– Lexical location (Inside what class)
– Location in memory in the translation
Cse321, Programming Languages and Compilers
1004/21/23
Multiple symbol tables• Compilers might use one big table, or many smaller
ones.• Multiple tables have advantages
– Each table stores uniform items
– Tables might have limited scope and can be recycled
– Each table can use different implementation
» Hash Table
» Linked List
» Balanced Tree
– Each table probably has different access patterns
» Create Once, then read only
» Block Structured, so stack allocation is possible
» Insertions only
» Both insertions and deletions
• Tables can have mutable or non-mutable data• Language may have multiple name spaces
– Types, labels, variables, selectors, . . .
Cse321, Programming Languages and Compilers
1104/21/23
Nested Scope
• Many tables record information with block structure or nested scope.
• Stack allocation is possible• Easy to implement in a functional language
like ML – Use inherited attribute computation
– Table becomes a parameter to the function
– Entering new block means a new call to function with the parameter augmented.
– Exiting scope means restoring the old parameter
» Natural in a functional style since the old parameter is always still around.
Cse321, Programming Languages and Compilers
1204/21/23
Operations on nested scope• Initialize Scope• Insert name value Scope• Lookup name Scope• Finalize Scope
type ('name,'value)table = ('name * 'value) list;type ('name,'value)Scope = (('name,'value)table) list ;
fun initialize scope = [ ] :: scopefun insert name value (table::scope) = ((name,value)::table)::scopefun Lookup name (table::scope) = case List.find (fn (x,y) => x=name) table of NONE => error | SOME (x,y) => yfun finalize (table::scope) = scope
More sophisticated kinds of tables can be used
here rather than a linked list of pairs. Hash
Tables, Balanced trees, etc.
Cse321, Programming Languages and Compilers
1304/21/23
Data Structures for the MiniJava Type Checker
• Scope in object oriented languages like mini-java is attached to the class structure.
• Each class has its own symbol table– Usually this table is an ordinary nested scope table
• Each class must link to the symbol table for its super-class.
• The Class hierarchy is a tree of symbol tables.
• The set of operations on the tables can be found by inspecting the type rules.
Cse321, Programming Languages and Compilers
1404/21/23
Judgments from the type rulesTh, C, TE |- exp : type
Th, R, C, TE |= stmt
C |~ t1 ≤ t2
t1 = t2
C defines x
In C p has method f
In C p has variable x
Op <+> : (t1,t2) -> t3
t is basic
Cse321, Programming Languages and Compilers
1504/21/23
Data Structuredatatype CTab
= Node of
Id * (* Class Name *)
(Id * Type)list * (* Class Variables *)
(Id * Type list * Type)list * (* Methods *)
CTab ref * (* Parent Class *)
CTab list (* Sub Classes *)
| NullClass;
val root = Node("object",[],[],ref NullClass,[]);
CTab for class table is an n-way branching tree.object
numericpoint
int double
boolean
colorpoint
void
Cse321, Programming Languages and Compilers
1604/21/23
newClassfun newClass name vars methods parent NullClass = NullClass | newClass name vars methods parent (n as Node(nm,vs,ms,p,subs)) = if parent=nm then let val p1 = ref n val new = Node(name,vars,methods,p1,[]) val newP = Node(nm,vs,ms,p, new :: subs) val _ = p1 := newP in newP end else Node(nm,vs,ms,p, map (newClass name vars methods parent) subs)
• newClass creates a new class hierarchy from the old one. The old one is unchanged.
Cse321, Programming Languages and Compilers
1704/21/23
val t1 = newClass "point" [] [] "object" root;
Node(“object”, [ ], [ ], ref NullClass,[ ])
Node(“point”, [ ], [ ], ref _ ,[ ])
root
new
Node(“object”, [ ], [ ], ref NullClass,
[Node(“point”, [ ], [ ], ref _ ,[ ])])
newP
•The final step is to overwrite the pointer to root with newP, and then return newP
•newClass rebuilds the part of the tree that are unchanged
•The references make cyclic structures
Cse321, Programming Languages and Compilers
1804/21/23
val t1 = newClass "point" [] [] "object" root;val t2 = newClass "colorpoint" [] [] "point" t1;
Node(“point”, [ ], [ ], ref _ ,[ _ ])
Node(“object”, [ ], [ ], ref NullClass ,[ _ ])
Node(“colorpoint”, [ ], [ ], ref _ ,[ ])
t2
Cse321, Programming Languages and Compilers
1904/21/23
val t1 = newClass "point" [] [] "object" root;val t2 = newClass "colorpoint" [] [] "point" t1;val t3 = newClass "person" [] [] "object" t2
Node(“point”, [ ], [ ], ref _ ,[ _ ])
Node(“object”, [ ], [ ], ref NullClass ,[ _ , _ ])
Node(“colorpoint”, [ ], [ ], ref _ ,[ ])
t3
Node(“person”, [ ], [ ], ref _ ,[ ])
Cse321, Programming Languages and Compilers
2004/21/23
C defines x
fun defines name NullClass = false
| defines name (Node(n,vs,ms,p,ss)) =
if name=n
then true
else List.exists (defines name) ss;
Cse321, Programming Languages and Compilers
2104/21/23
t1 = t2
fun basiceq (x,y) =
case (x,y) of
(Real,Real) => true
| (Int,Int) => true
| (Bool,Bool) => true
| (_,_) => false
fun typeeq (x,y) =
case (x,y) of
(BasicType x,BasicType y) => basiceq(x,y)
| (ArrayType x,ArrayType y) => basiceq(x,y)
| (ObjType x,ObjType y) => x=y
| (VoidType,VoidType) => true
| (_,_) => false
Cse321, Programming Languages and Compilers
2204/21/23
C |~ t1 ≤ t2
fun useTree NullClass (x,y) = false
| useTree (Node(nm,vs,ms,p,ss)) (x,y) =
if nm = y
then List.exists (defines x) ss
else List.exists (fn t => useTree t (x,y)) ss
fun subtype classH (x,y) =
case (x,y) of
(x,ObjType "object") => true
| (BasicType Int,ObjType "numeric") => true
| (BasicType Real,ObjType "numeric") => true
| (ObjType x,ObjType y) => useTree classH (x,y)
| (_,_) => typeeq(x,y)
Cse321, Programming Languages and Compilers
2304/21/23
Type checkers that rebuild the syntax tree
• Some type checkers use inference to add things to the syntax tree that are missing.– Coercions
» 3 + 5.6 -> toFloat 3 + 5.6
– Implicit class information
» X.f(3,5) -> X.ffrompoint(2,5)
– Implicit type information
» (fn x => x + 1) -> (fn (x:Int) => x + 1)
• Such type checkers return a tuple.– The tuple includes the synthesized attributes and a new syntax
tree. Compare the two types
– TCExp2: Exp -> (string * MLtype) list -> MLtype * Exp
– TCExp: Exp -> (string * MLtype) list -> MLtype
Cse321, Programming Languages and Compilers
2404/21/23
TCExp2fun TCExp2 x cntxt = case x of Lit c => (TCConstant c,x) | Var s => (case List.find (fn (nm,t) => nm=s) cntxt of SOME(nm,t) => (t,x) | NONE => error x "Undeclared variable") | Infix(l,x,r) => let val (ltype,l2) = TCExp2 l cntxt val (rtype,r2) = TCExp2 r cntxt val (lneed,rneed,result) = TCOp x in case (typeeq(ltype,lneed),typeeq(rtype,rneed)) of (true,true) => (result, Infix(l2,x,r2) ) | (true,false) => unexpected r rtype rneed | (false,true) => unexpected l ltype lneed | (false,false) => unexpected l ltype lneed end
When a term has no sub terms, the old term can
usually be returned
Sub terms are rebuilt and the
returned term is constructed from these.
Cse321, Programming Languages and Compilers
2504/21/23
Why Bother• If all we ever do is return the same tree, why bother?• We use type (or other) information to add little bits of syntax.
Infix(l,x,r) => let val (ltype,l2) = TCExp2 l cntxt val (rtype,r2) = TCExp2 r cntxt val (lneed,rneed,result) = TCOp x in case (typeeq(ltype,lneed),typeeq(rtype,rneed)) of (true,true) => Fix result (x,ltype,rtype) l2 r2 | (true,false) => unexpected r rtype rneed | (false,true) => unexpected l ltype lneed | (false,false) => unexpected l ltype lneed end
fun Fix result info left right = case info of (Plus,Int,Real) => (result,Infix( Int2Real left ,Plus,right)) | (Plus,Real,Int) => (result,Infix(left,Plus, Int2Real right )) | (oper, _ , _ ) => (result,Infix(left,oper,right))
Cse321, Programming Languages and Compilers
2604/21/23
Class exercise
• As an in class exercise, lets continue the function on the previous pages.
• Start with an non rebuilding type-checker– Make a copy of it.
• Rename every call to a new name (so it doesn’t conflict)
• For each returned expression add a another value to the tuple.
• For each recursive call, accept (or pattern match against) an additional value.