Calculator


Links

I wrote this program as proof of concept to one of my colleagues while at CTI. This program simply takes a string such as "1 + 1", parses it, and returns the result (2 in this case).

Note that it's very simple: it only does addition, subtraction, multiplication and division. In addition, I haven't put any error-checking into it. Perhaps one day when I feel like it I'll build upon it.

/*
calculator.cpp - takes a string and works out what it equals
Copyright (C) 2006 Kieron Thwaites

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/


#include <cstdlib>
#include <iostream>
#include <list>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::string;

// This function splits a string into its different words. We assume
// that words are delimited with a space.

list<string> split(const string& s)
{
   list<string> words;
   string::size_type i = 0;

   while (i != s.size())
   {
      // Ignore leading spaces
      while (i != s.size() && isspace(s[i]))
      {
         i++;
      }

      // Find the end of the next word
      string::size_type j = i;
      while (j != s.size() && !isspace(s[j]))
      {
         j++;
      }

      // If we found a word, take the substring corresponding
      // to the word and add it to the list

      if (i != j)
      {
         words.push_back(s.substr(i, j - i));
         i = j;
      }
   }

   return words;
}

// This function parses the list and simplifies it, eventually finding out
// what the original expression evaluates to

void parse(list<string>& element_list)
{
   typedef list<string>::iterator iter_type;
   iter_type position;
   bool op_found = false;

   // We need to obey BODMAS so, on our first loop, we only look for
   // a multiplication or a division operator

   for (iter_type i = element_list.begin(); i != element_list.end(); i++)
   {
      if ((*i) == "*" || (*i) == "/")
      {
         position = i;
         op_found = true;
         break;
      }
   }

   // Only if we didn't find a multiplication or a division operator,
   // we loop again, this time searching for an addition or
   // subtraction operator

   if (!op_found)
   {
      for (iter_type i = element_list.begin(); i != element_list.end(); i++)
      {
         if ((*i) == "+" || (*i) == "-")
         {
            position = i;
            op_found = true;
            break;
         }
      }
   }

   // If we found an operator...
   if (op_found)
   {
      // Evaluate the operator and the two operands
      // on either side of the operator

      string result;
      iter_type operand1 = --position;
      iter_type operand2 = ++(++position);
      position--; // reset it back
      char buffer [20];
      if ((*position) == "+")
      {
         result = gcvt(atof((*operand1).c_str())
            + atof((*operand2).c_str()), 6, buffer);
      }
      else if ((*position) == "-")
      {
         result = gcvt(atof((*operand1).c_str())
            - atof((*operand2).c_str()), 6, buffer);
      }
      else if ((*position) == "*")
      {
         result = gcvt(atof((*operand1).c_str())
            * atof((*operand2).c_str()), 6, buffer);
      }
      else // can only be a division operator
      {
         result = gcvt(atof((*operand1).c_str())
            / atof((*operand2).c_str()), 6, buffer);
      }

      // Remove the two operands and the operator, and replace
      // with the evaluated number

      position = element_list.erase(operand1, ++operand2);
      element_list.insert(position, result);

      // We now need to parse the list again
      parse(element_list);
   }
}

int main()
{
   // Get the expression
   cout << "Enter an expression: ";
   string expression;
   getline(cin, expression);

   // Split the expression
   list<string> elements = split(expression);

   // Parse the expression
   parse(elements);

   // After parsing, the list will only contain one element which is
   // the solution. Print this element

   list<string>::const_iterator iter = elements.begin();
   cout << "Result: " << (*iter) << endl;

   system("PAUSE");
   return 0;
}