static double SolveRPN(List <MathToken> RPN) //pushes numbers onto the stack, resolves functions and operators with those numbers, pushes the result back on, and so forth, { // until there's (hopefully) one number and no operators left Stack <double> operands = new Stack <double>(); foreach (MathToken t in RPN) { if (t.GetType() == typeof(OperatorToken)) { OperatorToken o = (OperatorToken)t; if (operands.Count >= 2) //binary operators need at least 2 numbers { double b = operands.Pop(); double a = operands.Pop(); double result = o.Operator(a, b); operands.Push(result); } else { throw new SyntaxException("Not enough operands"); } } else if (t.GetType() == typeof(NumberToken)) { NumberToken n = (NumberToken)t; operands.Push(n.NumberValue); } else if (t.GetType() == typeof(FunctionToken)) { FunctionToken f = (FunctionToken)t; if (operands.Count >= 1) //this only rules out an empty stack { double a = operands.Pop(); double result = f.Function(a); operands.Push(result); } else { throw new SyntaxException("Not enough operands"); } } } if (operands.Count > 1) //if we're left with more than one number and no operators { throw new SyntaxException("Not enough operators"); } else { return(operands.Pop()); } }
static List <MathToken> ShuntingYard(List <MathToken> calc) //algorithm by Edsger Dijkstra to turn (possibly) ambiguous infix notation into (much easier to parse) reverse Polish notation { List <MathToken> output = new List <MathToken>(); Stack <MathToken> stack = new Stack <MathToken>(); foreach (MathToken t in calc) { if (t.GetType() == typeof(NumberToken)) { output.Add(t); } else if (t.GetType() == typeof(FunctionToken)) { stack.Push(t); } else if (t.GetType() == typeof(OperatorToken)) { while (stack.Count > 0) { if (stack.Peek().GetType() == typeof(FunctionToken)) { output.Add(stack.Pop()); } else if (stack.Peek().GetType() == typeof(OperatorToken)) { OperatorToken stackoper = (OperatorToken)stack.Peek(); OperatorToken inputoper = (OperatorToken)t; if (stackoper.Precedence >= inputoper.Precedence) { output.Add(stack.Pop()); } else { break; } } else { break; } } stack.Push(t); } else if (t.GetType() == typeof(BracketToken)) { BracketToken b = (BracketToken)t; if (b.IsLeft) { stack.Push(t); } else { try { while (true) { if (stack.Peek().GetType() == typeof(BracketToken)) { BracketToken bracket = (BracketToken)stack.Peek(); if (bracket.IsLeft) { stack.Pop(); break; } } output.Add(stack.Pop()); } } catch (InvalidOperationException) //if it runs out of stack without finding an opening bracket { throw new SyntaxException("Mismatched parentheses"); } } } else //this should probably go, since every type of token is accounted for { throw new SyntaxException("Something went horribly wrong"); } } while (stack.Count > 0) //when all input is read, move the stack to the output { MathToken t = stack.Pop(); if (t.GetType() == typeof(BracketToken)) //if it finds an opening bracket that was never closed { BracketToken b = (BracketToken)t; if (b.IsLeft) { throw new SyntaxException("Mismatched parentheses"); } } else { output.Add(t); } } if (output.Count == 0) //it looks like acceptable input, but once you take the brackets out, you're left with nothing { throw new SyntaxException("Nothing but parentheses?"); } return(output); }