Comp 388 Lab 5 - The Compiler
Goals
- Implement a reasonably efficient two-level symbol table
- Make sure that duplicate declarations are detected
- Implement constants
All of these can be done entirely in the SymbolTable class, by editing
symboltable.cs.
The compiler files are as follows:
The compiler notes are at compiler.html.
Symbol Table
To implement a two-level symbol table,
use the built-in Dictionary class but create separate dictionaries
for the global scope and for each separate local scope. When you
reach the end of a local scope (endscope(), likely corresponding to the end
of a function), the current local-scope Dictionary will be discarded. There
may be additional global declarations before the next local scope is
entered; at this point you will create a new local scope.
For the two-level scope model, we are at any point either in the global
scope (scopecount == 0)
or the local scope (scopecount
> 0).
Suppose the two Dictionaries are named GlobalDict and LocalDict. If we are
currently in a local scope, then allocation will always involve creating
entries in LocalDict. GlobalDict will only receive new entries when we are
in the global scope..
However, variable lookup while in the local scope will involve first looking
up the identifier in LocalDict, and then, if it is not found there, looking
in GlobalDict.
The changes here should functionally be equivalent to how the module
symboltable1.cs works, but should be more efficient since the approach here
avoids cloning the Dictionary. After you finish implementation of this step,
the following should still compile:
Optional: implement a multi-level symbol table that
supports arbitrary nesting. See compiler.html.
Duplicate Declarations
The current compiler will give an error message indicating an identifier is
undefined if the call to SymbolTable.lookup() returns null, so undeclared
identifiers are detected. A declaration is a duplicate if
there is a previous declaration of that identifier at the same level.
This would occur if we had
int n;
int n;
You can detect this by noticing if, when allocVar()/allocConst()/allocProc()
are called, there is already a declaration of the identifier in question at
the same level. In the following code, the first n is at global scope
and the second is at local scope; this is legal.
int n;
foo() {
int n;
}
Functions are always declared at the global scope, but you still have to
check if a function is redeclared (or if a global variable or constant is
declared with the same name as the function).
If you detect a duplicate declaration, call t.error(string)
with a suitable error-message string that includes the identifier in
question. This will print the string and halt the compiler.
The file dupdecl.mjava
should not compile after your changes.
Constants
To implement constants, all you have to do is make sure allocConst() works.
The compiler syntax for defining constants is
final
int two = 2;
final int three = 3;
final int costPerYear = 10000;
The file consts.mjava
should then be able to run.
The only file you should have to modify is symboltable.cs (or, preferably,
symboltable1.cs).