CD - CH4 - Syntax Directed Translation
CD - CH4 - Syntax Directed Translation
• Introduction
• Type Systems
• Type Conversions
Introduction – 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.
Introduction – Static Checking
● The following are examples of static checks:
– Type Checking: Incompatible operands,
– Flow control check:-
● A break instruction in C that is not in an inclosing statement,
● A return in Pascal that is not in functions body.
– Uniqueness checks:- Redefined variable
– Name related checks:-
● In Ada loops can have names.
● However, the same name should be used to start and end the
loop.
Type Checking
● 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, ��� (%) expects two integer operands
– If any errors are found, they will be reported by the type checker.
● Type information produced by the type checker may be needed when the code is
generated.
● In almost all languages, types are either basic or constructed – In C++, for example:
– ���, �����, ������, �ℎ��, ... are basic types
– �����, ������, ... are constructed types
Type Systems
● 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.
– A basic type is a type expression, e.g., 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.
Type Systems
● The following are type constructors:
– Arrays: if � is an index set and � is a type expression,
then �����(�, �) is a Type Expression.
● For example, �����([� . . ��], �������) is a Type Expression.
– Products: if �1 and �2 are type expressions, the
Cartesian product �� × �� is a Type Expression.
● × is left associative.
● For example, in function parameters �(����, 5) = ������� ×
���
– Records: ������( (�����1 × �1 ) × (�����2 × �2 ) × … )
● For example, ������{ ��� ���; ����� ����; }
– ������( ( ��� × ������� ) × ( ���� × ����� ) )
Type Systems
● The following are type constructors:
– Pointers: if T is a Type Expression then Pointer(T) is a
Type expression
● For example, Pointer( Integer ).
– Functions: the Type Expression of a function has the
form
D⟶R
– where D is the type expression of the parameters
and R is the Type Expression of the returned value.
● For example, ��� ∗ �(�ℎ�� �, �ℎ�� �)
– �ℎ�� � �ℎ�� → �������( ������� )
Type Systems
DAG Representation:
● A convenient way to represent a type
expression is to use a graph (tree or DAG).
● For example, the type expression
corresponding to the above function
declaration is shown below:
Type Systems
● 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.
● Errors: At the very least, the compiler must report the nature
and location of errors.
● Error Recovery:
– It is also desirable that the type checker recovers from errors and
continues parsing the rest of the input.
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)}
Specification of a Simple Type Checker
Integer
Else
Type_error }
Else
Type_error }
Else
Type_error }
Specification of a Simple Type Checker
Statements
S ® id := E { S.type := if id.type = E.type
then void Else
Type_error }
Else
Type_error }
Equivalence of types
● So far we compared the type expressions using the equal
operators.
● However, such an operator is not defined except perhaps
between basic types.
● In fact we should rather use the equivalent operator
which is more appropriate.
● A natural notion of equivalence is 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).
Equivalence of types
● 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.
● 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.
Equivalence of types
● When names are allowed in type expressions, a new notion of
equivalence is introduced: Name equivalence.
● We have name equivalence between two type expressions if and only
if they are identical.
● Under structural equivalence, names are replaced by type expressions
they define,
– so two types are structurally equivalent if they represent two structurally
equivalent type expressions when all names have been substituted.
– For example, ptr and pointer (integer) are not name equivalent but they
are structurally equivalent.
● Note: Confusion arises from the fact that many implementations
associate an implicit type name with each declared identifier.
– Thus, C and D of the above example may not be name equivalent.
Type Conversions
● Consider expressions like � + �, where � is of type real
and � of type integer.
● Of course, the machine cannot execute this operation as
it involves different types of values.
● 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 ��������� may be inserted
whenever an operand needs to be implicitly converted.
Type Conversions
● Type conversions may be implicit or explicit
– Explicit – done by the programmer
For example, ����� �� = 3.14;
��� � = (���)��;