CS302 -- Lab 2


Overview

This lab is designed to give you practice implementing abstract data types using C++ classes. Specifically you will write a doubly linked list class, and then implement a stack in two different ways, one using the dynamic StringArray class from lab1 and one using the dlist class. In doing so, you will be given practice with some of the basic features of C++ such as:

Dlist Library

Your first task is to write an object-oriented Dlist class. Here is the class declaration you should use for dlists:
class Dlist;                     // Forward reference to a Dlist

class Dlnode {
  friend class Dlist;            // Dlist should be able to use and inspect
                                 // Dlist_node's protected members and methods
  protected:
    Dlnode(char val);
    ~Dlnode();

    char value;
    Dlnode *flink;               // pointer to the next node in the list
    Dlnode *blink;               // pointer to the previous node in the list
};

class Dlist {
  public:
    Dlist();                      // initializes the dlist
    ~Dlist();                     // destroys the dlist's nodes

    //  After insertBeforeCursor and insertAfterCursor are executed, 
    //  the list cursor should point to the newly created node
    void insertBeforeCursor(char value); // inserts the value before the node
                                         // pointed to by the list cursor
    void insertAfterCursor(char value); // inserts the value after the node
                                        // pointed to by the list cursor
    void append(char value);      // appends the value to the end of the list
    void prepend(char value);     // appends the value to the front of the list

    void next();               // moves the list cursor to the next 
                               // element in the list
    void prev();	       // moves the list cursor to the previous
                               // element in the list
    bool endOfList();          // true if the list cursor points to the 
                               // sentinel node; false otherwise
    // If the list is empty, the following two operations make the
    // list cursor point to the list's sentinel node
    void first();             // resets the list cursor to the first
                              // element in the list. 
    void last();              // resets the list cursor to the last
                              // element in the list

    char get();               // returns the value of the node pointed to
                              // by the list cursor

    void deleteNode();        // deletes the node pointed to by the list cursor
                              // and advances the list cursor to the next
			      // list element
    bool isEmpty();           // returns whether the list is empty

  protected:
    Dlnode *cursor;           // the list cursor
    Dlnode *sentinel_node;     // a pointer to the sentinel node
};

To illustrate how the Dlist class might be used, consider the following three problems and their solutions:

  1. Print out each of the elements on a Dlist named mylist:
         for (mylist.first(); !mylist.endOfList(); mylist.next())
           printf("%c\n", mylist.get());
         

  2. Return the first element of mylist and delete it from the list:
         char first_element = mylist.first().get();
         mylist.delete();
         

  3. Insert the character in value into mylist, assuming that mylist is ordered:
         for (mylist.first(); !mylist.endOfList(); mylist.next()) {
           if (value < mylist.get())
             break;
         }
         mylist.insertBeforeCursor(value);
         

Implementing the Dlist Class

To implement the Dlist class you will need to write definitions for each of the Dlist methods. You must use a sentinel node. Here is an example of how one of the Dlist methods might look:
void Dlist::insertBeforeCursor(char v)  
{

  Dlnode *last_node, *new_node; // since new is a reserved keyword in C++,
                                // I've replaced new with new_node

  new_node = new Dlnode(v);

  last_node = cursor->blink;

  cursor->blink = new_node;
  last_node->flink = new_node;
  new_node->blink = last_node;
  new_node->flink = cursor;
  cursor = new_node; // make the cursor point to the newly created node
}

Array Balance

In this part of the lab you are going to write a program called abalance that reads from standard input (stdin) and checks to see if parentheses, square braces and curly brackets are balanced. If you took CS140 from Dr. Plank, you may remember the balance program from lab5. Regardless of whether or not you took the course from Dr. Plank you will probably have to reimplement the program almost from scratch. For one thing the program has been simplified and for a second you will now have to use classes rather than structs. The description of the program is repeated almost verbatim here for your benefit: Write a program called abalance that checks to see if parentheses, square braces and curly brackets are balanced in standard input. All other characters should be ignored. Balanced means what you think it means. The following is balanced:
{}[ ( ) ] {{  [ []() ] }}   {
     }
Each of the following four lines is unbalanced:
{ (}             - left paren and right curly bracket don't match
[ () }           - left square brace and right curly bracket don't match
}                - no left curly bracket
() ( [] ) (      - no right paren
If standard input is balanced, the program should print out the number of each pair seen. If not, the program should print out what the error is.

For example, look at the files input1, input2, input3, and input4.

Input1 is a C program where everything is balanced. When you run abalance on it, the output should look like:

UNIX> abalance < input1
Parentheses    (): 26
Square braces  []: 3
Curly brackets {}: 5
UNIX> 
Almost all C programs are balanced -- try a few:
UNIX> abalance < ~cs140/www-home/notes/Stacks/stackrev.c
Parentheses    (): 12
Square braces  []: 0
Curly brackets {}: 3
UNIX> abalance < ~cs140/src/fields/fields.c
Parentheses    (): 41
Square braces  []: 7
Curly brackets {}: 21

The other three input files have the three types of unbalances that your program needs to catch -- unmatched '(', '[' or '}', unmatched ')', ']' or '}', and mismatches. For example, input2 has three unmatched characters (read the file to see which ones):

UNIX> abalance < input2
Unmatched symbols
UNIX> 
Input3 has an unmatched right paren:
UNIX> abalance < input3
abalance < input3
Unmatched )
UNIX> 
and input4 has a mismatch on lines 1 and 2
UNIX> abalance < input4
Unmatched ] 
UNIX> 
Obviously, the TA's will test more than just these input files. So should you.

You need to use stacks to write abalance. The concept is simple -- when you see a left paren, square brace or curly bracket, you push the character on the stack. When you see a right paren, square brace or curly bracket, you first see if the stack is empty. If so, you have an unmatched character that you flag and then exit. Next, you pop a character off the stack. If the character matches the current character (for example the character from the stack is a left paren and the current character is a right paren), then you have a match, and everything is fine -- go ahead and read the next character from standard input. If they don't match, then you have discovered a mismatch and can print it out and exit. When you are done reading standard input, if there are any characters left on the stack, then they are unmatched. If the stack is empty, you can conclude that the input was balanced.

Part a:Write abalance using a class called StackArray. StackArray should implement its stack using the dynamic CharArray class you've been given for this lab. CharArray is just like the StringArray class from lab1, except that it stores chars rather than strings. CharArray.h can be found in /ruby/homes/ftp/pub/bvz/classes/cs302/include and CharArray.o can be found in the cs302 objs directory.

Part b: Write dbalance using a class called StackList. StackList should implement its stack using your Dlist class.

Stack Interface

The interface for both of your stacks should look as follows:
class Stack[Array/List] {
  public:    
    void Push(char);
    char Pop();
    bool IsEmpty()
}

You will also have to add declarations for the constructor and destructor for each class.

Other Things You Need To Know About This Problem

  1. You must use the Fields class to read in lines of input.

  2. You can find out the length of a string using a string's length method. For example:
         string a = "Hi there";
         printf("string length = %d\n", a.length());
         


    What to Hand In

    You should mail to your TA a file created by /sunshine/homes/bvz/courses/302/bin/302submit. The file should be named username.lab where username is your username. For example, if I were submitting the lab, the file would be named bvz.lab. You will be sending your TA a makefile and your .h and .cc files. The makefile should create the executables abalance and dbalance. Both programs should read their input from stdin.


    Grading

    Your programs will be graded on the basis of 1) their correctness (the most paramount criteria), 2) their commenting, and 3) their conformance to object-oriented coding style.