0

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 by Sendy Hipo

2
Contributors
4
Replies
5
Views
4 Years
Discussion Span
Last Post by Sendy Hipo
0

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.

-2

bump

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

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 by Sendy Hipo

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.