Type checks:
A compiler should report an error if an operator is applied to an incompatible operand;
Example: If we are adding an array variable and a function variable.
Uniqueness checks:
Sometimes an object must be defined exactly once.
Example: In Pascal, an identifier must be declared uniquely,
Labels in case statement must be distinct,
Elements in a scalar type may not be repeated
However, with more complex constructs, like those of Ada, it may be convenient
to have a separate type-checking pass between parsing and intermediate code
generation as shown below:
A type checker verifies that the type of a construct matches that expected by its
context.
Example:
The built-in arithmetic operator MOD in Pascal requires integer operands, so
a type checker must verify that the operands of MOD have type integer.
Code Generation:
The final phase in a compiler model is the code generator.
Its input is an intermediate representation of the source program and it
produces as output an equivalent target program.
The output code must be correct and of high quality, meaning that it should
make effective use of the resources of the target machine. Moreover, the code
generator itself should run efficiently.
If the target machine does not support each data type in a uniform manner, then
each exception to the general rule requires special handling.
If we do not care about the efficiency of the target program, instruction selection
is striaghtforward.
For each type of three-address statement, we can design a code skeleton that
outlines the target code to be generated for that construct.
for example :
every three-address statement of the form x:= y + z can be translated into the
code sequence :
MOV y, R0 /* load y into register R0 */
ADD z, R0 /* add z to R0 */
MOV R0, x /* store R0 into x */
Unfortunatly, this kind of statement-by-statement code generation often produces
poor code;
for example:
a := b + c
d := a + e
these sequence would be translated into :
MOV b, R0
ADD c, R0
MOV R0, a
MOV a, R0
ADD e, R0
MOV R0, d
So, the third statement is redundant, and so the fourth one.
The quality of the generated code is determined by its speed and size.
The Target Machine:
Our target computer is a byte-addressable machine with four bytes to a word and
n general-purpose registers, R0, R1, . . ., Rn-1; it has two-address instructions :
Op Source, destination
Where op is an op-code, source and destination are data field:
MOV (move source to destination)
ADD (add source to destination)
SUB (subtract source from destination)