#include <iostream>
#include <limits>
#include <stdexcept>
usingnamespace std;
//declaring classes
class token
{
public:
char kind;
double value;
token (char ch)
:kind(ch), value(0) {}
token (char ch, double val)
:kind(ch), value(val) {}
};
class token_stream
{
public:
token_stream();
token token_get();
void putback(token t);
private:
bool full;
token buffer;
};
// class member functions of token_stream
token_stream::token_stream()
:full(false), buffer(0) {}
void token_stream::putback(token t)
{
if (full==true) throw runtime_error ("putback into a full buffer");
buffer = t;
full=true;
}
token token_stream::token_get()
{
if (full) {
full=false;
return buffer;
}
char ch;
cin >> ch;
switch (ch) {
case';':
case'q':
case'(': case')': case'+': case'-': case'*': case'/': case'{': case'}': case'!':
return token(ch);
case'.':
case'0': case'1': case'2': case'3': case'4':
case'5': case'6': case'7': case'8': case'9':
{
cin.putback(ch);
double val;
cin >> val;
return token ('8',val);
}
default:
throw runtime_error("bad token");
}
}
//declaring functions
token_stream ts;
double expression();
double term();
double primary();
int factorial(int number);
//functions
double primary()
{
token t = ts.token_get();
switch (t.kind) {
case'{':
{
double d = expression();
t = ts.token_get();
if (t.kind != '}') throw runtime_error ("']' expected");
return d;
}
case'(':
{
double d = expression();
t = ts.token_get();
if (t.kind != ')') throw runtime_error("')' expected");
return d;
}
case'!':
{
t = ts.token_get();
double d = factorial(t.value);
return d;
}
case'8':
return t.value;
case'q':
cout << "exit";
return 0;
default:
throw runtime_error("primary expected");
}
}
double term()
{
double left = primary();
token t = ts.token_get();
while (true) {
switch (t.kind) {
case'*':
left *= primary();
t = ts.token_get();
break;
case'/':
{
double d = primary();
if (d==0) throw runtime_error("divide by zero");
left /=d;
t = ts.token_get();
break;
}
default:
ts.putback(t);
return left;
}
}
}
double expression()
{
double left = term();
token t = ts.token_get();
while(true) {
switch(t.kind) {
case'+':
left+=term();
t = ts.token_get();
break;
case'-':
left-=term();
t = ts.token_get();
break;
default:
ts.putback(t);
return left;
}
}
}
int factorial(int number)
{
int solution = 1;
for (int i=number; i>1; i--) {
solution= solution*i;
}
return solution;
}
int main()
try
{
cout << "A simple calculator able to deal with +,-,*,/. Enter ';' to calculate and 'q' to quit" << '\n';
cout << ">";
//main loop
while (cin) {
token t = ts.token_get();
if (t.kind == 'q') {
cout << "Thanks for using the calculator" << '\n';
break; //'q' for quit
}
if (t.kind == ';') // ';' for "print now"
cout << "=" << expression() << '\n'<< ">";
else {
ts.putback(t);
cout << "=" << expression() << '\n' << ">";
}
}
}
catch (exception& e) {
cerr << "error: " << e.what() << '\n';
return 1;
}
catch (...) {
cerr << "Unknown exception!\n";
return 2;
}
Hello guys,
I'm working on Sir Stroustrups Beginner book. This is, as you can see, a simple calculator.
It is supposed to exit on pressing 'q', which it does, but only if I input 'q' before I do anything else. Afterwards I can't exit the program that way anymore.
From my understanding the following happens (Please correct me if I'm wrong)
- due to line 212, my last token is put back into the stream, thus the program calls "expression()" which calls "term()" which calls "primary()". Now I tried fixing the problem by inserting case "q" into primary, but from my understanding I can not end the program from a function, I can only "return" to main();
How please do I fix this? Feel free to criticize the rest of the code as well (keep in mind, I'm a beginner)