CS301 W'99 Lecture Notes Lecture 14 PSU CS301 W'99 Lecture 14 Oc Andrew Tolmach 1992-99 1 Syntax-Directed Type Checking Consider a simple language of declarations, statements, and expressions. P ! D ; S Actions for declarations trigger symbol table entries (or syn- thesize environment attributes): D ! D1 ; D2 D ! D1 id : T1 { addtype(id, T1 .type) } T ! bool { T.type := boolean } T ! int { T.type := integer } T ! array[num]of T1 { T.type := array(num.val,T1 .type) } T ! T1 * { T.type := pointer(T1 .type) } Actions for expressions check for compatible operands and synthesize attribute type: E ! num { E.type := integer } E ! id { E.type := lookuptype(id) } E ! E1 div E2 { if E1 .type = integer and E2 .type = integer then E.type := integer else issue type error } PSU CS301 W'99 Lecture 14 Oc Andrew Tolmach 1992-99 2 More Expressions E ! E1 [ E2 ] { if E1 .type = array(I,T) and E2 .type = integer then E.type := T else issue type error } E ! *E1 { if E1 .type = pointer(T) then E.type = T else issue type error } E ! E1 < E2 { if E1 .type = integer and E2 .type = integer then E.type := boolean else issue type error } E ! E1 or E2 { if E1 .type = boolean and E2 .type = boolean then E.type := boolean else issue type error } E ! E1 = E2 { if (E1 .type = boolean or E2 .type = integer) and E1 .type = E2 .type then E.type := boolean else issue type error } As shown, these actions abort immediately if there is an error. Alternatively, can continue to look for more errors; in this case, synthesized value should be chosen to avoid cascades of messages from a single mistake (e.g., last three always return boolean). PSU CS301 W'99 Lecture 14 Oc Andrew Tolmach 1992-99 3 Checking Statements In most languages, statements don't have a type, so no point in synthesizing an attribute. Actions just check component types: S ! id := E1 { if E1 .type 6= lookuptype(id) then issue type error } (Must also check that id is an l-value that can be assigned into.) S ! if E1 then S1 { if E1 .type 6= boolean then issue type error } S ! S1 ; S2 { } Procedure/Function Definitions and Calls Describe type of function as type 1 x type 2 x : : : x type n ! type D ! id ( F1 ) : T1 { addtype(id,F1 .type ! T1 .type) } F ! T1 { F.type := T1 .type} F ! T1 , F1 { F.type := T1 .type x F1 .type} E ! id ( A1 ) { if lookuptype(id) = T1 ! T2 then if A1 .type = T1 then E.type := T2 else issue type error else issue type error } A ! E1 { A.type := E1 .type } A ! E1 , A1 { A.type := E1 .type x A1 .type } PSU CS301 W'99 Lecture 14 Oc Andrew Tolmach 1992-99 4 Type Conversions Implicit conversions (or "coercions") occur as a result of applying semantic rules of the language, e.g., perhaps eval- uating r + i where r is a real and i is an integer, causes implicit conver- sion of the fetched value of i to a real before the additon. Note that there's no effect on the permanent contents of i. Explicit conversions (programmer-specified) include opera- tors like ord and chr in Pascal or casts in C. Sometimes these just change type at compile time and don't affect runtime code, but details may depend on target ma- chine, e.g., int i; char *p; p = (char *) i; generates no code on a SPARC, but changes representation on a CRAY-2, and may move i to an "a-register" on M68K. PSU CS301 W'99 Lecture 14 Oc Andrew Tolmach 1992-99 5 Type-checking with Conversions Conversions complicate type-checking (as well as code gen- eration), e.g.: E ! E1 + E2 { case (E1 ,E2 ) of (integer,integer): E.type := integer (integer,real): (real,integer): (real,real): E.type := real otherwise: issue type error }