public static bool InfixToPostfix(Expression inputExpression, out Expression postfixExpression) { List<Token> postfixTokens = new List<Token>(); Stack<Token> postfixStack = new Stack<Token>(); //process all tokens in input-expression, one by one foreach (Token token in inputExpression.Tokens) { if (token.Type == TokenType.Constant) //handle constants { postfixTokens.Add(token); } else if (token.Type == TokenType.Variable) //handle variables { postfixTokens.Add(token); } else if (token.Type == TokenType.Operator) //handle operators { if (CalcUtilities.IsOpenParenthesis(token)) //handle open-parenthesis { postfixStack.Push(token); } else if (CalcUtilities.IsCloseParenthesis(token)) //handle close-parenthesis { //pop all operators off the stack onto the output (until left parenthesis) while (true) { if (postfixStack.Count == 0) { postfixExpression = null; //error: mismatched parenthesis return (false); } Token top = postfixStack.Pop(); if (CalcUtilities.IsOpenParenthesis(top)) break; else postfixTokens.Add(top); } } else //handle arithmetic operators { Operator currentOperator = AllOperators.Find(token.LinearToken); if (postfixStack.Count > 0) { Token top = postfixStack.Peek(); if (CalcUtilities.IsArithmeticOperator(top)) { Operator stackOperator = AllOperators.Find(top.LinearToken); if ((currentOperator.Associativity == OperatorAssociativity.LeftToRight && currentOperator.PrecedenceLevel >= stackOperator.PrecedenceLevel) || (currentOperator.Associativity == OperatorAssociativity.RightToLeft && currentOperator.PrecedenceLevel > stackOperator.PrecedenceLevel)) //'>' operator implies less precedence { postfixStack.Pop(); postfixTokens.Add(top); } } } postfixStack.Push(token); //push operator to stack } } } //after reading all tokens, pop entire stack to output while (postfixStack.Count > 0) { Token top = postfixStack.Pop(); if (CalcUtilities.IsOpenParenthesis(top) || CalcUtilities.IsCloseParenthesis(top)) { postfixExpression = null; //error: mismatched parenthesis return (false); } else { postfixTokens.Add(top); } } postfixExpression = new Expression() { Tokens = postfixTokens }; return (true); }
public static void Validate(Expression expression, ref List<Token> postfixTokens, out bool isError, out int errorTokenIndex, out string errorMessage) { //initialize index of each token int tokenIndex = 0; foreach (Token token in expression.Tokens) { token.Index = tokenIndex; tokenIndex += 1; } Stack<Token> postfixStack = new Stack<Token>(); foreach (Token token in expression.Tokens) { if (token.Type == TokenType.Constant) //handle constants { postfixTokens.Add(token); } else if (token.Type == TokenType.Variable) //handle variables { postfixTokens.Add(token); } else if (token.Type == TokenType.Operator) //handle operators { if (CalcUtilities.IsOpenParenthesis(token)) //handle open-parenthesis { postfixStack.Push(token); } else if (CalcUtilities.IsCloseParenthesis(token)) //handle close-parenthesis { //pop all operators off the stack onto the output (until left parenthesis) while (true) { if (postfixStack.Count == 0) { isError = true; errorTokenIndex = token.Index; errorMessage = "Mismatched parenthesis."; return; } Token top = postfixStack.Pop(); if (CalcUtilities.IsOpenParenthesis(top)) { break; } else { postfixTokens.Add(top); } } } else //handle other operators (usually arithmetic) { Operator operator1 = AllOperators.Find(token.LinearToken); while (true) { if (postfixStack.Count == 0) { break; } Token top = postfixStack.Peek(); if (CalcUtilities.IsArithmeticOperator(top)) { bool readyToPopOperator2 = false; Operator operator2 = AllOperators.Find(top.LinearToken); if (operator1.Associativity == OperatorAssociativity.LeftToRight && operator1.PrecedenceLevel >= operator2.PrecedenceLevel) //'>' operator implies less precedence { readyToPopOperator2 = true; } else if (operator1.Associativity == OperatorAssociativity.RightToLeft && operator1.PrecedenceLevel > operator2.PrecedenceLevel) { readyToPopOperator2 = true; } if (readyToPopOperator2) { postfixStack.Pop(); postfixTokens.Add(top); } else { break; } } else { break; } } postfixStack.Push(token); } } } //pop entire stack to output while (postfixStack.Count > 0) { Token top = postfixStack.Pop(); if (CalcUtilities.IsOpenParenthesis(top) || CalcUtilities.IsCloseParenthesis(top)) { isError = true; errorTokenIndex = top.Index; errorMessage = "Mismatched Parenthesis."; return; } else { postfixTokens.Add(top); } } Stack<Token> evaluateStack = new Stack<Token>(); foreach (Token token in postfixTokens) { if (token.Type == TokenType.Constant) { evaluateStack.Push(token); } else if (token.Type == TokenType.Variable) { evaluateStack.Push(token); } else if (token.Type == TokenType.Operator) { Token top; switch (((Operator)token.TokenObject).OperandCount) { case 1: if (evaluateStack.Count >= 1) { top = evaluateStack.Pop(); //add a dummy constant as result of arithmetic evaluation Token dummyConstantToken = CalcUtilities.CreateNumberConstantToken("1"); evaluateStack.Push(dummyConstantToken); } else { isError = true; errorTokenIndex = token.Index; errorMessage = "Missing Operand for Operator '" + token.LinearToken + "'."; return; } break; case 2: if (evaluateStack.Count >= 2) { Token temp = evaluateStack.Pop(); top = evaluateStack.Pop(); //add a dummy constant as result of arithmetic evaluation Token dummyConstantToken = CalcUtilities.CreateNumberConstantToken("1"); evaluateStack.Push(dummyConstantToken); } else { isError = true; errorTokenIndex = token.Index; errorMessage = "Missing Operand for Operator '" + token.LinearToken + "'."; return; } break; } } } if (evaluateStack.Count == 1) //there should be exactly one token left in evaluate-stack { //leave the last token intact (as we are not evaluating to find the result) isError = false; errorTokenIndex = -1; errorMessage = string.Empty; } else { isError = true; errorTokenIndex = expression.Tokens.Count - 1; errorMessage = "Incomplete Expression."; } }
//checks whether the input expression contains only number-constants and operators. public static bool IsArithmeticExpression(Expression expression) { foreach (Token token in expression.Tokens) { if (!(token.Type == TokenType.Constant || token.Type == TokenType.Operator)) { return (false); } } return (true); }