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.

Edited 4 Years Ago by Sendy Hipo

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.

bump

Comments
It's impolite to BUMP a thread. Whe someone that can answer reads it, they will answer.

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

Edited 4 Years Ago by Sendy Hipo

This article has been dead for over six months. Start a new discussion instead.