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.

## All 4 Replies

One thing to point out is that I don't see the <string> header being included nor do is see std:: preceding string since you are not using a using statement.

ermm i believe , there's already a string type defined in the std_lib_facilities and i dont know, i get errors when im using header <string> and using std::string..
the std_lib_facilities reference : http://stroustrup.com/Programming/std_lib_facilities.h

bump

commented: It's impolite to BUMP a thread. Whe someone that can answer reads it, they will answer. -3

guys i just tried to copy and paste the codes into visual c++ 2010, and it works!
anyone knows why my primary() function returns the wrong value(returns "nan) when im using codeblocks??
thx for your patience

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, learning, and sharing knowledge.