Exam #3 - Comp 212

Rice University - Fall 2002

Instructions

  1. The examination is open book/notes.  You are allowed to consult any written materials available under the sun, except code from your current Comp212 classmates.  If your code is based on materials that we did not provide you, just give us the appropriate references.
  2. You are not allowed to discuss the exam in any way with anybody beside the instructor (Nguyen, but not the labbies) of this course.
  3. Do not post your questions on the newsgroup.  E-mail me, dxnguyen@rice.edu, your questions instead. I will reply to you directly, and if deemed necessary, I will forward our reply to the newsgroup as well.  I will check our e-mail as often as I can to catch and respond to your questions
  4. Write your code in the most object-oriented way possible, that is with the fewest number of control statements and no checking of the states and class types of the objects involved in any way.
  5. I expect correct Java syntax.
  6. There are 6 questions for a total of  100 points.  Each question should take on the average 30 minutes.  However, you have 5 hours to do the exam.
  7. Submission instruction: you may submit your exam in two ways.
    •  a hard copy with all answers in type-written form, except perhaps diagrams (if any) which can be hand-drawn.  Be sure to print your name and sign the honor pledge.
    • e-mail me  (dxnguyen@rice.edu) your solutions; be sure to zip or jar your exam to keep it small.  Your e-mail message should contain the pledge of honor.

    In either case, send me (dxnguyen@rice.edu)  an e-mail to notify your submission.  I will reply to confirm your submission. 

  8. The deadline for submission is  Dec. 18, 2002 at 5 PM.
Pledge of Honor

I. Recursive Descent Parsing  (see lab #11 of week 12)

Consider the following grammar rules to generate "sentences" consisting of terminal symbols a, b, c.

Grammar Rules

Description

S :: X Y
S  is the start symbol.  S is X followed by Y.
X :: c | A
X is either c or a followed by X, where a and c are terminal symbols.

A ::  a X

A is a followed by X.

Y :: B | X
Y is b followed by Y or  X, where b is a terminal symbol.

B :: b

B is b followed by Y

 

Here are a few examples of "sentences" generated by the above grammar rules.

The above grammar can be modeled by the following object structure (click here to download the source code: grammar.jar).

The main purpose of the following group of questions is to scan input text files consisting of characters such as 'a', 'b' and 'c' and build the corresponding S object.  The technique described in the following falls into the category of parsing called recursive descent parsing.  The parser here differs slightly from the one done in   lab #11 of week 12, in that instead of maintaining a current token, it gets the next token from the tokenizer at the appropriate time, passes the token around and let the token drive the control flow.  As a result, one can say that the parser described here is more object-oriented than the one done in  lab #11 of week 12.

Analogous to the grammar for Scheme arithmetic expressions done in lab #11, the tokens of the above grammar can be implemented using the visitor pattern.  

public abstract class AToken {
    private String _lexeme; // String representing the token.
    protected AToken(String lex) {_lexeme = lex;}
    public String toString() { return _lexeme;}
    public Object abstract execute(ATokVisitor v, Object inp);
}

public class TokenA extends AToken{ // represents the a token.
    // students to write code.
}

public abstract class ATokVisitor {
    /**
    * This is the case when the host is a concrete TokenA.
    * @param host a concrete token.
    * @param inp the input needed for this ATokVisitor to perform its task.
    * @exception IllegalArgumentException thrown as default behavior.
    */
    public Object caseA(TokenA host, Object inp) {
        throw new IllegalArgumentException("Wrong token: " + host);
    }
    // etc..., student to write a method for each concrete token case.
}

1.  (10 points) Write a concrete subclass of AToken to represent each of the remaining tokens in the above grammar. 

2. (10 points) Based on the answer to question 1, write all the methods for the abstract class ATokVisitor given in the above.  Throw an IllegalArgumentException in all the methods.  This is the default behavior of all tokens. 

3. (20 points) A tokenizer is an object that knows how to scan an input stream and extract the appropriate tokens for a given grammar, one token at a time.  Write the code for a tokenizer class specified in the following. 

/**
* Extracts and returns an appropriate AToken from some given source.
*/
interface ITokenizer (
    public AToken getNextToken();
}

/**
* Uses the StreamTokenizer provided by in java.io to scan an input
* stream and extract an appropriate AToken for the above grammar.
*/
public class TokenizerABC implements ITokenizer {
    private StreamTokenizer _st;

    /**
    * Initializes _st to read from a input Reader file with the given
    * input file name.
    * @param inputFileName the name of the input text file.
    public TokenizerABC(String inputFileName) {
    // Students to write code.
    }

    /**
    * Uses _st to scan the input, extracts, and returns an appropriate
    * concrete AToken.
    * Throws an exception if an illegal input is encountered.
    */
    public AToken getNextToken() {
    // Students to write code.
    }
}

4. (35 points) Write a recursive descent parser as specified in the following.  This parser

/**
* Abstract factory to produce an S object.
*/
interface
ISFactory {
    public S makeS(); 
}

/**
* Recursive descent parser to scan input text and produce an S object.
* Throws an Exception when an illegal input is encountered.
*/
public class RDPSFactory implements ISFactory {
    private ITokenizer _tokenizer;
    public RDPSFactory(ITokenizer tokenizer) { _tokenizer = tokenizer;}

    private AToken nextToken() { return _tokenizer.getNextToken(); }

    /**
    * Parses input and returns an S.
    */

    public S makeS() { 
    // Students to write code;  
    // Hint: what do you need to make first before you can make S?
    }

    /**
    * Given the current token tok, parses input and returns an AX.
    * @param tok the current token in the token stream.
    */

    private AX makeX(AToken tok) { 
    // Students to write code; 
    // If needed, use anonymous inner class for ATokVisitor
    }

    /**
    * Parses input and returns an AY, given a current token tok.
    * @param tok the current token in the token stream.
    */

    private AY makeY(AToken tok) { 
    // Students to write code; 
    // If needed, use anonymous inner class for ATokVisitor
    }

    /**
    * Parses input and returns an A, given a current token tok.
    * @param tok the current token in the token stream.
    */

    private A makeA(TokenA tok) {
    // Students to write code; 
    // If needed, use anonymous inner class for ATokVisitor
    }

    /**
    * Parses input and returns a B, given a current token tok.
    * @param tok the current token in the token stream.
    */

    private B makeB(TokenB tok) {
    // Students to write code; 
    // If needed, use anonymous inner class for ATokVisitor
    }

    /**
    * Returns a C, given a current token tok.
    * @param tok the current token in the token stream.
    */

    private C makeC(TokenC tok) {
    // Students to write code; 
    // If needed, use anonymous inner class for ATokVisitor
    }

    // Students are free to add any other non-public methods.
}

Here is an example of a client of the parser.

/**
 * Test can be run via: java RdpClient inputFileName
 */

public class RdpClient {

    /**
     * Does the test.
     * @param inFile name of input file
     */
    public void test(String inFile) {
	TokenizerABC tokenizer = new TokenizerABC(inFile);
	ISFactory fac = new RDPSFactory(tokenizer);
	System.out.println("Sentence= '" + fac.makeS() +"'");
    }

    /**
     * Gets called by the JVM.
     * @param arg[0] the input file name.
     */
    public static void main(String arg[]) {
        new RdpClient().test(arg[0]);
    }
}


5. (10 pointsMake appropriate changes to our object model of the grammar to support the visitor pattern; specifically, write the Java code for the interface and abstract and concrete method definitions necessary to support visitors.  Feel free to add code to the classes that are provided to you in grammar.jar

 

II. Tree Rotation

6. (15 points)  The diagram below illustrates special operations on binary trees called left rotation and right rotation.  These operations are inverses of each other.  These operations are commonly used on binary search trees (BST) because they maintain the BST property of the trees.  Write a visitor called RightRotation to perform a right rotation on a BiTree host.  The visitor should not create any new tree; instead it should mutate the host as illustrated in the figure.