lecture #16, march 7, 2007

26
Cse321, Programming Languages and Compilers 1 05/13/22 Lecture #16, March 7, 2007 Mutual Recursion Symbol Tables Class Hierarchies Type checkers that rebuild code

Upload: buffy

Post on 12-Jan-2016

31 views

Category:

Documents


0 download

DESCRIPTION

Lecture #16, March 7, 2007. Mutual Recursion Symbol Tables Class Hierarchies Type checkers that rebuild code. 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. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 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

Page 2: Lecture #16,  March 7, 2007

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

Page 3: Lecture #16,  March 7, 2007

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.

Page 4: Lecture #16,  March 7, 2007

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

Page 5: Lecture #16,  March 7, 2007

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;

Page 6: Lecture #16,  March 7, 2007

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);

Page 7: Lecture #16,  March 7, 2007

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

Page 8: Lecture #16,  March 7, 2007

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

Page 9: Lecture #16,  March 7, 2007

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

Page 10: Lecture #16,  March 7, 2007

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, . . .

Page 11: Lecture #16,  March 7, 2007

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.

Page 12: Lecture #16,  March 7, 2007

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.

Page 13: Lecture #16,  March 7, 2007

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.

Page 14: Lecture #16,  March 7, 2007

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

Page 15: Lecture #16,  March 7, 2007

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

Page 16: Lecture #16,  March 7, 2007

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.

Page 17: Lecture #16,  March 7, 2007

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

Page 18: Lecture #16,  March 7, 2007

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

Page 19: Lecture #16,  March 7, 2007

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 _ ,[ ])

Page 20: Lecture #16,  March 7, 2007

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;

Page 21: Lecture #16,  March 7, 2007

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

Page 22: Lecture #16,  March 7, 2007

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)

Page 23: Lecture #16,  March 7, 2007

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

Page 24: Lecture #16,  March 7, 2007

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.

Page 25: Lecture #16,  March 7, 2007

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))

Page 26: Lecture #16,  March 7, 2007

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.