Homework Assignment 5

  1. Do not change any of the files that I have provided. You must make your files work with my files. Use an ascii text editor or word processor to answer questions 1-3. Submission instructions are at the end of this assignment.
  2. For all programs that you write ensure that they work properly regardless of whether or not the input file ends with a newline character.

  1. In C++, when you throw an exception, why should you write:
        throw FooException();
      
    rather than:
        throw new FooException();
      

  2. You are given the follow class declarations:
           class RecognitionError extends Exception { ... }
           class MismatchedTokenError extends RecognitionError { ... }
           class InvalidTokenError extends RecognitionError { ... }
           class NoAvailableAlternativeError extends RecognitionError { ... }
           class MismatchedNumberError extends MismatchedTokenError { ... }
           class MismatchedOperatorError extends MismatchedTokenError { ... }
         
    For each of the following Java code snippets, explain what is wrong with the snippet and how you would fix it.
    1. 	 try {
      	    ...
      	 }
      	 catch (RecognitionError re) {
      	    ...
      	 }
      	 catch (InvalidTokenError te) {
      	    ...
      	 }
      	 catch (MismatchedOperatorError oe) {
      	    ...
      	 }
      	 
    2. The intent of the following code is to throw the exception out of evaluate and up the call stack. evaluate does not intend to handle the exception.
      	public void evaluate () {
      	     ...
      	     if (error condition) {
      	         throw new InvalidTokenError();
                   }
      	     ...
      	}
            
  3. What is the output printed by the following Java code (I know you can code up this example and run it, but will you be able to do that on an exam?):
           class NegativeNumberError extends Exception { 
             int index; 
             public NegativeNumberError(int i) {
               index = i;
             }
             int getIndex() { return index; }
             public String getMessage() {
               return "Negative number at index " + index;
             }
           }
    
           int sumArray(int x[]) throws NegativeNumberError {
             int i;
             int sum = 0;
             try {
               for (i = 0; i < x.length; i++) {
    	     if (x[i] < 0) throw new NegativeNumberError(i);
                 sum += x[i];
               }
             } 
             catch (NegativeNumberError ne) {
    	   System.out.println(ne.getMessage());
    	   throw ne;
             }           
             finally {
    	   System.out.printf("sum = %d%n", sum);
    	 }
    	 return sum;
           }
    
           public int printSum() {
    	   int numbers[] = { 10, 20, 40, -20, 30, -40 };
             int sum = 0;
             try {
    	    sum = sumArray(numbers);
    	 }
             catch (NegativeNumberError ne) {
    	    System.out.printf("Negative number is %d%n", numbers[ne.getIndex()]);
    	 }
             System.out.printf("sum = %d%n", sum);
    	 return sum;
           }
    			
  4. Write a generic queue in C using a "void *" implementation. The implementation should use an array to hold the queue elements. Use a "circular" implementation that wraps the end of the queue around to the front of the array once it reaches the end of the array. Your implementation will need to keep track of two indices--one that points to the front of the queue and one that points to the end of the queue.

    The API that you will implement is:

    void *queue_new(int numItems);  // create a queue that can hold the indicated number of items
    void queue_enqueue(void *q, void *item); // add the element to the back of the queue
    void *queue_dequeue(void *q); // remove and return the element at the front of the queue
    int queue_isEmpty(void *q);   // 1 if empty and 0 otherwise
    
    I have included several files for this problem: If you have questions about what your output should look like, I have placed a C executable named cQueueDriver in /home/bvanderz/cs365/hw/hw5.

  5. In both Java and C++ write generic code (i.e., templates) to implement a generic queue class using the circular array algorithm that you used for implementing the C generic queue in the previous problem. For Java use an ArrayList rather than an array. We discussed this issue in class, namely that Java does not allow you to create generic arrays (e.g., items = new E[10] is not allowed), which is why I am telling you to use an ArrayList. Your queue class should meet the following specifications:

    1. The API: You should implement the following API:

      1. Queue(int maxCapacity): maxCapacity is the maximum capacity of the queue. You will initialize your queue to have maxCapacity elements.
      2. void enqueue(T value): Adds the value to the end of the queue
      3. T dequeue(): Removes the front value from the queue and returns it.
      4. void printQueue(): Prints the contents of the queue from front to back, one item per line. You may assume for both Java and C++ that the items know how to print themselves.

    2. Exceptions: Your Queue class should throw two types of programmer-defined exceptions:

      1. QueueOverflowException(T item): if the maximum number of items in the queue is exceeded then throw a QueueOverflow exception with the item passed as an argument to the constructor.
      2. QueueEmptyException(): if the user attempts to dequeue an element from an empty queue.

      You need to observe the following requirements for these two classes:

      1. You must use exactly these names for the C++ exceptions since my QueueDriver.cpp program assumes that these are the exception names.
      2. The QueueOverflowException class must be implemented as a template class in C++ and as a non-template class that takes an Object parameter in Java. Normally I would want this class to be a template class in Java but you cannot have a generic class extend the Exception class.
      3. In Jave the QueueOverflowException and QueueEmptyException classes must be declared in separate files and placed in the queue package. In C++ you may place the declarations/method bodies for these two classes into the Queue.h file.
      4. In both the C++ and Java versions the two classes must support a getMessage() method that returns a string. The QueueOverflow version of the method should return a string of the form:
        "queue full: cannot enqueue"  + string form of the item
        
        The EmptyQueue version should return a string of the form:
        queue empty: cannot dequeue
        In Java the toString method ensures that the object can print itself. You may assume that in the C++ version that objects have overloaded the << and string operators to produce strings on request.
      5. The Java exception classes must subclass Exception. The C++ classes do not need to subclass anything.
      6. These exceptions should be thrown out of the queue methods that cause them and up to the calling methods.

    Testing Your Program

    Write queue drivers in both C++ and Java that test your queue class. They should take their input from stdin and test your queue by creating a queue of strings. The first line of your input should be the maximum number of items in the queue. Each succeeding line should start with one of the following commands:

    1. enqueue string: enqueues the indicated string
    2. dequeue: dequeues the first element in the queue and prints it
    3. print: prints the contents of the queue

    If the user tries to input any other command, your driver should print the error message:

    invalid command: user-entered command
    
    where user-entered command is the command the user tried to enter.

    Here is a sample input file (I know I'm using integers but input them as string--our test cases will include normal strings):

    3
    enqueue 5
    enqueue 8
    print
    dequeue
    enqueue 10
    enqueue 11
    enqueue 20
    print
    dequeue
    dequeue
    dequeue
    dequeue
    dequeue
    enqueue 15
    print
    dequeue
    

    Exception Handling and Sample Output

    You may assume that the input is syntactically correct, but that it may cause the queue to either overflow or underflow (i.e., dequeues from an empty queue). If the input tries to enqueue an item and the queue throws an overflow exception, print the string returned by getMessage(), ignore the item and continue. If the input tries to dequeue an item and the queue throws an empty queue exception, print the string returned by getMessage(), ignore the command, and continue. As an example, your output based on the above input must be (your driver program will be printing the "dequeue value" string):

    queue contents
    5
    8
    dequeue: 5
    queue full: cannot enqueue 20
    queue contents
    8
    10
    11
    dequeue: 8
    dequeue: 10
    dequeue: 11
    queue empty: cannot dequeue 
    queue empty: cannot dequeue 
    queue contents
    15
    dequeue: 15
    

    It is highly likely that the TAs will be using script grading so please ensure that your output matches the output produced by my executable.

    Other information that may be useful:

    1. I have placed a C++ executable named QueueDriver in the directory /home/bvanderz/cs365/hw/hw5 on the hydra machines. You can run this executable to see what the output from both your java and C++ implementations should look like.

    2. For the C++ version it is not okay to include your C++ queue code in your class declaration. You must put the method bodies in the Queue.cpp file.

    3. For the Java version place all of your classes, including QueueDriver.java, in a package named queue.

    4. For the Java version remember to close your scanner after you process each line. You need to do so regardless of whether or not the line contained a command that executed properly. Hence you will probably need to use a finally clause to close your scanner.


What to Submit

  1. A hw5.txt or hw5.pdf file with your answers to questions 1-3.
  2. queue.c: We will use a makefile to compile your queue.c into an executable with queueDriver.c.
  3. QueueDriver.cpp/Queue.h/Queue.cpp
  4. An executable jar file named Queue.jar with your .java and .class files for the queue question. We should be able to type:
    java -jar Queue.jar < q5Input
    
    and have your queue driver run.