c++
/* 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 "../std_lib_facilities.h" //------------------------------------------------------------------------------ lass 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() { 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': { 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); 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) { 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; }
Headerfile
/* simple "Programming: Principles and Practice using C++" course header to be used for the first few weeks. It provides the most common standard headers (in the global namespace) and minimal exception/error support. Students: please don't try to understand the details of headers just yet. All will be explained. This header is primarily used so that you don't have to understand every concept all at once. Revised April 25, 2010: simple_error() added */ #ifndef H112 #define H112 201004L #include<iostream> #include<fstream> #include<sstream> #include<cmath> #include<cstdlib> #include<string> #include<list> #include<vector> #include<algorithm> #include<stdexcept> //------------------------------------------------------------------------------ #ifdef _MSC_VER #include <hash_map> using stdext::hash_map; #else #include <ext/hash_map> using __gnu_cxx::hash_map; namespace __gnu_cxx { template<> struct hash<std::string> { size_t operator()(const std::string& s) const { return hash<char*>()(s.c_str()); } }; } // of namespace __gnu_cxx #endif //------------------------------------------------------------------------------ #define unordered_map hash_map //------------------------------------------------------------------------------ typedef long Unicode; //------------------------------------------------------------------------------ using namespace std; template<class T> string to_string(const T& t) { ostringstream os; os << t; return os.str(); } struct Range_error : out_of_range { // enhanced vector range error reporting int index; Range_error(int i) :out_of_range("Range error: "+to_string(i)), index(i) { } }; // trivially range-checked vector (no iterator checking): template< class T> struct Vector : public std::vector<T> { typedef typename std::vector<T>::size_type size_type; Vector() { } explicit Vector(size_type n) :std::vector<T>(n) {} Vector(size_type n, const T& v) :std::vector<T>(n,v) {} template <class I> Vector(I first, I last) :std::vector<T>(first,last) {} T& operator[](unsigned int i) // rather than return at(i); { if (i<0||this->size()<=i) throw Range_error(i); return std::vector<T>::operator[](i); } const T& operator[](unsigned int i) const { if (i<0||this->size()<=i) throw Range_error(i); return std::vector<T>::operator[](i); } }; // disgusting macro hack to get a range checked vector: #define vector Vector // trivially range-checked string (no iterator checking): struct String : std::string { String() { } String(const char* p) :std::string(p) {} String(const string& s) :std::string(s) {} template<class S> String(S s) :std::string(s) {} String(int sz, char val) :std::string(sz,val) {} template<class Iter> String(Iter p1, Iter p2) : std::string(p1,p2) { } char& operator[](unsigned int i) // rather than return at(i); { if (i<0||size()<=i) throw Range_error(i); return std::string::operator[](i); } const char& operator[](unsigned int i) const { if (i<0||size()<=i) throw Range_error(i); return std::string::operator[](i); } }; #ifndef _MSC_VER namespace __gnu_cxx { template<> struct hash<String> { size_t operator()(const String& s) const { return hash<std::string>()(s); } }; } // of namespace __gnu_cxx #endif struct Exit : runtime_error { Exit(): runtime_error("Exit") {} }; // error() simply disguises throws: inline void error(const string& s) { throw runtime_error(s); } inline void error(const string& s, const string& s2) { error(s+s2); } inline void error(const string& s, int i) { ostringstream os; os << s <<": " << i; error(os.str()); } #if _MSC_VER<1500 // disgusting macro hack to get a range checked string: #define string String // MS C++ 9.0 have a built-in assert for string range check // and uses "std::string" in several places so that macro substitution fails #endif template<class T> char* as_bytes(T& i) // needed for binary I/O { void* addr = &i; // get the address of the first byte // of memory used to store the object return static_cast<char*>(addr); // treat that memory as bytes } inline void keep_window_open() { cin.clear(); cout << "Please enter a character to exitn"; char ch; cin >> ch; return; } inline void keep_window_open(string s) { if (s=="") return; cin.clear(); cin.ignore(120,'n'); for (;;) { cout << "Please enter " << s << " to exitn"; string ss; while (cin >> ss && ss!=s) cout << "Please enter " << s << " to exitn"; return; } } // error function to be used (only) until error() is introduced in Chapter 5: inline void simple_error(string s) // write ``error: s�� and exit program { cerr << "error: " << s << 'n'; keep_window_open(); // for some Windows environments exit(1); } // make std::min() and std::max() accessible: #undef min #undef max #include<iomanip> inline ios_base& general(ios_base& b) // to augment fixed and scientific { b.setf(ios_base::fmtflags(0),ios_base::floatfield); return b; } // run-time checked narrowing cast (type conversion): template<class R, class A> R narrow_cast(const A& a) { R r = R(a); if (A(r)!=a) error(string("info loss")); return r; } inline int randint(int max) { return rand()%max; } inline int randint(int min, int max) { return randint(max-min)+min; } inline double sqrt(int x) { return sqrt(double(x)); } // to match C++0x #endif
Expert Answer
// ERROR.at_least_for_me #include “../std_lib_facilities.h”
#include “std_lib_facilities.h”
//——————————————————————————
// ERROR.1.syntax lass Token {
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
}
//——————————————————————————
// ERROR.2.syntax Token get()
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’:
// ERROR.3.logic case ‘5’: case ‘6’: case ‘7’: case ‘9’:
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();
// ERROR.4.syntax if (t.kind != ‘)’) error(“‘)’ expected);
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();
// ERROR.5.logic no break;
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()
{
// ERROR.6.syntax double left = term(; // read and evaluate a Term
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 ‘-‘:
// ERROR.7.logic left += term(); // evaluate Term and subtract
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”
<< “Please enter expressions using floating-point numbers.n”
<< “(Currently +, -, *, /, and () are supported.)n”
<< “Evaluate the expression with = at the end. Enter x to quit.n”;
// ERROR.8.syntax No val variable declared
double val = 0;
while (cin) {
Token t = ts.get();
if (t.kind == ‘x’) 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;
}
//——————————————————————————
std_lib_facilities.h
#ifndef H112
#define H112 251113L
#include<iostream>
#include<iomanip>
#include<fstream>
#include<sstream>
#include<cmath>
#include<cstdlib>
#include<string>
#include<list>
#include <forward_list>
#include<vector>
#include<unordered_map>
#include<algorithm>
#include <array>
#include <regex>
#include<random>
#include<stdexcept>
typedef long Unicode;
//——————————————————————————
using namespace std;
template<class T> string to_string(const T& t)
{
ostringstream os;
os << t;
return os.str();
}
struct Range_error : out_of_range { // enhanced vector range error reporting
int index;
Range_error(int i) :out_of_range(“Range error: “+to_string(i)), index(i) { }
};
// trivially range-checked vector (no iterator checking):
template< class T> struct Vector : public std::vector<T> {
using size_type = typename std::vector<T>::size_type;
#ifdef _MSC_VER
// microsoft doesn’t yet support C++11 inheriting constructors
Vector() { }
explicit Vector(size_type n) :std::vector<T>(n) {}
Vector(size_type n, const T& v) :std::vector<T>(n,v) {}
template <class I>
Vector(I first, I last) : std::vector<T>(first, last) {}
Vector(initializer_list<T> list) : std::vector<T>(list) {}
#else
using std::vector<T>::vector; // inheriting constructor
#endif
T& operator[](unsigned int i) // rather than return at(i);
{
if (i<0||this->size()<=i) throw Range_error(i);
return std::vector<T>::operator[](i);
}
const T& operator[](unsigned int i) const
{
if (i<0||this->size()<=i) throw Range_error(i);
return std::vector<T>::operator[](i);
}
};
// disgusting macro hack to get a range checked vector:
#define vector Vector
// trivially range-checked string (no iterator checking):
struct String : std::string {
using size_type = std::string::size_type;
// using string::string;
char& operator[](unsigned int i) // rather than return at(i);
{
if (i<0||size()<=i) throw Range_error(i);
return std::string::operator[](i);
}
const char& operator[](unsigned int i) const
{
if (i<0||size()<=i) throw Range_error(i);
return std::string::operator[](i);
}
};
namespace std {
template<> struct hash<String>
{
size_t operator()(const String& s) const
{
return hash<std::string>()(s);
}
};
} // of namespace std
struct Exit : runtime_error {
Exit(): runtime_error(“Exit”) {}
};
// error() simply disguises throws:
inline void error(const string& s)
{
throw runtime_error(s);
}
inline void error(const string& s, const string& s2)
{
error(s+s2);
}
inline void error(const string& s, int i)
{
ostringstream os;
os << s <<“: ” << i;
error(os.str());
}
template<class T> char* as_bytes(T& i) // needed for binary I/O
{
void* addr = &i; // get the address of the first byte
// of memory used to store the object
return static_cast<char*>(addr); // treat that memory as bytes
}
inline void keep_window_open()
{
cin.clear();
cout << “Please enter a character to exitn”;
char ch;
cin >> ch;
return;
}
inline void keep_window_open(string s)
{
if (s==””) return;
cin.clear();
cin.ignore(120,’n’);
for (;;) {
cout << “Please enter ” << s << ” to exitn”;
string ss;
while (cin >> ss && ss!=s)
cout << “Please enter ” << s << ” to exitn”;
return;
}
}
// error function to be used (only) until error() is introduced in Chapter 5:
inline void simple_error(string s) // write “error: s and exit program
{
cerr << “error: ” << s << ‘n’;
keep_window_open(); // for some Windows environments
exit(1);
}
// make std::min() and std::max() accessible on systems with antisocial macros:
#undef min
#undef max
// run-time checked narrowing cast (type conversion). See ???.
template<class R, class A> R narrow_cast(const A& a)
{
R r = R(a);
if (A(r)!=a) error(string(“info loss”));
return r;
}
// random number generators. See 24.7.
inline int randint(int min, int max) { static default_random_engine ran; return uniform_int_distribution<>{min, max}(ran); }
inline int randint(int max) { return randint(0, max); }
//inline double sqrt(int x) { return sqrt(double(x)); } // to match C++0x
// container algorithms. See 21.9.
template<typename C>
using Value_type = typename C::value_type;
template<typename C>
using Iterator = typename C::iterator;
template<typename C>
// requires Container<C>()
void sort(C& c)
{
std::sort(c.begin(), c.end());
}
template<typename C, typename Pred>
// requires Container<C>() && Binary_Predicate<Value_type<C>>()
void sort(C& c, Pred p)
{
std::sort(c.begin(), c.end(), p);
}
template<typename C, typename Val>
// requires Container<C>() && Equality_comparable<C,Val>()
Iterator<C> find(C& c, Val v)
{
return std::find(c.begin(), c.end(), v);
}
template<typename C, typename Pred>
// requires Container<C>() && Predicate<Pred,Value_type<C>>()
Iterator<C> find_if(C& c, Pred p)
{
return std::find_if(c.begin(), c.end(), p);
}
#endif //H112