×
Stay dedicated because great things takes time.
--Your friends at LectureNotes
Close

Compiler Design

by Kiran KumarKiran Kumar
Type: NoteInstitute: ACET/JNTUK Course: B.Tech Specialization: Computer Science EngineeringViews: 8Uploaded: 2 months ago

Share it with your friends

Suggested Materials

Leave your Comments

Contributors

Kiran Kumar
Kiran Kumar
Type Checking Type checker verifies that the type of a construct (constant, variable, array, list, object) matches what is expected in its Computer Science 332 usage context. E.g., Java's % (modulo) operator expects two integers, so Compiler Construction Chapter 6: Type Checking (Skip 6.4) 3%4.5 is a type error. Some operators (+, -, *, /) are "overloaded"; i.e., they can apply to objects of different types (int, real). Functions may be polymorphic; i.e., accept arguments of different types. 6.1 Type Systems Type Constructors Type checker needs to know about Cartesian Product: If T1 and T2 are type expressions, then – Syntactic constructs in language (e.g., operators) T1 X T2 is a type expression (e.g., ML tuples) – Basic types of language (int, real) – Rules for assigning types to constructs Function:If T1 and T2 are type expressions, then T1 type expression (e.g., ML functions) E.g., "if both operands of + are int, result is int"  Leads to recursively defined type expression: – Basic type: int, real – Type variable (α, β, ...) – Result of applying type constructor to type expression mod: X int int int  T2 is a
6.2 Specification of a Simple Type Checker Static vs. Dynamic Type Checking Static: Done at compile time (e.g., Java) Consider a language (e.g., Java) that requires that an identifier Dynamic: Done at run time (e.g., Scheme) be declared with a type before the variable is used. Sound type system is one where any program that passes the For simplicity, we'll declare all identifiers before using them in static type checker cannot contain run-time type errors. Such a single expression: languages are said to be strongly typed. P D T E Some errors can only be detected at run-time; e.g., array out-ofbounds: int [] a = new int [10]; for (int i=0; i<20; ++i) a[i] = i; Type Checking of Statements Add syntax-directed definitions to type-check expressions: D T T T T id char int T1 [ num ] { addtype (id.entry, T.type ) } { T.type := char } { T.type := integer } { T.type := array (0..num.val-1, T1.type ) } E E id E1 mod E2 { E.type := lookup ( id.entry ) } { E.type := if E1.type = integer and E2.type = integer then integer E E1 [ E2 ] else type_error } { E.type := if E2.type = integer and E1.type = array(s,t) then t else type_error } Where addtype, lookup are symbol-table methods, array is a type constructor D;E D ; D | T id char | int | T [ num ] id | E mod E | E [ E ] A more realistic language would also have statements (whose type is trivially void ) P D;S S id := E S if E then S1 { S.type := if id.type = E.type then void else type_error } { S.type := if E.type = boolean then S1.type S S1 ; S2 else type_error } { S.type := if S1.type = void and S2.type = void then void else type_error }
Type Checking of Functions We can declare function types using a rule: T T1 ' ' T2 { T.type := function (T1 , T2 ) } 6.3 Equivalence of Type Expressions Need a way of implementing checks like "E2.type = s" Structural Equivalence: Recursive definition: where function is another type constructor ML supports this, but in practice function types are usually inferred. In either case, we need to type-check function application: E function sequiv(s, t) : boolean if s and t are the same basic type then return true else if s = array(s1, s2) and t = array(t1, t2) then return sequiv(s1, t1) and sequiv(s2, t2) E1 ( E2 ) { E.type := { if E2.type = s and else if s = cartesian(s1, s2) and t = cartesian(t1, t2) then E1.type = function(s,t) then t return sequiv(s1, t1) and sequiv(s2, t2) else type_error } else if s = function(s1, s2) and t = function(t1, t2) then return sequiv(s1, t1) and sequiv(s2, t2) else return false 6.5 Overloading of Functions and Operators Some operators (+, -, *, /) are "overloaded"; i.e., they can apply to objects of different types (int, real). Overloading is resolved when we determine the actual type Arguments alone do not always resolve operator's type; e.g, in Java type of 3*5 may resolve to either int or double, depending on context: 3*5+2 (int) or 3*5+2.0 (double) We allow the .type attribute to be a set of types, and add code to narrow this set to a single type for a given expression Add an attribute .unique to contain unique type, and a special symbol E' to support narrowing: E' E E id E E1 ( E2 ) { E'.types := E.types E.unique := if E.types = {t} then t else type_error } { E.types := { lookup ( id.entry ) } } { E.types := s' | ∃ s ∈ E2.types such that function(s, s') ∈ E1.types t := E.unique S := { s | s ∈ E2.types and function(s,t) ∈ E1.types } E2.unique := if S = {s} then s else type_error E1.unique := if S = {s} then function(s,t) else type_error }

Lecture Notes