//
// CS 202 demonstration program 11_stack.cpp
// Written by Dave Williams for 11/13/03 class
//
// Stack-based calculator using singly-linked list
//
// Functions just like Hewlett Packard RPN ("reverse Polish notation")
// calculator system dating back to HP-35 (circa 1973) and extending
// through HP-48 series and the brand new HP 49G+.
//
struct Data // note numerical-based structure
{
int level; // stack level
double data; // data for stack level
Data *pnext; // pointer to next record
};
void Show_stack(Data *); // pass by value
void Pop(Data *&, Data *&, Data *&, Data *&); // by reference - why?
void Push(Data *&, Data *&, Data *&, Data *&, double); // also by reference
void Swap(Data *&, Data *&, Data *&, Data *&); // and again
#include <iostream.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h> // for atof (ASCII to double conversion)
int main()
{
char choice[24]; // we want a char here - why?
float result;
Data *pnew = 0;
Data *pfirst = 0;
Data *plast = 0;
Data *pprev = 0;
Data *pactive = 0;
cout << "\n\nProgram to implement a stack-based 'RPN' calculator."
<< "\n\nEnter a number at prompt and press to push or"
<< "\nenter an operation and press to execute. Any"
<< "\nunrecognized character data will push 0 on the stack. "
<< "\n\nThe current stack is updated after every entry.";
cout << endl;
cout << "\n\n----------------------------------------------------\n";
Show_stack(pfirst) ; // show empty stack at the beginning
do
{
cout << "\n\n----------------------------------------------------";
cout << "\n(d)rop (s)wap (n)egate + - * / ^ (q)uit ";
cout << "\n---------------------------------------------------- --> ";
cin >> choice;
switch(choice[0])
{
case 'q':
exit(0);
break;
case '+': // perform operations:
if (pprev != 0) // check for at least two
{ // data on the stack,
result = pprev->data + plast->data; // capture data & operate,
Pop(pfirst, plast, pprev, pactive); // pop the stack,
plast->data = result; // then push result on stack.
}
else // if < 2 data for operation
cout << " "
<< "--> Stack underflow!";
break;
case '-': // These are, strictly
if (pprev != 0) // speaking, not "pure"
{ // stack operations because
result = pprev->data - plast->data; // they don't pop both data
Pop(pfirst, plast, pprev, pactive); // elements from the stack.
plast->data = result; // They are, however, a lot
} // faster and more efficient
// than that method.
else
cout << " "
<< "--> Stack underflow!";
break;
case '*': // Sometimes, being faster
if (pprev != 0) // and more efficient is
{ // better than being "pure".
result = pprev->data * plast->data; // see Swap() below for an
Pop(pfirst, plast, pprev, pactive); // example of "pure"
plast->data = result;
}
else
cout << " "
<< "--> Stack underflow!";
break;
case '/':
if (pprev != 0)
{
result = pprev->data / plast->data;
Pop(pfirst, plast, pprev, pactive);
plast->data = result;
}
else
cout << " "
<< "--> Stack underflow!";
break;
case '^':
if (pprev != 0)
{
result = pow(pprev->data , plast->data);
Pop(pfirst, plast, pprev, pactive);
plast->data = result;
}
else
cout << " "
<< "--> Stack underflow!";
break;
case 'd': // pop last data
Pop(pfirst, plast, pprev, pactive);
break;
case 's': // swap top two levels
Swap(pfirst, plast, pprev, pactive); // This one _is_ written as
break; // a 100% pure stack
// operation.
case 'n': // negate top level
plast->data = plast->data * -1;
break;
default: // create a new stack level & add data
Push(pfirst, plast, pprev, pactive, atof(choice));
}
Show_stack(pfirst); // show the stack after each operation
} while (1); // repeat endlessly until told to quit
return 0;
}
void Pop(Data *&pfirst, Data *&plast, Data *&pprev, Data *&pactive)
{
pactive = pfirst; // set pactive to bottom of stack
if (plast == 0) // means that stack is empty
cout << " "
<< "Stack underflow!";
else if (pactive->pnext == 0) // for one level in stack
{
pfirst = 0;
pactive = 0;
pprev = 0;
delete plast;
plast = 0;
}
else if (pactive->pnext == plast) // for two levels in the stack
{
pactive->pnext = 0;
pprev = 0;
delete plast;
plast = pactive;
}
else
{
while (pactive->pnext != pprev)
pactive = pactive->pnext; // find pactive that will become pprev
pprev->pnext = 0; // null this before deleting
pprev = pactive;
delete plast;
plast = pprev->pnext;
}
return;
}
void Push(Data *&pfirst, Data *&plast, Data *&pprev, Data *&pactive, double choice)
{
Data *pnew = 0; // a pointer for giving birth to new levels
pnew = new Data;
if (plast == 0) // if this is the first record,
{
plast = pnew; // then set all of these
pfirst = pnew;
pnew->level = 1;
}
else
{
pnew->level = plast->level + 1; // add stack level automatically
plast->pnext = pnew; // set pointer to new level
}
pnew->data = choice; // place the data
pnew->pnext = 0; // zero the pointer in new record
if (plast != pnew) // set pointer if not the first record
{
pprev = plast; // pprev points to second-newest level
plast = pnew; // and plast points to the newest
pnew = 0; // null this so it doesn't turn wild
}
return;
}
void Swap(Data *&pfirst, Data *&plast, Data *&pprev, Data *&pactive)
{
double value1, value2; // this the the 100% authentic "stack-approved"
// way to swap data values. It's done completely
if (pprev != 0) // with pops & pushes and without any data swaps
{
value1 = pprev->data; // capture data
value2 = plast->data;
Pop(pfirst, plast, pprev, pactive); // pop once
Pop(pfirst, plast, pprev, pactive); // pop twice
Push(pfirst, plast, pprev, pactive, value2); // then push one data back
Push(pfirst, plast, pprev, pactive, value1); // and then the other in
} // the reverse order
else
cout << " "
<< "--> Stack underflow!";
return;
}
void Show_stack(Data *pactive)
{
while(pactive != 0)
{
cout << "\n--------------------";
cout << "\nLevel " << pactive->level;
cout << ": " << pactive->data;
pactive = pactive->pnext;
}
cout << "\n====================";
return;
}
// 
// 
//