University of Toronto

csc324H Programming Languages, Fall 1996

Assignment 3 [10 of mark]

Out: November 19, 1996
Due: December 4, Wednesday, 11:59 (electronically)
Due: December 5, Thursday, in lecture (paper version)

Objective

In this project, you will use virtual function mechanism of C++.

Background

A list is a sequence of zero or more values. Any value can be a list element. For example,
  ("abc", 1, 3.2, 'a')
is a list. For the purpose of this assignment, list elements can be integers, strings and other lists. For example,
   ("abc", (1, 2), 3)
is a list where the first element is a string "abc", the second element is a list containing two integers, 1 and 2, and the first element is an integer 3. Possible operations on lists are cons (takes an element and a list and inserts the element in the beginning of list), car (returns the first element of the list), cdr (returns the list with the first element removed), null (returns true if the list has no elements), and append (takes two lists and puts the second list to the right of the first.) Here are some examples of list operations:
    cons (1, (2, 3, 4)) = (1, 2, 3, 4)
    cons (1, (1, 2, 3)) = (1, 1, 2, 3)
    cons ((1, 2), (2, 3)) = ((1, 2), (2, 3))
    car ((1, 2, 3)) = 1
    car (((1, 2), 3, 4)) = (1, 2)
    cdr ((1)) = ()  /* empty list, i.e., list with no elements */
    cdr (((1, 2), 3, 4)) = (3, 4)
    null ((1, 2)) = false
    null (()) = true
    append ((1), (2, 3)) = (1, 2, 3)
    append (((1)), (2, 3)) = ((1), 2, 3)
    append ((), (2, (3))) = (2, (3))

In functional languages like Scheme or ML, lists are represented using a dotted notation. All lists are constructed using cons, and a "dot" is put in place where cons was called. For example, a list (1, 2, 3) could be constructed starting with an empty list () using a constructor cons as follows:

   cons (1, cons (2, cons (3, ())))

i.e., first construct a list (3), then insert 2 in front of it, and then insert 1 in front of the resulting list. So, in functional languages a list (1, 2, 3) would be represented as

  (1. (2 . (3. ())))
Note that unlike Scheme, this cons does not make the copy of the original list! .

Project Description

You are to implement lists in C++. The elements consist of strings, integers and other lists. Implement cons, car, cdr, null and append ( append makes a new list which consists of concatenation of the previous lists). In addition, implement operations print and clone. The print operation should produce the ``dotted'' notation form of lists. clone makes a copy of the list and returns a reference to it.

The program skeleton appears below. It is broken down into two files here, the file containing class definitions and implementation of member functions, and the file containing main program. In your projects, please break up the solutions into at least 3 files.

// File classdef.h
// This file contains a definition and an implementation for
// lists.

class Object;
typedef Object* PObject;  // we do this so that we can define
                          // a pointer to class Object


class Object { /* an abstract class */
public:
  virtual PObject clone() = 0;
  virtual ~Object() {};
  friend  ostream &operator<<(ostream &, const Object &);
private:
  virtual ostream &printTo(ostream &o) const=0;
};

ostream &operator << (ostream &o, const Object &s) {
   return s.printTo(o);
}

// You will need to provide definitions for classes
// String and Int, and implementations for classes
// String, Int and List.

class String;
class Int;
class List;
typedef List* PList;

// This is the definition of class List
class List: public Object
{
public:
  List(); 
  ~List();
  PObject car() const;
  List& cons(PObject);
  List& cdr() const;
  int null() const;
  ostream &printTo(ostream &o) const;
  PObject clone();
private:
  PObject car_part;
  PList cdr_part;
};

// Notice that append is not a member function!
List& append (List* X, List* Z) { }

And now the file which contains main:

// main.C.  This file contains test cases for the
// implementation of lists.

#include < iostream.h >
#include "classdef.h"

int main()
{
    String V1("Hello");
    Int V2(7);

    Object *p1 = &V1, *p2 = &V2;

    List L1;
    List L2;

    List L3 = L2.cons(&Int(1)).cons(&String("Two")).cons(&Int(3)).cons(&String("Four")).cons(&Int(5)).cons(&Int(6));
    List L4 = L2.cons(&Int(25)).cons(&String("Fleas")).cons(&String("has")).cons(&Int(24));

    List L5 = append(&L3,&L4);

    for(; !L3.null(); L3= L3.cdr()) {
      cout << *L3.car() << endl << L3 << endl << L3.cdr()t << endl;
    }
    cout << L3 << endl << endl << endl;
    cout << V1 << endl;
    cout << V2 << endl;

    p1 = V1.clone(); 
    cout << *p1 << endl;
    p2 = V2.clone();
    cout << *p2 << endl;

    cout << "(L1.cons(&V1))=" << (L1.cons(&V1)) << endl;   
    cout << "(L1.cons(p1))=" << (L1.cons(p1)) << endl;

    p1 = (L1.cons(&V1)).clone();
    p2 = (L1.cons(&V2)).clone();
    cout << "append((PList)p1,(PList)p2)=" 
         << append((PList)p1,(PList)p2) << endl;

    cout << "(L1.cons(&V2).cons(&V1))=" << (L1.cons(&V2).cons(&V1)) << endl;
    if ( (L1.cons(&V2).cdr()).null() ) 
      cout << "null list\n";

    cout << L4 << endl;
    cout << L5 << endl;
}

Your program should produce the following output.
Int: 6
(Int: 6 . (Int: 5 . (String: "Four" . (Int: 3 . (String: "Two" . (Int: 1 . ( )))))))
(Int: 5 . (String: "Four" . (Int: 3 . (String: "Two" . (Int: 1 . ( ))))))
Int: 5
(Int: 5 . (String: "Four" . (Int: 3 . (String: "Two" . (Int: 1 . ( ))))))
(String: "Four" . (Int: 3 . (String: "Two" . (Int: 1 . ( )))))
String: "Four"
(String: "Four" . (Int: 3 . (String: "Two" . (Int: 1 . ( )))))
(Int: 3 . (String: "Two" . (Int: 1 . ( ))))
Int: 3
(Int: 3 . (String: "Two" . (Int: 1 . ( ))))
(String: "Two" . (Int: 1 . ( )))
String: "Two"
(String: "Two" . (Int: 1 . ( )))
(Int: 1 . ( ))
Int: 1
(Int: 1 . ( ))
( )
( )


String: "Hello"
Int: 7
String: "Hello"
Int: 7
(L1.cons(&V1))=(String: "Hello" . ( ))
(L1.cons(p1))=(String: "Hello" . ( ))
append((PList)p1,(PList)p2)=(String: "Hello" . (Int: 7 . ( )))
(L1.cons(&V2).cons(&V1))=(String: "Hello" . (Int: 7 . ( )))
null list
(Int: 24 . (String: "has" . (String: "Fleas" . (Int: 25 . ( )))))
(Int: 6 . (Int: 5 . (String: "Four" . (Int: 3 . (String: "Two" . (Int: 1 . (Int: 24 . (String: "has" . (String: "Fleas" . (Int: 25 . ( )))))))))))

Submission

Submit (electronically) a tar file with

  1. Well-documented source code (broken down into several files)
  2. Test programs
  3. Makefile
  4. Output showing the operation of your program.
  5. (Optional) README file with instructions on how to run your program.

Note that we will rerun your program with, so please do not change the output of your program!!!!!

Bring a paper copy with your programs, test cases, output, etc. to class

Marking

Marking scheme for this project is as follows:

Correctness 55 The program gives the correct output.
Documentation 10 The program should contain explanations for each class, each function and the entire program.
Testing 10 Has the program been tested appropriately? To test the program, generate various Main programs with the same operations as those in the sample Main, build the executable and check the output.
Style 25 The program should be written using object-oriented programming style and work efficiently, avoiding extra computation where appropriate.

Notes

  • This project is graded by Nick Zahariadis. Grading questions can be directed to him via e-mail to at324zah@cdf. Nick will hold an office hour after the projects are graded to explain the grading policies, etc.
  • As usual, the project will be run on CDF. You are welcome to develop the project on your home computer using any C++ implementation. However, make sure that your project works using CC or g++ compilers on CDF. Also, make sure that your Makefile uses the appropriate compiler. We will use your Makefiles to build executables and run them.
  • You may use any auxiliary member and non-member functions. However, make sure that all functions described in the project are correctly implemented.
  • Read ut.cdf.csc324h for updated information, test cases, etc.
  • You may want to start with classes Int and String and get then to work. Then proceed with simple lists (no nested lists). Finally, add nested lists.
  • You do not have to overload the assignment operator if you do the project correctly.