CS333 Lab P1-3:
Computer Supported Collaborative Work: Shared Spreadsheet
Goals of this lab:
- Design a simple spreadsheet that can be shared by multiple users.
- Learn about parsing and interpreting expressions.
- Improve your object-oriented design skills.
Introduction:
Computer supported collaborative work is the use
of a computer as an intermediary in human interactions.
This is different from simple teleconferencing, since there
is computation that takes place as part of the interaction.
In this lab, you will design and implement a simple spreadsheet that
allows multiple users to enter data and formulae. The results from
the spreadsheet calculations will be available for graphical
visualization and control. (In a later assignments, you will extend
your shared spreadsheet to support the construction of distributed
simulations and other kinds of iterative calculations.)
Directions:
Read over the entire assignment before starting.
Then, follow the instructions step by step.
- A Spreadsheet Object:
Design a C++ class for a spreadsheet object whose internal
representation is a two-dimensional array of real numbers.
Let the spreadsheet have a fixed number of rows and
columns, provided as parameters to the constructor function.
Your spreadsheet object should support the following
operations:
- setval row col value
- sets the entry in the given row and column to the given value
- getval row col
- returns the value in the given row and column
- print
- prints the contents of the spreadsheet on the standard output,
in nicely formatted rows and columns (useful for debugging)
- Publish the Spreadsheet:
Read about the PGarray data type in the manual.
Modify the constructor of your spreadhsheet object to publish the
spreadsheet. Now run two instances of your spreadsheet application
on different machines and connect them with a bidirectional
connection. Make sure that changes in each spreadsheet are visible
in the other.
- A Formula Object:
Spreadsheets are not very interesting unless they can perform
calculations. To allow cells of the spreadsheet to have computed values,
we need a way to put formulae into the spreadsheet. Design a
formula object whose internal representation is a character string of
up to 80 characters. The character string will be a formula with
a Scheme-like syntax in which the following operators are allowed:
- Arithmetic: '+', '-', '*', '/' (exactly two arguments)
For example, (+ 3 (* 4 7)) would evaluate to 31
- Comparison: '>', '<', '=' (0 and 1 represent true and false)
For example, (< 3 5) would evaluate to 1
- Boolean operators: '&', '|'
For example, (& (> 3 5) (< 3 5)) would evaluate to 0
- Spreadsheet access: to extract a value from the spreadsheet
For example, (s 0 2) would return the value
in row 0 and column 2 of the spreadsheet
- Conditional evaluation: if-then-else semantics
For example,
(c test-exp then-exp else-exp)
would evaluate test-exp and, if non-zero, would return
the value of the then-exp and otherwise would return
the value of the else-exp.
Any expression may be used as an argument of any other expression,
but for simplicity we will assume that the row and column numbers in
a spreadsheet access are constants, not other expressions.
Your formula object should have a constructor (with the associated
spreadsheet object provided as a parameter). Other operations should
include: print the formula to standard output, replace the contents of
the formula by a new string, and evaluate the formula. (A formula
with incorrect syntax will evaluate to 0. You may also want to print
an error message in this case.)
- Formulae in Cells:
Add a two-dimensional array of formula objects to the internal
representation of your spreadsheet, where each formula computes the
value in the corresponding entry of the spreadsheet. You should also
keep track, perhaps in another array, of which cells in the
spreadsheet are computed by formulae.
Extend your driver with three new commands:
- enter (or reenter) the formula for a cell,
- evaluate the spreadsheet by evaluating all the formulae,
- print all formulae.
Note that you could compute all the formulae left-to-right and
top-to-bottom, but what would happen if the value of a cell A depends
upon the value of a cell B that is further to the right or further
down? Develop a strategy so that you would calculate the value of
cell B before completing the calculation for cell A. However, don't
compute the value of any cell more than once in a single evaluation of
the spreadsheet! If there are cycles among the formula dependencies,
you may break the cycles arbitrarily. See the instructor if
you have questions about this.
Test and debug your formula object using your extended driver.
- Publishing individual cells:
Add another command to your driver that will allow users of the
spreadsheet to publish individual cells (and give them external names).
Now use EUPHORIA to observe and control the contents of the cells
of the spreadsheet. You may want to try writing a reaction function
that will reevaluate the spreadsheet whenever a value is changed
externally. What will happen if you connect two spreadsheets together
that have such a reaction function?
- Spreadsheet Front-End:
Read about aggregate mappings in the
EUPHORIA manual. Then use EUPHORIA to create
a graphical user interface to the spreadsheet module. It should allow
data values and formulae to be seen and changed by the user. It should
also allow you to control the publishing of individual cell values.
(Note: EUPHORIA currently does not support user editing of text
that is contained within a widget.)
We prefer that you create a GUI using EUPHORIA, but another
possibility is to write a program that tests your spreadsheet object
by interactively taking commands to: set the value in a particular
cell, get the value of a particular cell, print the spreadsheet, or
quit. Use a switch statement in your driver so that you can easily
add more commands later. Your driver should print out a list of the
possible commands and their arguments whenever an invalid command is
entered.
Optional Extension: Iterating Spreadsheet
In this extension, you will
construct a general-purpose
iterating spreadsheet.
Then, you will use your spreadsheet to build the process control application from
the process control lab without writing any additional
code!
Introduction:
Consider a dependency graph for a spreadsheet, defined as
follows. Let there be exactly one vertex in the graph corresponding
to each cell of the spreadsheet, and let there be a directed edge from
vertex A to vertex B in the graph if and only if the cell
corresponding to vertex A is referenced by the formula used to compute
the cell corresponding to vertex B.
For most commercial spreadsheet packages, the dependency graph is
restricted to be acyclic, so the entire spreadsheet can be made
consistent by evaluating each formula at most once.
In other words, the view is that the formulae are normally
considered to be invariant assertions about the state of
the spreadsheet.
However, if we allow cycles in the cell dependency graph, then we
can use spreadsheets to specify more complex calculations, provided
that we can specify when the calculations should terminate.
Your goal is to augment the shared spreadsheet module you
have built so that it can iterate
until a specified termination condition is reached.
This will allow you to construct simulations and other complex
computations simply by entering the appropriate formulae,
initial values, and termination conditions into your spreadsheet.
You will even be able to distribute these computations
by publishing the appropriate cells from multiple spreadsheets
and forming logical connections among them.
- Termination Condition:
Add a termination condition formula to the internal representation
of your spreadsheet. This will be just another instance of your
formula object. Add an option to your driver program that allows
the user to enter a termination condition formula.
In your prompt message, remind the
user that this should be a true/false formula.
- Iteration:
Add an option to your driver program to "iterate."
Provided that a termination condition has been given, this should
evaluate the spreadsheet repeatedly until the termination condition
evaluates to true:
While the termination condition is not true,
evaluate the spreadsheet
PG::sleep(1,0); // so you can see what's happening and not hog the CPU
You may want to allow the user to specify a maximum number of iterations,
so that the program will stop eventually, even if the termination condition
does not become true.
Test your iterating spreadsheet thoroughly. A good first test would
be to fill cell 0,0 with an initial value of 0 and the formula
(+ (s 0 0) 1). Then iterate using
a simple termination condition like (> (s 0 0) 10).
- Files:
Extend your speadsheet to save and load data and formulae in files.
(Alternatively, you can just run your driver, directing the input
from a file.)
- Constructing a simulation:
Use the iteration feature of your spreadsheet to construct the
process control simulation. One spreadsheet will act as the
sensor module, another as the control module
from the process control lab. You will need to publish
individual cells of the spreadsheet in order to accomplish this. Suggestion:
First set up the control module as a spreadsheet and substituting it for the
hard-coded control module you wrote previously.
Then do the same for the sensor module.
To receive credit for this lab, you should:
- Clean up and print out your code. (Don't turn it in, but
save it for your code/design review.)
- Turn in a
Project Evaluation Form near the beginning of
class on the day you want to do your demonstration and code/design
review. You should be
prepared to demonstrate your working application, explain your
design and code, and answer questions.