It wasn't that bad. You don't have to check for a lot of things a calculator does. Here's the body of the code. I made it static, since you really don't need to instantiate it. If I ever make it into a calculator, I'd probably make it non-static, and make the stack a class-level field.
class PostfixParser
{
const string Placeholder = "[x]";
private static Dictionary<string, Func<double, double, double>> op;
private static List<string> operators = new List<string>() { "+", "-", "*", "/" };
static PostfixParser()
{
op = new Dictionary<string, Func<double, double, double>>();
op.Add("+", (x, y) => x + y);
op.Add("-", (x, y) => x - y);
op.Add("*", (x, y) => x * y);
op.Add("/", (x, y) => x / y);
op.Add("^", (x, y) => Math.Pow(x, y));
}
public static double ParseExp(string exp, double? val)
{
string[] tokens = exp.Split(new string[] { " " } , StringSplitOptions.RemoveEmptyEntries);
if (tokens.Contains(Placeholder) && val == null)
throw new InvalidOperationException("Placeholder token detected in expression, but parameter \"val\" was null.");
Stack<double> stack = new Stack<double>();
foreach (string token in tokens)
{
if (operators.Contains(token))
{
if (stack.Count < 2)
throw new InvalidOperationException("Operator imbalance.");
double y = stack.Pop();
double x = stack.Pop();
stack.Push(op[token](x, y));
}
else
{
double n;
if (token == Placeholder)
n = val.Value;
else if (!double.TryParse(token, out n))
throw new InvalidOperationException("Invalid token detected: " + token);
stack.Push(n);
}
}
if (stack.Count > 1)
throw new InvalidOperationException("More than one result on the stack.");
if (stack.Count < 1)
throw new InvalidOperationException("No results on the stack.");
return stack.Pop();
}
public static double ParseExp(string exp)
{
return ParseExp(exp, null);
}
}This can be used like this:
string fToCExp = "5 9 / [x] 32 - *";
string cToFExp = "9 5 / [x] * 32 + ";
Console.WriteLine("100C converted to F:");
Console.WriteLine(PostfixParser.ParseExp(cToFExp, 100));
Console.WriteLine("32F converted to C:");
Console.WriteLine(PostfixParser.ParseExp(fToCExp, 32));
Console.ReadKey();To give an output of:
100C converted to F: 212 32F converted to C: 0
You could add more operators if you wished, like a 1/x or a SQRT, but since most other operators are unary rather than binary, you'd have to change your popping logic.
Note: I did it with a placeholder value in mind. I used "[x]" for whatever reason, but it could be anything that won't parse into a double by itself or match one of the operators. You could remove this altogether, if you cared to.
No comments:
Post a Comment
Speak your mind.