hi im trying to do Bjarne Stroustrup's exercise (calculator), it worked well but when im trying to add new function in the calculator (add new variable) it has bugs..
its not complete yet, because when i checked a bit, after i add string "name" inside Token class
, it gives no answer ("nan"). then i checked and test each functions, it seems the problem is in the primary()
function, it doesn't return what it should does, i already check using std::cout
inside the switch statement(it gives the right token's value), but when it returns the value to the term()
function (to the double left
specificly, and yes i checked left
with std::cout
and i found the that primary function return the wrong value) the valuue is "nan", i cant figure out why this goes wrong , anyone can help?
here's the code :
#include <iostream>
#include <vector>
#include <cstdlib>
#include <cctype>
#include "std_lib_facilities.h"
const char number = '8';
const char print = ';';
const char quit = 'q';
const char NAME = 'a';
const char let = 'L';
class Token
{
public:
char kind;
double value;
string name;
Token(char k, string n)
{
kind = k;
name = n;
}
Token(char k, double v)
{
kind = k;
value = v;
}
Token(char k)
{
kind = k;
value = 0;
}
Token(double v)
{
kind = number;
value = 0;
}
Token()
{
kind = number;
value = 0;
}
};class Token_Stream
{
private :
bool full;
Token buffer;
public:
void ignore()
{
if(full == true && buffer.kind == print)
{
full = false;
return;
}
full = false;
char ch = 0;
while(cin>>ch)
{
if(ch == print)
return;
}
}
Token_Stream() : full(false), buffer(0.0){}
void put_back(Token t)
{
buffer = t;
full = true;
}
Token get()
{
if(full == true)
{
full = false;
return buffer;
}
char ch;
std::cin>>ch;
switch(ch)
{
case '!':
case print:
case quit:
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':
{
std::cin.putback(ch);// put the char ch back into the istream
double value;
std::cin>>value;//get number from istream
return Token(number, value);
}
default :
if(isalpha(ch))
{
string temp;
temp += ch;
while((std::cin.get(ch) && isalpha(ch)) ||isdigit(ch))
{
temp += ch;
}
std::cin.putback(ch);
if(temp == "let")
{
return Token(let);
}
if(temp == "quit")
{
return Token(NAME);
}
}
error("bad token!");
}
}
};
Token_Stream ts;
void calculate();
double expression();
double term();
double primary();
double fact(double);
void clean_up_mess();
int main()
{
try
{
calculate();
return 0;
}
catch(runtime_error &e)
{
std::cerr<<e.what();
std::cout<<"enter '~' to continue \n";
keep_window_open("~");
}
return 0;
}
void calculate()
{
while(std::cin)
{
try
{
Token t;
std::cout<<"> ";
t = ts.get();
while(t.kind == print)//discard all "prints" (';')
{
t = ts.get();
}
if(t.kind == quit)
{
return;
}
ts.put_back(t);
std::cout<<"the answer is = "<<expression()<<std::endl;
}
catch(exception &e)
{
std::cerr<<e.what()<<std::endl;
ts.ignore();
}
}
}
double expression()
{
double left = term();
Token t = ts.get();
while(true)
{
switch(t.kind)
{
case '+' : left += term();
t = ts.get();
break;
case '-' : left -= term();
t = ts.get();
break;
default : ts.put_back(t);
return left;
}
}
}
double term()
{
double left = primary();
Token t = ts.get();
while(true)
{
switch(t.kind)
{
case '!' :
{
double x = left;
left *= fact(x-1);t = ts.get();break;
}
case '*' : left *= primary();
t = ts.get();
break;
case '/' :
{
double d = primary();
if(d == 0)
{
error("divide by zero");
}
left /= d;
t = ts.get();
break;
}
case '%':
{
int d = narrow_cast<int>(left);
int d2 = narrow_cast<int>(primary());
if(d2 == 0)
{
error("cannot divide by zero");
}
left = d % d2;
t = ts.get();
break;
}
case '{':
case '(': ts.put_back(t);
left *= primary();
t = ts.get();
break;
default : ts.put_back(t);
return left;
}
}
}
double primary()
{
Token t = ts.get();
switch(t.kind)
{
case '(' :
{
double d = expression();
t = ts.get();
if(t.kind != ')')
{
error("error expected ) !");
}
return d;
}
case '{':
{
double d = expression();
t = ts.get();
if(t.kind != '}')
{
error("error expected } !");
}
return d;
}
case number:return t.value;
case '+' : return primary();
case '-' : return -primary();
default : error("expected primary expression");
}
}
double fact(double x)
{
if(x>0)
return x * fact(x-1);
else
return 1;
}
its not complete yet, because everytime i make a bit change, i always check.
if i remove string name
from the class Token
, the calculator works well.