You are on page 1of 39

Principles of Compiler Design

Course Outline
1. Introduction
2. Lexical Analysis
3. Syntax Analysis
4. Syntax Directed Translation
5. Symbol Tables & Type Checking
6. Intermediate Code Generation
7. Run Time Environment
8. Code Generation
9. Code Optimization
1
By: Yohannes Taye Jemberie
Chapter 5: Symbol Tables & Type Checking
Type and Issues in typing
Static Checking
Type Checking
Type Systems
Type Expressions
Type Constructors
Specification of a Simple Type Checker
Equivalence of types
Type Conversions
Types
• Type =
– a set of values
– operations that are allowed on these values.
• Why?
– To generate better code, with less runtime
overhead
– To avoid runtime errors

By: Yohannes Taye Jemberie 3


Type
• Type system for a programming language:
– set of types AND
– rules that specify how a typed program is allowed to
behave
• Actions
– Type checking
• Given an operation and an operand of some type,
determine whether the operation is allowed on that
operand

By: Yohannes Taye Jemberie 4


– Type inference
• Given the type of operands, determine
– the meaning of the operation
– the type of the operation
• OR, without variable declarations, infer type from the
way the variable is used.

By: Yohannes Taye Jemberie 5


Issues in typing
• Does the language have a type system?
– Untyped languages (e.g. assembly) have no type system at all
• When is typing performed?
– Static typing: At compile time
– Dynamic typing: At runtime
• How strictly are the rules enforced?
– Strongly typed: No exceptions
– Weakly typed: With well-defined exceptions
• Type equivalence & subtyping
– When are two types equivalent?
• What does "equivalent" mean anyway?
– When can one type replace another?

By: Yohannes Taye Jemberie 6


Static Checking
• The compiler must check if the source
program follows semantic conventions of the
source language.
• This is called static checking (to distinguish it
from dynamic checking executed during
execution of the program).
• Static checking ensures that certain kind of
errors are detected and reported.

By: Yohannes Taye Jemberie 7


Static Checking (cont’d)
• The following are examples of static checks:
– Type checks
• compatibility checking between operands
– (e.g., a[i] + a[i+1])
– Flow control check
Examples:
• A break instruction in C that is not in an inclosing statement
• A return in Pascal that is not in a function’s body

By: Yohannes Taye Jemberie 8


– uniqueness checks
• the situation in which an object must be defined exactly once
– e.g.,
» an identifier in Pascal

– Name related checks


• the situation in which the same name must appear more than one
times

Example:
• In Ada loops can have names. However, the same name should be
used to start and end the loop.

By: Yohannes Taye Jemberie 9


Type Checking
• Type Checking ?
– The processes of identifying errors in a program
based on explicitly or implicitly stated type
information
• Static (Compile time) vs. Dynamic (Run-time)
• Strongly typed language vs. weakly type language

• Kind Checking
– The processes of identifying errors in a program
based on stated kind information
• Variables
• Functions/procedures

By: Yohannes Taye Jemberie 10


• A type checker verifies that the type construct
matches that expected by its context.
– For example, a type checker should verify that the
type value assigned to a variable is compatible
with the type of the variable.
For instance, mod (%) expects two integer
operands

By: Yohannes Taye Jemberie 11


Type Checking

TYPE CHECKING is the main activity in semantic


analysis.
Goal: calculate and ensure consistency of the type
of every expression in a program
If there are type errors, we need to notify the user.
Otherwise, we need the type information to
generate code that is correct.

By: Yohannes12
Taye Jemberie
Type Systems
• Every language has a set of types and rules for
assigning types to language constructs.
• In almost all languages, types are either basic
or constructed.
• Two types
– Basic types
– Constructed types

By: Yohannes Taye Jemberie 13


Type Systems:
• Basic types
– Atomic types with no internal structure
• e.g.,
– Boolean (AND/OR/XOR operations)
– Characters (STRING OPERATIOSNS)
– Numbers ( *, /, -, + operators)
– Void (null value)

By: Yohannes14
Taye Jemberie
• Constructed types (user-defined types)
– types that are constructed from basic types and
other constructed types
– Var A: Array [1..10] of integer

By: Yohannes Taye Jemberie 15


Type Expressions
• The type of a language construct will be
denoted by a type expression.
• A type expression is either a basic type or
formed by applying an operator called type
constructor to the type expression.
• The type expression may be obtained by using
the following definition.

By: Yohannes Taye Jemberie 16


Type Expressions (cont’d)
• In this chapter the following are type expressions:
– A basic type is a type expression
Ex. Integer, boolean, char, …
– A type name is a type expression
– A type constructor applied to a type expression is a type
expression.
• The type checker uses two more basic types:
– Void  indicates absence of type error
– Type_error  indicates the presence of a type error

By: Yohannes Taye Jemberie 17


Type Constructors
• The following are type constructors:
– Arrays: if I in an index set and T is a type expression, then
Array (I, T) is a type expression
Ex. Array([1..10], integer) is a type expression
– Products: if T1 and T2 are type expressions, the Cartesian
product T1 x T2 is a type expression. X is left associative.
Ex. In function parameters f(True, 5) = Boolean X int

By: Yohannes Taye Jemberie 18


• Records: a record is a special kind of product in which the
fields have names
Record( (field1 X T1)X(field2 X T2)X… )

Ex. struct{ int age; float cgpa; }


record( ( age X integer ) X ( cgpa X float ) )

– Pointers: if T is a type exrpession then Pointer (T) is a type


expression

Ex. Pointer( Integer )

By: Yohannes Taye Jemberie 19


Type Constructors (cont’d)
– Functions:Functions in a programming language
map a domain type D to a range type R.
– the TE of a function has the form
D  R where D is the type expression of the
parameters and R is the TE of the returned value
Ex. int * f (char a, char b)
char X char  Pointer( Integer )

By: Yohannes Taye Jemberie 20


Graph Representation
• A convenient way to represent a type expression is to
use a graph (tree or Graph).
• For example, the type expression corresponding to
the above function declaration is shown below:

X Pointer

char char Integer

char X char  Pointer( Integer )


By: Yohannes Taye Jemberie 21
Type System
• A type system is a collection of rules
implemented by the type checker for
assigning type expressions to the various parts
of a program.
• Different type systems may be used by
different compilers for the same language.
• For example, some compilers implement
stricter rules than others. Lint, for instance,
has much more detailed type system than the
C compiler itself.
By: Yohannes Taye Jemberie 22
Errors
• At the very least, the compiler must report the
nature and location of errors.

• It is also desirable that the type checker


recovers from errors and continues parsing
the rest of the input.

By: Yohannes Taye Jemberie 23


Specification of a Simple Type Checker
• Declarations
The purpose of the semantic actions is to determine
the type expression of a variable and add the type
expression in the symbol table
PD;E
DD;D
D  id : T {addtype (id.lexeme, T.Type)}
T  char {T.type := char}
T  integer {T.type := integer}
T  ^T1 {T.type := pointer (T1.type)}
T  array [num1..num2] of T1
{T.type := array ([num1.val..num2.val], T1.type)}
By: Yohannes Taye Jemberie 24
Simple Type Checker (cont’d)
• Example
Consider the following declarations
A : array[1..10] of ^ array[1..5] of char;
B : char;

Draw the decorated parse tree for the given


declaration.

By: Yohannes Taye Jemberie 25


Simple Type Checker (cont’d)

• Expressions
E  literal
E  num
E  id
E  E1 mod E2
E  E1[E2]
E  ^E1
By: Yohannes Taye Jemberie 26
Simple Type Checker (cont’d)
• Expressions
E  literal {E.type := char}
E  num {E.type := integer}
E  id {E.type := lookup (id.lexeme)}
E  E1 mod E2 {E.type := if E1.type = integer and E2.type := integer then
Integer
Else
Type_error
}
E  E1 [E2] {
E.type := if E2.type = integer and E1.type := array (s, t) then
t
Else
Type_error
}
E  ^E1 { E.type := if E2.type = pointer (t) then
t
Else
Type_error }
By: Yohannes Taye Jemberie 27
Simple Type Checker (cont’d)
• Statements

S  id := E
S  if E then S1
S  while E do S1
S  S1 ; S2

By: Yohannes Taye Jemberie 28


Simple Type Checker (cont’d)
• Statements
S  id := E {S.type := if id.type = E.type then
void
Else
Type_error}
S  if E then S1 {S.type := if E.type = Boolean then
S1.type
Else
Type_error}
S  while E do S1 {S.type := if E.type = Boolean then
S1.type
Else
Type_error}
S  S1 ; S 2 {S.type := if S1.type = void and S2.type = void then
void
Else
Type_error}
By: Yohannes Taye Jemberie 29
Simple Type Checker (cont’d)
The following example gives a type checking
system for function calls:
E  E1 (E2)
{ E.type := if E2.type = s and E1.type = s  t then
t
Else
Type_error
}

By: Yohannes Taye Jemberie 30


Equivalence of types
• Types MUST be checked for compatibility and equivalent
• Examples include
– Assignment statements
– Formal and actual parameters of procedure/function calls
• Compilers must detect and report any situation that
violates the type incompatibility
– e.g., found integers but compilers expected real
Type checkers need to ask questions like:
– “if E1.type == E2.type, then …”
What does it mean for two type expressions to be equal?

By: Yohannes Taye Jemberie 31


Equivalence of types (cont’d)
• There are two kinds of type equivalence
– Name equivalence (used for almost all languages)
– Structural equivalence (difficult to implement)

• A natural notion of equivalence is structural equivalence:

By: Yohannes Taye Jemberie 32


Name equivalence
• Two types are name equivalent if they have
the SAME NAME
• e.g.
– Type t1 = Array [1..10] of integer;
– Type t2 = Array [1..10] of integer;
– are they name equivalent? No because they have
distinct type definitions (names)

By: Yohannes Taye Jemberie 33


Structural equivalence
• two type expressions are structurally equivalent if and only if
they are the same basic type or are formed by applying the
same constructor to structurally equivalent types.
• For example,
– integer is equivalent only to integer
– pointer (integer) is structurally equivalent to pointer (integer).
• Some relaxing rules are very often added to this notion of
equivalence.
– For example, when arrays are passed as parameter, the array
boundaries of the effective parameters may not be the same as those
of the formal parameters.

By: Yohannes Taye Jemberie 34


Equivalence of types (…cont’d)
• In some languages, types may be given names. For
example in Pascal we can define:
Type:
Ptr = ^Integer;
Var
A : Ptr;
B : Ptr;
C : ^Integer;
D, E : ^Integer;
• Have the variables A, B, C, D, E the same type?
Surprisingly, the answer varies from implementation
to implementation.
By: Yohannes Taye Jemberie 35
Type Conversions
• Suppose we encounter an expression x+i where x has
type float and i has type int.
• CPU instructions for addition could take EITHER float
OR int as operands, but not a mix.
• This means the compiler must sometimes convert
the operands of arithmetic expressions to ensure
that operands are consistent with operators.

By: Yohannes Taye Jemberie 36


• However, most languages accept such
expressions to be used; the compiler will be in
charge of converting one of the operand into
the type of the other.
• The type checker can be used to insert these
conversion operations into the intermediate
representation of the source program.
• For example, an operator inttoreal may be
inserted whenever an operand needs to be
implicitly converted.

By: Yohannes Taye Jemberie 37


Type coercion
• If type conversion is done by the compiler
without the programmer requesting it, it is
called IMPLICIT conversion or type COERCION.
• EXPLICIT conversions are those that the
programmer specifices, e.g.
x = (int)y * 2;

By: Yohannes Taye Jemberie 38


Type Conversions (…cont’d)
• Explicit – done by the programmer
Ex. float pi = 3.14;
int x = (int)pi;
• Implicit – done by the compiler
Ex. int x = 10;
float y = x;

By: Yohannes Taye Jemberie 39

You might also like