This is my basic C# calculator; I'm sure there is much that can be improved. This design is based on Bjarne Stroustrup's C++ calculator, a purposely be-bugged version of which can be found at his website.
enum Operators
{
Addition, Subtraction, Multiplication, Division, Modulo
}
static class ExtensionMethods
{
public static string RemoveAll(this string str, char toRemove)
{
for (int i = 0; i < str.Length; i++)
{
if (str[i] == toRemove)
{
str = str.Remove(i, 1);
i--;
}
}
return str;
}
}
class Calculator
{
private static StreamReader dataStream;
private static Operators getNextOperator()
{
const string OperatorSet = "+-*/%";
char token = (char)dataStream.Read();
if (OperatorSet.IndexOf(token) == -1)
{
throw new InvalidDataException("Invalid or missing operator.");
}
return (Operators)OperatorSet.IndexOf(token);
}
private static double getNextNum()
{
string value = string.Empty;
while (true)
{
if ("0123456789.".IndexOf((char)dataStream.Peek()) == -1)
{
break;
}
value += (char)dataStream.Read();
}
double d;
if (double.TryParse(value, out d))
{
return d;
}
Console.WriteLine(value);
throw new InvalidDataException("Expected a number.");
}
private static double NumbersAndParens()
{
bool valueIsNegative = false;
double val = -1; // trick the compiler
if ((char)dataStream.Peek() == '-')
{
valueIsNegative = true;
dataStream.Read();
}
if ((char)dataStream.Peek() == '(')
{
dataStream.Read();
val = AdditiveOperators();
if ((char)dataStream.Peek() == ')')
{
dataStream.Read();
return valueIsNegative ? -1 * val : val;
}
else
{
throw new InvalidDataException("Expected closing parenthesis.");
}
}
val = getNextNum();
return valueIsNegative ? -1 * val : val;
}
private static double MultiplicativeOperators()
{
double val = NumbersAndParens();
while (true)
{
if ("*/%".IndexOf((char)dataStream.Peek()) == -1)
{
return val;
}
Operators op = getNextOperator();
if (op == Operators.Multiplication)
{
val *= NumbersAndParens();
}
else if (op == Operators.Division)
{
double nextNum = NumbersAndParens();
if (nextNum == 0)
{
throw new DivideByZeroException("Divide by 0 error.");
}
val /= nextNum;
}
else
{
val %= NumbersAndParens();
}
}
}
private static double AdditiveOperators()
{
double val = MultiplicativeOperators();
while (true)
{
if ("-+".IndexOf((char)dataStream.Peek()) == -1)
{
return val;
}
Operators op = getNextOperator();
if (op == Operators.Addition)
{
val += MultiplicativeOperators();
}
else if (op == Operators.Subtraction)
{
val -= MultiplicativeOperators();
}
}
}
private static Stream StringToStream(string equation)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(equation.RemoveAll(' '));
writer.Flush();
stream.Position = 0;
return stream;
}
/// <summary>
///
/// </summary>
/// <param name="equation">A mathematical epxression needing evalation.</param>
/// <returns>The evaluated expression.</returns>
public static double EvaluateExpression(string equation)
{
dataStream = new StreamReader(StringToStream(equation));
double evaluation = AdditiveOperators();
if (!dataStream.EndOfStream)
{
throw new InvalidDataException("Invalid expression.");
}
return evaluation;
}
}