DragonOsman

Expression Calculator

May 7th, 2015
496
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.07 KB | None | 0 0
  1. //
  2. // This is an expression calculator using code from
  3. // "Principles and Practice using C++" by Bjarne Stroustrup as basis
  4. // Edited and run by Osman Zakir
  5. // 4/26/2015
  6. //
  7. /*
  8.           Simple calculator
  9.  
  10.           Revision history:
  11.  
  12.                     Revised by Bjarne Stroustrup November 2013
  13.                     Revised by Bjarne Stroustrup May 2007
  14.                     Revised by Bjarne Stroustrup August 2006
  15.                     Revised by Bjarne Stroustrup August 2004
  16.                     Originally written by Bjarne Stroustrup
  17.                                ([email protected]) Spring 2004.
  18.  
  19.           This program implements a basic expression calculator.
  20.           Input from cin; output to cout.
  21.           The grammar for input is:
  22.  
  23.           Calculation:
  24.                      Statement
  25.                      Print
  26.                      Quit
  27.                      Calculation Statement
  28.                      Square Root (sqrt())
  29.                      Exponent (pow())
  30.  
  31.           Statement:
  32.                      Declaration
  33.                      Expression
  34.  
  35.           Declaration:
  36.                      "let" Name "=" Expression
  37.  
  38.           Print:
  39.                     ;
  40.  
  41.           Quit:
  42.                     q
  43.  
  44.           Expression:
  45.                     Term
  46.                     Expression + Term
  47.                     Expression – Term
  48.           Term:
  49.                     Primary
  50.                     Primary! (read: Primary factorial)
  51.                     Term * Primary
  52.                     Term / Primary
  53.                     Term % Primary
  54.                     Variable * Primary
  55.                     Variable / Primary
  56.                     Variable % Primary
  57.           Primary:
  58.                     Number
  59.                     Variable
  60.                     ( Expression )
  61.                     – Primary
  62.                     + Primary
  63.           Number:
  64.                     floating-point-literal
  65.  
  66.  
  67.           Input comes from cin through the Token_stream called ts.
  68. */
  69.  
  70. #include <cmath>
  71. #include <vector>
  72. #include <cctype>
  73. #include "../custom_std_lib_facilities.h"
  74. #include <stdexcept>
  75.  
  76. using namespace std;
  77.  
  78. class Token
  79. {
  80. public:
  81.     char kind;
  82.     double value;
  83.     string name;
  84.     Token(char ch) :kind{ch} {}
  85.     Token(char ch, double val) :kind{ch}, value{val} {}
  86.     Token(char ch, string n) :kind{ch}, name{n} {}
  87. };
  88.  
  89. class Token_stream
  90. {
  91. public:
  92.     Token_stream();
  93.     Token get(Token_stream& ts);        // get a Token
  94.     void putback(Token t);      // put a Token back
  95.     void ignore(char c);        // discard characters up to and including a c
  96. private:
  97.     bool full {false};
  98.     Token buffer;
  99. };
  100.  
  101. class Variable
  102. {
  103. public:
  104.     string name;
  105.     double value;
  106.     Variable(string var, double val) :name(var), value(val) {}
  107. };
  108.  
  109. void calculate(Token_stream& ts, const char& quit, const char& print);
  110.  
  111. double expression(Token_stream& ts);  // read and evaluate a Expression
  112.  
  113. void clean_up_mess(Token_stream& ts, const char& print);
  114.  
  115. double term(Token_stream& ts);        // read and evaluate a Term
  116.  
  117. double get_value(const string& s);
  118.  
  119. void set_value(const string& s, double d, vector<Variable> var_table);
  120.  
  121. double statement(Token_stream& ts);
  122.  
  123. bool is_declared(const string& var);
  124.  
  125. double define_name(const string& var, double val);
  126.  
  127. double declaration(Token_stream& ts);
  128.  
  129. int main()
  130. {
  131.     cout.precision(3);
  132.     cout.setf(ios::fixed);
  133.     Token_stream ts;
  134.     vector<Variable> var_table;
  135.     const char quit = 'q';
  136.     const char print = ';';
  137.     try
  138.     {
  139.         cout << "Welcome to our simple calculator.  We can handle the operations '+', '-', '*', '/', '!' and '%' (for remainders).\n";
  140.         cout << "Negative numbers are allowed. To get the result for an expression, press ';'.\n";
  141.         cout << "To stop entering values and to reach the end of the program, press 'q'.\n";
  142.         cout << "The '>' on the screen means you can do a calculation.\n";
  143.         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 ";
  144.         cout << "square-root of a number.  Good luck.\n\n";
  145.         // predefined Variables for PI, Euler's Number and k (k for 1000, like how 4k means 4000)
  146.         define_name("pi",3.1415926535);
  147.         define_name("e",2.7182818284);
  148.         define_name("k", 1000);
  149.         calculate(ts, quit, print);
  150.         keep_window_open();     // cope with Windows console mode
  151.         return 0;
  152.     }
  153.     catch (exception& e)
  154.     {
  155.         cerr << e.what() << endl;
  156.         keep_window_open ("~~");
  157.         return 1;
  158.     }
  159.     catch (...)
  160.     {
  161.         cerr << "exception \n";
  162.         keep_window_open ("~~");
  163.         return 2;
  164.     }
  165. }
  166.  
  167. void calculate(Token_stream& ts, const char& quit, const char& print)
  168. {
  169.     const string prompt = "> ";
  170.     const string result = "= ";        // used to indicate that what follows is a result
  171.     while (cin)
  172.     {
  173.         try
  174.         {
  175.             cout << prompt;
  176.             Token t = ts.get(ts);
  177.             while (t.kind == print)
  178.             {
  179.                 t = ts.get(ts);       // first discard all "prints"
  180.             }
  181.             if (t.kind == quit)
  182.             {
  183.                 return;
  184.             }
  185.             ts.putback(t);
  186.             cout << "\n" << result << statement(ts) << '\n';
  187.         }
  188.         catch (exception& e)
  189.         {
  190.             cerr << e.what() << '\n';      // write error message
  191.             clean_up_mess(ts, print);
  192.         }
  193.     }
  194. }
  195.  
  196. void clean_up_mess(Token_stream& ts, const char& print)
  197. {
  198.     ts.ignore(print);
  199. }
  200.  
  201. Token_stream::Token_stream()
  202. :full(false), buffer(0)    // no Token in buffer
  203. {
  204. }
  205.  
  206. void Token_stream::putback(Token t)     // put a Token back into the Token stream
  207. {
  208.     buffer = t;
  209.     full = true;
  210. }
  211.  
  212. const char name = 'a';      // for Variable names
  213. const char let = 'L';       // declaration Token
  214. const char number = '8';
  215. const string declkey = "let";     // declaration keyword
  216.  
  217. Token Token_stream::get(Token_stream& ts)       // read from cin and compose a Token
  218. {
  219.  
  220.     if (full)
  221.     {
  222.         full = false;
  223.         return buffer;
  224.     }
  225.     char ch;
  226.     cin >> ch;
  227.     switch (ch)
  228.     {
  229.     case 'q':
  230.     case ';':
  231.     case '(':
  232.     case ')':
  233.     case '{':
  234.     case '}':
  235.     case '+':
  236.     case '-':
  237.     case '*':
  238.     case '/':
  239.     case '%':
  240.     case '=':
  241.     case '!':
  242.     case 's':
  243.     case 'p':
  244.         return Token{ch};       // let each character represent itself
  245.     case '.':           // a floating-point literal can start with a dot
  246.     case '0': case '1': case '2': case '3': case '4':
  247.     case '5': case '6': case '7': case '8': case '9':       // numeric literal
  248.         {
  249.             cin.putback(ch);       // put digit back into the input stream
  250.             double val;
  251.             cin >> val;
  252.             return {number, val};
  253.         }
  254.     default:
  255.         if (isalpha(ch))
  256.         {
  257.             string s;
  258.             s += ch;
  259.             while (cin.get(ch) && (isalpha(ch) || isdigit(ch)))
  260.             {
  261.                 s += ch;
  262.             }
  263.             cin.putback(ch);
  264.             if (s == declkey)
  265.             {
  266.                 return Token{let};
  267.             }
  268.             return Token{name, s};
  269.         }
  270.         error("Bad token");
  271.     }
  272. }
  273.  
  274. void Token_stream::ignore(char c)
  275. {
  276.     if (full && c == buffer.kind)
  277.     {
  278.         full = false;
  279.         return;
  280.     }
  281.     full = false;
  282.     // now search input
  283.     char ch = 0;
  284.     while (cin >> ch)
  285.     {
  286.         if (ch == c)
  287.         {
  288.             return;
  289.         }
  290.     }
  291. }
  292.  
  293. double primary(Token_stream& ts)     // read and evaluate a Primary
  294. {
  295.     Token t = ts.get(ts);
  296.     switch (t.kind)
  297.     {
  298.     case '(':    // handle '(' expression ')'
  299.         {
  300.             double d = expression(ts);
  301.             t = ts.get(ts);
  302.             if (t.kind != ')')
  303.             {
  304.                 error("')' expected");
  305.             }
  306.             return d;
  307.             break;
  308.         }
  309.     case '{':
  310.         {
  311.             double d = expression(ts);
  312.             t = ts.get(ts);
  313.             if (t.kind != '}')
  314.             {
  315.                 error("'}' expected");
  316.             }
  317.             return d;
  318.         }
  319.     case number:
  320.         return t.value;
  321.     case '-':
  322.         return - primary(ts);
  323.     case '+':
  324.         return primary(ts);
  325.     default:
  326.         error("primary expected");
  327.     }
  328. }
  329.  
  330. double expression(Token_stream& ts)
  331. {
  332.     double left = term(ts);
  333.     Token t = ts.get(ts);
  334.     while (true)
  335.         {
  336.         switch (t.kind)
  337.         {
  338.         case '+':
  339.             left += term(ts);
  340.             t = ts.get(ts);
  341.             break;
  342.         case '-':
  343.             left -= term(ts);
  344.             t = ts.get(ts);
  345.             break;
  346.         default:
  347.             ts.putback(t);
  348.             return left;
  349.         }
  350.     }
  351. }
  352.  
  353. double statement(Token_stream& ts)
  354. {
  355.     Token t = ts.get(ts);
  356.     switch (t.kind)
  357.     {
  358.     case let:
  359.         return declaration(ts);
  360.     default:
  361.         ts.putback(t);
  362.         return expression(ts);
  363.     }
  364. }
  365.  
  366. double term(Token_stream& ts)
  367. {
  368.     double left = primary(ts);
  369.     Token t = ts.get(ts);
  370.     while (true)
  371.     {
  372.         switch (t.kind)
  373.         {
  374.         case 'p':
  375.             {
  376.                 double power = primary(ts);
  377.                 left = pow(left, power);
  378.                 t = ts.get(ts);
  379.                 break;
  380.             }
  381.         case '!':
  382.             {
  383.                 for (int i = left - 1; i > 1; i--)
  384.                 {
  385.                     left *= i;
  386.                 }
  387.                 t = ts.get(ts);
  388.                 break;
  389.             }
  390.         case 's':
  391.             {
  392.                 left = sqrt(left);
  393.                 t = ts.get(ts);
  394.                 break;
  395.             }
  396.         case '*':
  397.             left *= primary(ts);
  398.             t = ts.get(ts);
  399.             break;
  400.         case '/':
  401.             {
  402.                 double d = primary(ts);
  403.                 if (d == 0)
  404.                 {
  405.                     error("divide by 0");
  406.                 }
  407.                 left /= d;
  408.                 t = ts.get(ts);
  409.                 break;
  410.             }
  411.         case '%':
  412.             {
  413.                 double d = primary(ts);
  414.                 if (d == 0)
  415.                 {
  416.                     error("division by 0");
  417.                 }
  418.                 left = fmod(left, d);
  419.                 t = ts.get(ts);
  420.                 break;
  421.             }
  422.         default:
  423.             ts.putback(t);
  424.             return left;
  425.         }
  426.     }
  427. }
  428.  
  429. vector<Variable> var_table;
  430.  
  431. double get_value(const string& s)
  432.     // return the value of a Variable named s
  433. {
  434.     for (const Variable& v : var_table)
  435.     {
  436.         if (v.name == s)
  437.         {
  438.             return v.value;
  439.         }
  440.     }
  441.     error("get: undefined variable ", s);
  442. }
  443.  
  444. void set_value(const string& s, double d)
  445.     // set the Variable named s to d
  446.     // (change the value of Variable s to d)
  447. {
  448.     for (Variable& v : var_table)
  449.     {
  450.         if (v.name == s)
  451.         {
  452.             v.value = d;
  453.             return;
  454.         }
  455.     }
  456.     error("set: undefined variable ", s);
  457. }
  458.  
  459. double declaration(Token_stream& ts)
  460.     // assume we have seen "let"
  461.     // handle: name = expression
  462.       // declare a variable called "name" with the initial value "expression"
  463. {
  464.     Token t = ts.get(ts);
  465.     if (t.kind != name)
  466.     {
  467.         error("name expected in declaration");
  468.     }
  469.     string var_name = t.name;
  470.     Token t2 = ts.get(ts);
  471.     if (t2.kind != '=')
  472.     {
  473.         error("= missing in declaration of ", var_name);
  474.     }
  475.     double d = expression(ts);
  476.     define_name(var_name, d);
  477.     return d;
  478. }
  479.  
  480. bool is_declared(const string& var)
  481.     // is var already in var_table?
  482. {
  483.     for (const Variable& v : var_table)
  484.     {
  485.         if (v.name == var)
  486.         {
  487.             return true;
  488.         }
  489.     }
  490.     return false;
  491. }
  492.  
  493. double define_name(const string& var, double val)
  494.     // add (var, val) to var_table
  495. {
  496.     if (is_declared(var))
  497.     {
  498.         error(var, " declared twice");
  499.     }
  500.     var_table.push_back(Variable(var, val));
  501.     return val;
  502. }
Advertisement
Add Comment
Please, Sign In to add comment