bugged calculator..

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 :

please do check on primary () function

sorry for the long code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
 
#include <iostream>

#include <cctype>
#include "std_lib_facilities.h"



const char number = '8';
const char print = ';';
const char quit = 'q';
const char test = 'a';
const char let = 'L';

class Token
{
    public:
    char kind;
    double value;
    string name;

    Token(char k, String n)
    {
        kind = k;
        name = n;
        value = 0;
    }

    Token(char k, double v)
    {
        kind = k;
        value = v;
        name = "";
    }
    Token(char k)
    {
        kind = k;
        value = 0;
    }
    Token(double v)
    {
        kind = number;
        value = 0;
    }
    Token(String s)
    {
        name = s;
    }
    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);// taro char balik ke istream
                double value;
                std::cin>>value;//smua yang ad di istream(yang tadi d putback) d masukin ke value

                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(test);
                            }



                        }
                        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();
    std::cout<<left<<std::endl;//check the value that's returned from primary , it says "nan"

    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 x = ts.get();

    switch(x.kind)
    {
        case '(' :
               {
                   std::cout<<"case (\n";
                   double d = expression();
                   x = ts.get();
                   if(x.kind != ')')
                   {
                       error("error expected ) !");
                   }
                   return d;
               }
        case '{':std::cout<<"case {\n";
                {
                    double d = expression();
                   x = ts.get();
                   if(x.kind != '}')
                   {
                       error("error expected } !");
                   }
                   return d;
                }
        case number: std::cout<<x.value<<std::endl; //i check the value here
                     return x.value;break;
        case '+' :std::cout<<"case +\n"; return primary();
        case '-' :std::cout<<"case -\n"; 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.
Last edited on
closed account (j2NvC542)
I have some error in a header file now, but it should work on windows. I have done the same exercise and I could pastebin it if you want, so you can compare with yours.
erm sure
actually i know that the problem is (what i think) from the primary function that's not returning the right value, do you know why this happens?
What is the error?
closed account (j2NvC542)
This is my output:
> 1+3;
1
1
3
3
the answer is = 4

This is on Windows XP with Visual C++ 2010 Express. I assume you use that IDE too?

I have no idea how it outputs "nan". Really.
Last edited on
guys i just tried using visual c++ 2010 and it works, before i used codeblocks (windows).
now the question is why in codde blocks it(the code, specificly in primary () function) returns "nan"?
closed account (j2NvC542)
Build log in Codeblocks:

/usr/lib/gcc/x86_64-redhat-linux/4.6.3/../../../../include/c++/4.6.3/bits/locale_facets_nonio.h:1902:5: error: template-id ‘do_get<>’ for ‘String std::messages<char>::do_get(std::messages_base::catalog, int, int, const String&) const’ does not match any template declaration
/usr/lib/gcc/x86_64-redhat-linux/4.6.3/../../../../include/c++/4.6.3/bits/locale_facets_nonio.h:1902:62: note: saw 1 ‘template<>’, need 2 for specializing a member function template


Build messages:

/usr/lib/gcc/x86_64-redhat-linux/4.6.3/../../../../include/c++/4.6.3/bits/locale_facets_nonio.h|1902|error: template-id ‘do_get<>’ for ‘String std::messages<char>::do_get(std::messages_base::catalog, int, int, const String&) const’ does not match any template declaration|
/usr/lib/gcc/x86_64-redhat-linux/4.6.3/../../../../include/c++/4.6.3/bits/locale_facets_nonio.h|1902|note: saw 1 ‘template<>’, need 2 for specializing a member function template|


Can we see your std_lib_facilities.h?
erm sure, actually i just make new header files and copy all contents from :

http://stroustrup.com/Programming/std_lib_facilities.h

to my new header file which i named "std_lib_facilities.h"
Topic archived. No new replies allowed.