This assignment makes use of files contained in this zip file.
This assignment is due Monday, April 30.
This assignment is based on Language_2. In this assignment you will add "static analysis" to Language_2.
A common kind of programming error is to reference a variable that has not been declared (for example, you might misspell a variable name when you are trying to reference it) or to re-declare a variable in the same scope. An interpreter is not a good tool for finding these kinds of errors. First of all, there are parts of the program text that the interpreter might rarely see. For example, the interpreter may not traverse the else-clause of an if-expression because the else-clause is meant to handle a rarely occurring error condition. A second reason an interpreter is bad for finding undeclared (and re-declared) variables is that the interpreter may not find one until after the program has been running for a long time. The resulting error, and the halting of the interpreter, will find the undeclared or re-declared variable, but at the cost of much wasted time.
In a statically scoped language, it is possible to find all undeclared variables in a program without having to run the program (this is not true for dynamically scoped languages; for those languages, you must execute the program to find undeclared variables). In this assignment you will write a "static analysis" program that finds all undeclared variable references in a program and all re-declarations of previously declared variables.
In the zip file there is a file StaticAnalysis.java
that is supposed to perform static analysis of programs from Language_2
. You need to complete this program so that it can find all references to undeclared variables and all re-declarations of existing variables (within the same scope as the original declaration).
The StaticAnalysis.java
program should be structured the same way as the Parser.java
and Evaluate.java
programs. They use a "syntax driven" structure with one method for every production in the grammar (so the grammar of the language becomes a table of contents to the program's code). The methods in StaticAnalysis.java
should have names like analyzeApply()
(in place of parseApply()
and evaluateApply()
from the parser and interpreter, respectively).
The analysis methods in StaticAnalysis.java
should all be boolean
methods. Each method should print, to stdout, an appropriate error message whenever it finds an error (the methods should not throw any exceptions). An analysis method should return true
if it does not find any errors and it should return false
if finds at least one error. Whenever an analysis method detects an error, it should print an error message and then continue to analyze the remaining code (similar to how a compiler does not stop when it finds a compile time error). Notice that a single call to an analysis method could find several errors. For example, if both x
and y
are undeclared variables, then a call to analyzeSet()
for this code,
( set x y )
should produce two "undeclared variable" error messages, one for each variable. Similarly, if x
is already declared and y
is undeclared, then a call to analyzeVar()
for this code,
( var x y )
should produce two error messages, a "previously declared variable" error message for x
and an "undeclared variable" error message for y
.
When you have finished implementing StaticAnalysis.java
, the file Tests.java
should compile and run. The output from running this program should look exactly like the file Tests_output.txt
.
Notice how the error messages in Tests_output.txt
contain the token numbers of variables. This is so that the error messages are unambiguous. I have modified the Tokenizer.java
, Tree.java
, and Parser.java
files so that each token in the parse tree contains its token number. Use the getTokenNumber()
method from the Tree
class to get a token's number.
Most of the code for StaticAnalysis.java
can be found in Evaluate.java
. The static analyzer acts very much like an interpreter, but it doesn't need to fully evaluate a program. For example, the static analyzer needs to use global and local Environment
objects to keep track of which variables have been declared, but the analyzer does not need to keep track of the value of any variable (in my code, whenever I put a variable into an new Value(false)
, even for function names). As another example, the method analyzeWhile()
needs to analyze each expression in the while-loop, but it does not need to execute any loops.
The biggest difference between StaticAnalysis.java
and Evaluate.java
is that the body of a function definition is analyzed as part of the analysis of the function declaration, not as part of a function application. So the code for analyzeFun()
looks a lot like the code from evaluateApply()
(and the code for analyzeApply()
is actually similar to analyzeSet()
).
Turn in a zip file called CS316Hw4Surname.zip
(where Surname
is your last name) containing your version of StaticAnalysis.java
.
This assignment is due Monday, April 30.