Skip to content

Instantly share code, notes, and snippets.

@torazuka
Created September 7, 2011 23:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save torazuka/1202112 to your computer and use it in GitHub Desktop.
Save torazuka/1202112 to your computer and use it in GitHub Desktop.
Chapter06_drill_PPPC++
//
// 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!
this is one answer
*/
#include "../../std_lib_facilities.h"
//------------------------------------------------------------------------------
// lass Token { // error(1)
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 get() // error(2)
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 'x': // 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': // logic error(1)
case '5': case '6': case '7': case '8': case '9':
{
cin.putback(ch); // put digit back into the input stream
double val;
cin >> val; // read a floating-point number
return Token('8',val); // let '8' represent "a number"
}
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); // error(3)
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();
// logic error(2)
break;
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 // error(4)
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 // logic error(3)
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
{
cout << "Welcome to our simple calculator.\n";
cout << "Please enter expressions using floating-point numbers.\n";
cout << "[+, -, *, /]operators, [x]quit, [=]print result\n";
// error(5)
double val = 0;
while (cin) {
Token t = ts.get();
if (t.kind == 'x') break; // 'x' 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;
}
//------------------------------------------------------------------------------
@hadiys
Copy link

hadiys commented Jul 23, 2020

Can you post the original buggy code as well ?

Thanks!

@torazuka
Copy link
Author

@hadiys
Copy link

hadiys commented Jul 25, 2020

Thank you Sir!

@shengchao-lin
Copy link

I was recently looking at this code as well. However, inputs like "1+2=x" would break the program. As when the program reads line 173 (after getting 3) and gets a "=" it would put "=" back to be caught.
Then after printing the result (line 202), it would try to get an expression. However it's "x" next which will throw error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment