Stack
class for the stack.
Calc
class as the calculator object.
A few design suggestions:
Calc
object should have only two publicly
visible member functions: the constructor
(Calc()
) and an evaluate()
member which returns the result of the given
string expression.
The string expression is passed to the Calc
object via the constructor.
strstream
objects:
istrstream
as the input string, from
which you can ``read'' calculator expression
tokens, e.g.,
float t;
istrstream istr;
istr >> t;
will read in a float into the variable
t
from the given istr
.
This makes parsing the input really easy,
without having to bother with the older
mystring()
or myatof()
C functions.
ostrstream
as the output string, to
which you can ``write'' the expression in
postfix notation, e.g.,
ostrstream ostr;
ostr << ' ';
ostr << token2char((TokenType)(int)stk.pop());
ostr << ' ';
will compose the current portion of the postfix
string ostr
.
Calc
can use two different
instances of he Stack
object:
a float stack for postfix expression
processing, e.g.,
Stack<float> stk;
,
and an integer stack for infix to postfix
string conversion, e.g.,
Stack<int> stk;
.
Gui
class as the GTK GUI object. The
Gui
object only has 1 publicly visible member
function: the constructor.
A few design suggestions:
Gui
object should contain the
top-level windows as its private data members,
i.e., here's the Gui
class interface:
class Gui {
public:
// constructors
Gui() { init(); }
// destructors (default destructor ok)
// ~Gui() { }
// friend callbacks
friend void cal_cb_button(GtkWidget *button, gpointer label);
private:
void init(void);
void add_button(GtkWidget *packing_box,gpointer data);
void process_button(gpointer label);
GtkWidget *window;
GtkWidget *frame;
GtkWidget *text;
};
cal_cb_button()
function is a global
function which is made to be the signal handler for
button presses. However, because it is global,
by default it cannot access private members of
the Gui
class. Since we evenutally
need to access the Gui
internals when
processing button presses, we make the signal
handler a kind of redirection routine, whose only
task is to access a suitable Gui
member function, e.g., here's the code for the
button handler:
void cal_cb_button(GtkWidget *button, gpointer label)
{
Gui *guip;
guip = (Gui *)gtk_object_get_data(GTK_OBJECT(button),"gui");
guip->process_button(label);
}
Notice that to make this setup work, we also have
to attach the entire Gui
object to each
button widget. This is done as follows in
the void Gui::add_button(...)
routine:
// attach text widget pointer to button
gtk_object_set_data(GTK_OBJECT(button),"gui",this);
If you decide that the Gui
function member
called by the button handler is to be a private
Gui
function (no real reason to make it
public), then the handler function must be made a
friend of the Gui
class.
gui_test.cpp
driver program should simply consist of the following function:
#include <iostream>
#include <strstream>
#include <glib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <gtk/gtkwidget.h>
#include <gtk/gtkhscale.h>
#include <gtk/gtkvscale.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
using namespace std;
#include "stk.h"
#include "cal.h"
#include "gui.h"
int main(int argc, char **argv);
int main(int argc, char **argv)
{
Gui *gui;
gtk_init(&argc, &argv);
gui = new Gui();
gtk_main();
return(0);
}
It is strongly suggested that you develop
this program incrementally. That is, when you
finish implementing the Stack
object, write a
short test driver program which just tests this module. For
example, here's a short stand-alone program,
stk_test.cpp
which tests the Stack
module:
#include <iostream>
using namespace std;
#include "stk.h"
int main()
{
Stack stk;
cout << "stack should be empty: stack is ";
stk.empty() ? cout << "empty\n" : cout << "not empty\n";
// create list
for(int i=0;i<10;i++) stk.push(10*(i+1));
cout << "printing forwards:" << endl << stk;
cout << "getting top node:" << stk.top() << endl;
cout << "removing from front:" << endl;
while(!stk.empty()) cout << stk.pop() << endl;
cout << "stack should be empty: stack is ";
stk.empty() ? cout << "empty\n" : cout << "not empty\n";
}
Similarly, you should write a short calculator test driver
when you're done writing the Calc
module.
Here's the stand-alone driver program
cal_test.cpp
:
#include <iostream>
#include <strstream>
#include <stdlib.h>
#include <math.h>
using namespace std;
#include "stk.h"
#include "cal.h"
int main()
{
const int MAXSIZE = 80;
char input[MAXSIZE];
while(cin.getline(input,MAXSIZE-1) && input[0] != 'q') {
Calc calc(input);
cout << calc.evaluate() << endl;
// calc gets automatically deleted here
}
}
.tar
of your project directory, complete with
a Makefile
and README
files.
See the tar
'ing instructions web page for further info on creating the tar
file.