Hi people, I am currently teaching myself C++ with Stroustrup's "Programming, Principles and Practice using C++" and I'm stuck on one of the in-book exercises. It is a chunk of code (~180 lines) of buggy code that, when debugged properly, should create a calculator program. I have reached the limits of my ability and need some more help. There are 8 bugs in total, 5 syntax and 3 logic. I have debugged the syntax errors and now need help with the logic. I think I got one of the logic, so there *should* only be 2 left.

Any help would be very useful. Hopefully the code won't be *too* long.

//
// This is example code from Chapter 6.7 "Trying the second version" of
// "Software - Principles and Practice using C++" by Bjarne Stroustrup
//

/*
	This file is known as calculator02buggy.cpp

	I have inserted 5 errors that should cause this not to compile
	I have inserted 3 logic errors that should cause the program to give wrong results

	First try to find an remove the bugs without looking in the book.
	If that gets tedious, compare the code to that in the book (or posted source code)
	Happy hunting!
*/
#include "stdafx.h"
#include "...\std_lib_facilities.h"
//------------------------------------------------------------------------------
class Token {
public:
    char kind;        // what kind of token
    double value;     // for numbers: a value 
    Token(char ch)    // make a Token from a char
        :kind(ch), value(0) { }    
    Token(char ch, double val)     // make a Token from a char and a double
        :kind(ch), value(val) { }
};
//------------------------------------------------------------------------------
class Token_stream {
public: 
    Token_stream();   // make a Token_stream that reads from cin
    Token get();      // get a Token (get() is defined elsewhere)
    void putback(Token t);    // put a Token back
private:
    bool full;        // is there a Token in the buffer?
    Token buffer;     // here is where we keep a Token put back using putback()
};
//------------------------------------------------------------------------------
// The constructor just sets full to indicate that the buffer is empty:
Token_stream::Token_stream()
:full(false), buffer(0)    // no Token in buffer
{
}
//------------------------------------------------------------------------------
// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
    if (full) error("putback() into a full buffer");
    buffer = t;       // copy t to buffer
    full = true;      // buffer is now full
}
//------------------------------------------------------------------------------
Token Token_stream::get()
{
    if (full) {       // do we already have a Token ready?
        // remove token from buffer
        full=false;
        return buffer;
    } 
    char ch;
    cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)
    switch (ch) {
    case ';':    // for "print"
    case 'q':    // for "quit"
    case '(': case ')': case '+': case '-': case '*': case '/': 
        return Token(ch);        // let each character represent itself
    case '.':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '9':
		{
            double val;
            cin >> val;              // read a floating-point number
            return Token('8',val);   // let '8' represent "a number"
			cin.putback(ch);         // put digit back into the input stream
		}
    default:
        error("Bad token");
    }
}
//------------------------------------------------------------------------------
Token_stream ts;        // provides get() and putback() 
//------------------------------------------------------------------------------
double expression();    // declaration so that primary() can call expression()
//------------------------------------------------------------------------------
// deal with numbers and parentheses
double primary()
{
    Token t = ts.get();
    switch (t.kind) {
    case '(':    // handle '(' expression ')'
        {    
            double d = expression();
            t = ts.get();
            if (t.kind != ')') error("')' expected");
            return d;
        }
    case '8':            // we use '8' to represent a number
        return t.value;  // return the number's value
    default:
        error("primary expected");
    }
}
//------------------------------------------------------------------------------
// deal with *, /, and %
double term()
{
    double left = primary();
    Token t = ts.get();        // get the next token from token stream
    while(true) {
        switch (t.kind) {
        case '*':
            left *= primary();
            t = ts.get();
        case '/':
            {    
                double d = primary();
                if (d == 0) error("divide by zero");
                left /= d; 
                t = ts.get();
                break;
            }
        default: 
            ts.putback(t);     // put t back into the token stream
            return left;
        }
    }
}
//------------------------------------------------------------------------------
// deal with + and -
double expression()
{
    double left = term();      // read and evaluate a Term
    Token t = ts.get();        // get the next token from token stream
    while(true) {    
        switch(t.kind) {
        case '+':
            left += term();    // evaluate Term and add
            t = ts.get();
            break;
        case '-':
            left += term();    // evaluate Term and subtract
            t = ts.get();
            break;
        default: 
            ts.putback(t);     // put t back into the token stream
            return left;       // finally: no more + or -: return the answer
        }
    }
}
//------------------------------------------------------------------------------
int main()
try
{
    while (cin) {
		double val;
        Token t = ts.get();
        if (t.kind == 'q') break; // 'q' for quit
        if (t.kind == ';')        // ';' for "print now"
            cout << "=" << val << '\n';
        else
            ts.putback(t);
        val = expression();
    }
	keep_window_open();
}
catch (exception& e) {
    cerr << "error: " << e.what() << '\n'; 
	keep_window_open();
    return 1;
}
catch (...) {
    cerr << "Oops: unknown exception!\n"; 
	keep_window_open();
    return 2;
}
//------------------------------------------------------------------------------

Recommended Answers

All 12 Replies

I actually went a head to try compile your code.

You are using two headers which prevents me from compiling this code, as I don't have them.

You are using two headers which prevents me from compiling this code, as I don't have them

You can get the second one from BS's page (it's just a mishmash of #includes, template functions,etc)http://www.stroustrup.com/Programming/std_lib_facilities.h

stdafx is needed for precompiled headers. If the OP doesn't have anything listed in there, you can skip it.

>>I think I got one of the logic, so there *should* only be 2 left.

Why two? If you know where the bugs are, you might want to tell us. We're not all clairvoyant here.

commented: OK, WaltP.... Only kidding. His comments are desperately needed. +4

If there are three logic bugs in total and one's down, two are left.

>>If there are three logic bugs in total and one's down, two are left.

Holy shit. That's some amazing math!
Although you obviously think otherwise: I'm not stupid. I was asking where the two remaining errors are.

Nothing indicates that the OP knows where they are, so your question inevitably led me to believe you didn't read the post entirely.

>> I have debugged the syntax errors and now need help with the logic. I think I got
>> one of the logic, so there *should* only be 2 left.

So, if you've gotten the code to compile, it might be worth testing its functionality to see where it goes wrong.

I.e. run very simple tests such as;

1 + 1;
2 * 2;

and so on.

PS. If you already haven't, then try to configure your compiler to produce as many warnings as possible - that might help too.

>>If there are three logic bugs in total and one's down, two are left.

Holy shit. That's some amazing math!
Although you obviously think otherwise: I'm not stupid. I was asking where the two remaining errors are.

I think he got this code from the book. And the book probably said there was x amounts
of errors in the code. And so, he is left hunting for them. Thats why, he maybe saying there are 2 errors left.

I think he got this code from the book. And the book probably said there was x amounts
of errors in the code. And so, he is left hunting for them. Thats why, he maybe saying there are 2 errors left.

You're right, it even says so in the code. But I never read the code because the question wasn't clear, so: whoopsie :S

Anyway: I compiled the code and I can't get one single calculation out of it. There are still quite a few things things wrong with this code. Could you indicate which things you've already changed? Maybe you accidently introduced some new bugs in the code, while removing others? I don't own the book, so I can't check.

I am teaching myself C++ with the very same book and did that very exercise yesterday.

One of the 3 'run-time' errors, as opposed to the 5 'compile-time' errors, is that not all of the possible cases are accounted for. The calculator won't recognize a certain digit as a valid token.

A second 'run-time' error is that the calculator won't perform one of the operations it is supposed to because the character that identifies the case is not the same as the operation that the calculator will actually perform.

I am still looking for the third run-time error. The calculator so far gives correct results for me.

Hi, I'm working through the book as well, and am stumped with this problem. I have been able to find one logic error, which is, in the function:

Token Token_stream::get()

There are the following two lines,

case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '9':

This should be changed to:

case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':

to include:

case '8':

If you figure out how to do the rest let me know.

EDIT: Just realised someone else has already mentioned that error. I looked at the OP's code and the first page, so missed the last post.

Hi,

in case anyone will still be looking here for help, I managed to find all of the logic errors. As the above have stated, the case for the digit 8 is missing.

Secondly, the calculator will not break out of the multiplication, so you need to add a break; statement to the multiplication case of the term function.

Finaly, the expression function will add numbers in both cases, so you need to switch the subtraction case to -= to actually perform the subtraction.

I hope this helps! :)

~Lebar

Be a part of the DaniWeb community

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