Type CheckingTopDealing with Nested Scopes at Run-timeMore on Order of Declaration Processing

More on Order of Declaration Processing

  1. Last week (and in the handout for the first phase), I explained that it is necessary to make (at least) two complete passes over the abstract syntax tree to correctly process the declarations in a Woolite program.
  2. Even within the first pass, processing order is critical.

  3. During the first pass of semantic analysis of a program, for each class you need to:
    1. Create a declaration descriptor for each declaration found in the class (i.e. the top level declaration, not those nested in nested class declarations).
    2. Put the declaration "in scope" by adding it to the correct scope's list of bindings and the correct identifier's stack of bindings.
    3. Set (many of) the fields of each declaration descriptor that are independent of the correct meanings of other names in its scope:
      • The type of declaration,
      • Its declaration level,
      • The line number it occurred on and the identifier involved,
      • etc.
    4. Put bindings for the methods declared in the hash table that maps class/name pairs to method declarations
    5. Add the declarations of inherited methods to the scope for the class.
    6. Add entries for inherited methods paired with the enclosing class to the method hash table.
    7. Set (many of) the fields of each declaration descriptor that depend its type and on the correct meanings of other names in its scope (primarily type names):
      • Method return types,
      • Method formal parameter types,
      • Instance variable types,
    8. Check to see whether method declarations that attempt to override inherited methods have matching return and parameter types.
  4. These tasks can be completed in many different orders, but there are many constraints that require certain tasks be performed before others. To understand the constraints, consider the class "Nasty" shown in Figure * below.
    class Nasty {
    
        A var;
    
        class A {
            int meth() {
                Bad x;
                x = new Bad;
                return x.meth().meth();
            }
             void C() { . . . }
         }
    
        class Bad {
            C meth () {   return new C;    }
    
            int C;
        }
    
        class C extends A {
              C meth3() {  return var;  }
         }
    
         int meth2( C p ) {
            A y;
            y = new A;
            return y.meth();
         }
    }
    
     
  5. First, it should be clear that we cannot perform step (g) until step (a) has been completed since we obviously cannot use a classes declaration descriptor to represent a variable's type or a return type if the declaration descriptor hasn't been created.
  6. Similarly, we cannot perform step (g) until step (b) has been completed, since without putting the declarations "in scope" we will have no way of finding the correct declaration descriptor for a class name while processing a type description.
  7. This suggest that "pass 1" must include at least two subpasses.
  8. Performing step (d) is the real goal of the first pass. Since all it requires is that the method declaration descriptors exist (and not that they be completely filled in), we might as well do it on the first subpass.
  9. Because it may change the meanings of names within the scope of a class, it is also necessary to perform step (e) before step (g).
  10. Since we will have to scan through all the superclasses to add inherited methods to the scope (i.e. perform step (e)), we might as well add the methods to the hash table while we are at it (i.e. perform step (f).
  11. Finally, step (h) cannot be performed before step (g) for a given method since to determine whether an inherited method and a method defined within a class represent method overriding or a name conflict we have to know the return type and parameter types of both method declarations.

Computer Science 434
Department of Computer Science
Williams College

Type CheckingTopDealing with Nested Scopes at Run-timeMore on Order of Declaration Processing