Type Checking

Type checking is normally a static process - this is also true for this type checker. That is we check before we have any run time information like the result on some evaluated expression. Thus we can't for example type check on out of bound indexing on arrays if the index expression has to be evaluated, for example a[i + 2 * 4].

Type checking amounts to a "pseudo" evaluation of a given syntax tree, \( T_{0} \). In the situation of Janus \( T_{0} \) is a list of procedures. Each procedure is a list of statements. So we simply loop through \( T_{0} \). For each procedure we create a scope containing the arguments given in its definition. Now we loop through the statements of this procedure checking if every variable used match according to the type in the scope. If we reach a local statement, we add the type of the variable to the scope.

We might as well have the type checker check if a given variable is in scope at all. We can check if a called procedure is not defined. And we can check for mismatch of types and variable names in local statements.

Further on Scope

The scope is handled in the compiler as thus:

  1. We reach a definition for some variable, \( v_{0} \).
  2. If \( v_{0} \) is already present in scope, store it and replace it with the new value (in the case of Janus the value is a pointer). If \( v_{0} \) isn't present, store a null pointer.
  3. When \( v_{0} \) leaves scope again, replace it with the old value we stored in step 2.

In scope we store an Empty type when no value is present. And we fail with a "not in scope" error message if we at any point use a variable that is Empty. Now as long as we keep track of the scope in the type checker, we do not have to worry about null pointers during compilation.