|
|
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;
}
|