MCS-287 Lab 3 (Spring 2012)

Due April 16, 2012


You are to write and turn in a Java program that meets the following specification. You do not need to turn in any evidence of testing if the program works correctly. However, if the program fails in some way to meet its specification, you are expected to turn in a statement regarding the shortcoming. If you fail to do so, your grade will be reduced both for your failure to document the error as well as for the error itself. If there is any aspect of the specification that isn't clear to you, please ask about it. You can submit your program the same way as in the prior lab.

Some technical details

The program you write is supposed to read input from "standard input" and produce output on "standard output." In Java, that means you will be reading input from and producing output on System.out. These input/output channels are ordinarily connected to the console but can be redirected to other input sources and output destinations, such as files or other programs. For testing using a JUnit test, the input can come from a string and the output can go to another string that is compared for equality with a string of expected output.

To illustrate this, the Eclipse project I am providing you contains a small example program,, that reads in words from the standard input and writes each out on an individual output line on the standard output. The project also contains a JUnit test class, WordsTest, that shows how this is tested. The program reads individual words using an instance of java.util.Scanner.

The file contains the Eclipse project that you can import as your starting point. In addition to the Words and WordsTest classes, it contains Analyzer and AnalyzerTest. The test case in AnalyzerTest is the example that is given below. I would suggest adding other tests of your own. For example, my test doesn't contain any syntax errors, so it wouldn't exercise that portion of your program. The Analyzer class I provided passes the example test but wouldn't pass any other test because it ignores its input and always blindly produces the example output. Your will replace this "dummy" output code with a real version.


Your program should read text from the standard input that constitutes a block, as described by the following BNF grammar:

<blck> ::= begin <stmts> end

<stmts> ::= <empty>
          | <stmt> <stmts>

<stmt> ::= declare <name>
         | use <name>
         | <blck>

A <name> is a token that consists of any non-whitespace characters; as such, you can readily use the java.util.Scanner class, just as in the Words program. At least one whitespace character must separate each pair of consecutive tokens. Additional whitespace may freely occur before the first token, after the last token, or between tokens.

If the input does not conform to this specification, your program should process the input until the point where the syntax error becomes apparent, producing the output for that portion of the input, and then ending its output with a line containing just the message "Syntax error". This handling of syntactically illegal inputs will count for 20% of the grade of the assignment. In order for the input to be syntactically legal, it must consist of a single block and nothing more.


Your program should echo back the input on the standard output, but with two changes. (You should only echo the input back a single time, with both changes in place. Don't echo it back once with the first change and a second time with the other change.) First, although the whitespace in the input is largely irrelevant, the output should be formatted to show its structure. Each line should include exactly one begin, end, declare or use. The indentation of the lines should correspond to the block structure: two spaces of indentation per enclosing block. The second change your program should make in the output (as compared to the input) is that each declaration statement or use statement should be followed by an annotation as in the following example:

  declare x {declaration 1}
  use y {illegal undeclared use}
  declare y {declaration 2}
    use x {references declaration 1}
    declare x {declaration 3}
    use x {references declaration 3}
    declare x {illegal redeclaration}
    use x {references declaration 3}
    declare y {declaration 4}
  use x {references declaration 1}

Notice that each legal declaration receives a number one higher than the previous one. These numbers are stored for later reference in the use statements. An illegal redeclaration does not advance the number by one.

Data Structure

Your program should use a generic class, ScopedMap, which you must write. That class should conform to the documentation that I am linking to this assignment. This class will count for 70% of the grade of the assignment.

Your job will be easier if you use some of the predefined generic types in the Java API. Moreover, if you fail to do so, but rather build the ScopedMap class from scratch, you will not get full credit.

There are multiple plausible ways to store this data structure. Some are more efficient than others. You will receive extra credit if your design allows your program to process input of length n in time that is big theta of n, not counting the time spent indenting the output. (For some inputs, the indentation may itself require quadratic time.)