Declaration descriptors are really the most important element of the symbol table. All the
other elements are designed to provide an efficient way to find the correct declaration
descriptors.
There are a few common elements we will want to include in all declaration descriptors:
We will want each declaration descriptor to include a pointer to the
associated identifier descriptor (so that we can easily access the string of character
used as the identifier for compile-time error message and symbolic debugging).
We will want each declaration descriptor to include the nesting depth at which
the declaration occurred. When we generate code, we will depend on this information.
Beyond this short list of common elements,
the contents will vary from one type of declaration to another:
Variables and formals
For each variable we will want to include a description of its type.
As a result, shortly, we will describe yet another type of descriptor,
the type descriptor.
For code generation, we will eventually need information about the offset
to the variable within the heap object or method activation record that contains it.
On the WC34000, all data objects require one word, so if we simply count variable
declarations and store the current count in each variable's descriptor, this will
be sufficient. Note, however, that for instance variables, this count must include
all variable's in super classes.
Methods
We will want to store the method's return type
We will want to keep a pointer to a list of the declaration descriptors for the
method's formals (this will be needed to type check invocations of the method
(among other things)).
We will need a count of the number of local variable so that we can tell how
much memory to allocate for an frame/activation record when the method
is invoked.
For code generation, we will build a table of pointers to the code for each of the
methods associated with a class. Therefore, like variables, we will want to
associate an offset with each method. Again, as with variables,
since all data values occupy 1 word on the WC34000, a simple count
of this method's position within the list of methods associated with the class will
do the job.
Note that this count will have to include methods defined in superclasses,
but exclude methods that simply override existing methods (since they will not
get a new slot in the table but instead reuse the old slot).
Classes
If the class is a subclass, we will want to know its superclass.
To allocate objects of a class, we will have to keep track of the total space
required for variables. Again, on the WC34000 all variables will take one word.
Therefore, the class declaration descriptor is a good
place to keep a count of how many variables we have processed.
We will also want to keep the count of the number of distinct method names
associated with the class.
As mentioned, we now need to design yet another descriptor used to hold information
about the type of variables, expressions, etc. in Woolite.
Luckily, there aren't too many choices. The only types are int, declared classes,
and arrays of the above. A type descriptor can therefore simply be a pair including
a pointer to the base type (a class declaration descriptor), and
a count of the number of dimensions (where 0 means the type is not an array at all).