Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // This is an expression calculator using code from
- // "Principles and Practice using C++" by Bjarne Stroustrup as basis
- // Edited and run by Osman Zakir
- // 4/26/2015
- //
- /*
- Simple calculator
- Revision history:
- Revised by Bjarne Stroustrup November 2013
- Revised by Bjarne Stroustrup May 2007
- Revised by Bjarne Stroustrup August 2006
- Revised by Bjarne Stroustrup August 2004
- Originally written by Bjarne Stroustrup
- ([email protected]) Spring 2004.
- This program implements a basic expression calculator.
- Input from cin; output to cout.
- The grammar for input is:
- Calculation:
- Statement
- Print
- Quit
- Calculation Statement
- Square Root (sqrt())
- Exponent (pow())
- Statement:
- Declaration
- Expression
- Declaration:
- "let" Name "=" Expression
- Print:
- ;
- Quit:
- q
- Expression:
- Term
- Expression + Term
- Expression – Term
- Term:
- Primary
- Primary! (read: Primary factorial)
- Term * Primary
- Term / Primary
- Term % Primary
- Variable * Primary
- Variable / Primary
- Variable % Primary
- Primary:
- Number
- Variable
- ( Expression )
- – Primary
- + Primary
- Number:
- floating-point-literal
- Input comes from cin through the Token_stream called ts.
- */
- #include <cmath>
- #include <vector>
- #include <cctype>
- #include "../custom_std_lib_facilities.h"
- #include <stdexcept>
- using namespace std;
- class Token
- {
- public:
- char kind;
- double value;
- string name;
- Token(char ch) :kind{ch} {}
- Token(char ch, double val) :kind{ch}, value{val} {}
- Token(char ch, string n) :kind{ch}, name{n} {}
- };
- class Token_stream
- {
- public:
- Token_stream();
- Token get(Token_stream& ts); // get a Token
- void putback(Token t); // put a Token back
- void ignore(char c); // discard characters up to and including a c
- private:
- bool full {false};
- Token buffer;
- };
- class Variable
- {
- public:
- string name;
- double value;
- Variable(string var, double val) :name(var), value(val) {}
- };
- void calculate(Token_stream& ts, const char& quit, const char& print);
- double expression(Token_stream& ts); // read and evaluate a Expression
- void clean_up_mess(Token_stream& ts, const char& print);
- double term(Token_stream& ts); // read and evaluate a Term
- double get_value(const string& s);
- void set_value(const string& s, double d, vector<Variable> var_table);
- double statement(Token_stream& ts);
- bool is_declared(const string& var);
- double define_name(const string& var, double val);
- double declaration(Token_stream& ts);
- int main()
- {
- cout.precision(3);
- cout.setf(ios::fixed);
- Token_stream ts;
- vector<Variable> var_table;
- const char quit = 'q';
- const char print = ';';
- try
- {
- cout << "Welcome to our simple calculator. We can handle the operations '+', '-', '*', '/', '!' and '%' (for remainders).\n";
- cout << "Negative numbers are allowed. To get the result for an expression, press ';'.\n";
- cout << "To stop entering values and to reach the end of the program, press 'q'.\n";
- cout << "The '>' on the screen means you can do a calculation.\n";
- cout << "You can use 'p' to raise a number to a power (specify power after the 'p') and you can use 's' to take the ";
- cout << "square-root of a number. Good luck.\n\n";
- // predefined Variables for PI, Euler's Number and k (k for 1000, like how 4k means 4000)
- define_name("pi",3.1415926535);
- define_name("e",2.7182818284);
- define_name("k", 1000);
- calculate(ts, quit, print);
- keep_window_open(); // cope with Windows console mode
- return 0;
- }
- catch (exception& e)
- {
- cerr << e.what() << endl;
- keep_window_open ("~~");
- return 1;
- }
- catch (...)
- {
- cerr << "exception \n";
- keep_window_open ("~~");
- return 2;
- }
- }
- void calculate(Token_stream& ts, const char& quit, const char& print)
- {
- const string prompt = "> ";
- const string result = "= "; // used to indicate that what follows is a result
- while (cin)
- {
- try
- {
- cout << prompt;
- Token t = ts.get(ts);
- while (t.kind == print)
- {
- t = ts.get(ts); // first discard all "prints"
- }
- if (t.kind == quit)
- {
- return;
- }
- ts.putback(t);
- cout << "\n" << result << statement(ts) << '\n';
- }
- catch (exception& e)
- {
- cerr << e.what() << '\n'; // write error message
- clean_up_mess(ts, print);
- }
- }
- }
- void clean_up_mess(Token_stream& ts, const char& print)
- {
- ts.ignore(print);
- }
- Token_stream::Token_stream()
- :full(false), buffer(0) // no Token in buffer
- {
- }
- void Token_stream::putback(Token t) // put a Token back into the Token stream
- {
- buffer = t;
- full = true;
- }
- const char name = 'a'; // for Variable names
- const char let = 'L'; // declaration Token
- const char number = '8';
- const string declkey = "let"; // declaration keyword
- Token Token_stream::get(Token_stream& ts) // read from cin and compose a Token
- {
- if (full)
- {
- full = false;
- return buffer;
- }
- char ch;
- cin >> ch;
- switch (ch)
- {
- case 'q':
- case ';':
- case '(':
- case ')':
- case '{':
- case '}':
- case '+':
- case '-':
- case '*':
- case '/':
- case '%':
- case '=':
- case '!':
- case 's':
- case 'p':
- return Token{ch}; // let each character represent itself
- case '.': // a floating-point literal can start with a dot
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9': // numeric literal
- {
- cin.putback(ch); // put digit back into the input stream
- double val;
- cin >> val;
- return {number, val};
- }
- default:
- if (isalpha(ch))
- {
- string s;
- s += ch;
- while (cin.get(ch) && (isalpha(ch) || isdigit(ch)))
- {
- s += ch;
- }
- cin.putback(ch);
- if (s == declkey)
- {
- return Token{let};
- }
- return Token{name, s};
- }
- error("Bad token");
- }
- }
- void Token_stream::ignore(char c)
- {
- if (full && c == buffer.kind)
- {
- full = false;
- return;
- }
- full = false;
- // now search input
- char ch = 0;
- while (cin >> ch)
- {
- if (ch == c)
- {
- return;
- }
- }
- }
- double primary(Token_stream& ts) // read and evaluate a Primary
- {
- Token t = ts.get(ts);
- switch (t.kind)
- {
- case '(': // handle '(' expression ')'
- {
- double d = expression(ts);
- t = ts.get(ts);
- if (t.kind != ')')
- {
- error("')' expected");
- }
- return d;
- break;
- }
- case '{':
- {
- double d = expression(ts);
- t = ts.get(ts);
- if (t.kind != '}')
- {
- error("'}' expected");
- }
- return d;
- }
- case number:
- return t.value;
- case '-':
- return - primary(ts);
- case '+':
- return primary(ts);
- default:
- error("primary expected");
- }
- }
- double expression(Token_stream& ts)
- {
- double left = term(ts);
- Token t = ts.get(ts);
- while (true)
- {
- switch (t.kind)
- {
- case '+':
- left += term(ts);
- t = ts.get(ts);
- break;
- case '-':
- left -= term(ts);
- t = ts.get(ts);
- break;
- default:
- ts.putback(t);
- return left;
- }
- }
- }
- double statement(Token_stream& ts)
- {
- Token t = ts.get(ts);
- switch (t.kind)
- {
- case let:
- return declaration(ts);
- default:
- ts.putback(t);
- return expression(ts);
- }
- }
- double term(Token_stream& ts)
- {
- double left = primary(ts);
- Token t = ts.get(ts);
- while (true)
- {
- switch (t.kind)
- {
- case 'p':
- {
- double power = primary(ts);
- left = pow(left, power);
- t = ts.get(ts);
- break;
- }
- case '!':
- {
- for (int i = left - 1; i > 1; i--)
- {
- left *= i;
- }
- t = ts.get(ts);
- break;
- }
- case 's':
- {
- left = sqrt(left);
- t = ts.get(ts);
- break;
- }
- case '*':
- left *= primary(ts);
- t = ts.get(ts);
- break;
- case '/':
- {
- double d = primary(ts);
- if (d == 0)
- {
- error("divide by 0");
- }
- left /= d;
- t = ts.get(ts);
- break;
- }
- case '%':
- {
- double d = primary(ts);
- if (d == 0)
- {
- error("division by 0");
- }
- left = fmod(left, d);
- t = ts.get(ts);
- break;
- }
- default:
- ts.putback(t);
- return left;
- }
- }
- }
- vector<Variable> var_table;
- double get_value(const string& s)
- // return the value of a Variable named s
- {
- for (const Variable& v : var_table)
- {
- if (v.name == s)
- {
- return v.value;
- }
- }
- error("get: undefined variable ", s);
- }
- void set_value(const string& s, double d)
- // set the Variable named s to d
- // (change the value of Variable s to d)
- {
- for (Variable& v : var_table)
- {
- if (v.name == s)
- {
- v.value = d;
- return;
- }
- }
- error("set: undefined variable ", s);
- }
- double declaration(Token_stream& ts)
- // assume we have seen "let"
- // handle: name = expression
- // declare a variable called "name" with the initial value "expression"
- {
- Token t = ts.get(ts);
- if (t.kind != name)
- {
- error("name expected in declaration");
- }
- string var_name = t.name;
- Token t2 = ts.get(ts);
- if (t2.kind != '=')
- {
- error("= missing in declaration of ", var_name);
- }
- double d = expression(ts);
- define_name(var_name, d);
- return d;
- }
- bool is_declared(const string& var)
- // is var already in var_table?
- {
- for (const Variable& v : var_table)
- {
- if (v.name == var)
- {
- return true;
- }
- }
- return false;
- }
- double define_name(const string& var, double val)
- // add (var, val) to var_table
- {
- if (is_declared(var))
- {
- error(var, " declared twice");
- }
- var_table.push_back(Variable(var, val));
- return val;
- }
Advertisement
Add Comment
Please, Sign In to add comment