#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include <windows.h>
using namespace std;
class Element
//a class to store both numbers and operators
{
private:
double number;
char operat;
public:
//constructor for number
Element(double num)
{
number = num;
operat = '\0';
}
//constructor for operator
Element(char oper)
{
operat = oper;
number = 0;
}
//get value functions
double getNumber()
{
return number;
}
char getOperator()
{
return operat;
}
//set value functions
//do i need them?
//do i add oper = '/0'?
void setNumber(double num)
{
number = num;
}
void setOperator(char oper)
{
operat = oper;
}
};
void errorHandling(int errorCode)
{
switch(errorCode)
{
case 0:
cout<<"Unknown error. Program terminates"<<endl;
break;
case 1:
cout<<"Input contains unsupported symbols. Program terminates"<<endl;
break;
case 2:
cout<<"Missing left bracket"<<endl;
break;
case 3:
cout<<"Missing right bracket"<<endl;
break;
case 4:
cout<<"Can't divide by zero"<<endl;
break;
/**/
}
}
bool checkSupport(string str)
//a function to check for unsupported symbols
{
int strLength = str.length();
int i;
for (i=0; i <= strLength - 1; i++)
{
//if there are only numbers and supported symbols then continue
if(str[i]>='0'&&str[i]<='9')
continue;
else if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'||str[i]=='.'||str[i]=='('||str[i]==')'||str[i]=='=')
continue;
//if not, then there are unsupported symbols
else
return false;
}
return true;
}
vector<Element>::iterator intAsIterator(vector<Element> &expression, int num)
//making the vector iteration easier
{
int i;
vector<Element>::iterator it = expression.begin();
for(i = 1; i <= num; i++)
it++;
return it;
}
double convertToDouble(string str)
{
int strLength = str.length();
int pointP = strLength;
int i;
double convertedNum = 0;
double intPart = 1, fracPart = 0.1;
for(i=0; i <= strLength - 1; i++)
{
if(str[i]=='.')
{
pointP = i;
break;
}
}
for(i = pointP - 1; i>=0; i--)
{
convertedNum += (double)(str[i]-'0') * intPart;
intPart *= 10;
}
for(i = pointP + 1; i <= strLength; i++)
{
convertedNum += (double)(str[i] - '0') * fracPart;
fracPart /= 10;
}
return convertedNum;
}
bool calculate(vector<Element> &expression, int i)
{
double result = 0;
//the calculating part itself
if(expression[i].getOperator()=='+')
result = expression[i-1].getNumber() + expression[i+1].getNumber();
else if (expression[i].getOperator()=='-')
result = expression[i-1].getNumber() - expression[i+1].getNumber();
else if (expression[i].getOperator()=='*')
result = expression[i-1].getNumber() * expression[i+1].getNumber();
else if (expression[i].getOperator()=='/')
result = expression[i-1].getNumber() / expression[i+1].getNumber();
Element tempElem(result);
//cleaning up the mess
expression.erase(intAsIterator(expression, i));
expression.insert(intAsIterator(expression, i), tempElem);
expression.erase(intAsIterator(expression, i+1));
expression.erase(intAsIterator(expression, i-1));
return true;
}
bool determineOperatorPrecedanceAndCalculate(vector<Element> &expression, int leftP, int rightP)
//multiplication and division first, addition and substraction second
{
int i;
//multiplication and division calculation
for(i = leftP; i <= rightP; i++)
{
if(expression[i].getOperator()=='*')
{
calculate(expression, i);
//only a number left instead of two numbers and an operator, changing right position
rightP -= 2;
i--;
}
else if(expression[i].getOperator()=='/')
{
//checking division by zero
if(expression[i+1].getNumber()==0)
{
errorHandling(4);
return false;
}
calculate(expression, i);
//same as above
rightP -= 2;
i--;
}
}
//addition and substraction calculation
for (i = leftP; i <= rightP; i++)
{
if(expression[i].getOperator()=='+'||expression[i].getOperator()=='-')
{
calculate(expression, i);
//same as above
rightP -= 2;
i--;
}
}
return true;
}
bool simplifyAndCalculate(vector<Element> &expression)
//a function to remove parantheses by calculating their contents and simplyfying the total expression
{
int size = expression.size();
int leftP, rightP;
int i, j;
leftP = 0;
rightP = size;
//hunting for parentheses, looking for the first to appear right one
for(i = 0; i<size; i++)
{
if(expression[i].getOperator()==')')
{
rightP = i;
//and then the corresponding left one
for(j = i; j>=-1; j--)
{
if(j==-1)
{
errorHandling(2);
return false;
}
if(expression[j].getOperator()=='(')
{
leftP = j;
break;
}
}
//removing the right brace first
expression.erase(intAsIterator(expression, rightP));
expression.erase(intAsIterator(expression, leftP));
if(!(determineOperatorPrecedanceAndCalculate(expression, leftP, rightP-2)))
return false;
//deleting the calculated fragment
size -= (rightP - leftP);
i = 0;
}
}
//if there is no right brace but a left brace, then error
for(i = 0; i <= size - 1; i++)
{
if(expression[i].getOperator()=='(')
{
errorHandling(3);
return false;
}
}
//no more parentheses from this point
if((size!=1)&&(determineOperatorPrecedanceAndCalculate(expression, 0, size - 1) == false))
return false;
return true;
}
int main()
{
//self-explanatory
SetConsoleTitle(TEXT("My Console Calculator"));
//variables, vector container to store the expression
string inputStr, oneNumberStr;
vector<Element> expression;
int leftP, rightP;
int strLength = inputStr.length();
int i;
double convertedNum;
//welcome text
cout<<"This is a simple console calculator.\nAddition, substraction, multiplication, division, floating point numbers and parentheses are supported.\nType in you expression without spaces or 'exit' to exit:"<<endl;
while(cin>>inputStr)
{
//exit case
if(inputStr=="exit")
return 0;
//unsupported symbol checking
if(checkSupport(inputStr)==false)
{
errorHandling(1);
return 0;
}
//adding an element to the expression
for(i=0; i <= strLength - 1; i++)
{
//adding an operator
if(!((inputStr[i]>='0'&&inputStr[i]<='9')||inputStr[i]=='.'))
{
Element elem(inputStr[i]);
expression.push_back(elem);
continue;
}
//adding a number
if((inputStr[i]>='0'&&inputStr[i]<='9')||inputStr[i]=='.')
{
leftP = i;
i++;
for(;; i++)
{
//if there is an operator to the right of the number then break
if(!((inputStr[i]>='0'&&inputStr[i]<='9')||inputStr[i]=='.'))
{
rightP = i;
i--;
break;
}
//if it's the end of the expression then break
if(i==strLength-1)
{
rightP = strLength;
break;
}
}
oneNumberStr = inputStr.substr(leftP, rightP - leftP);
convertedNum = convertToDouble(oneNumberStr);
Element elem(convertedNum);
expression.push_back(elem);
}
}
vector<Element>::iterator iter = expression.end() - 1;
expression.erase(iter);
//and just a bit more code
if(simplifyAndCalculate(expression)==true)
cout<<"The result is "<<expression[0].getNumber()<<endl;
else
errorHandling(0);
}
return 0;
}