public void ToPostfixExtensionMethodActsIdentically() { // Arrange const string expression = "+26--8"; var operatorA = new OperatorToken { Position = 0, Lexeme = "+", Type = Operator.UnaryPlus }; var operand1 = new OperandToken { Position = 1, Lexeme = "26", Type = Operand.Numeric }; var operatorB = new OperatorToken { Position = 3, Lexeme = "-", Type = Operator.Subtraction }; var operatorC = new OperatorToken { Position = 4, Lexeme = "-", Type = Operator.UnaryMinus }; var operand2 = new OperandToken { Position = 5, Lexeme = "8", Type = Operand.Numeric }; var infix = new List <IToken> { operatorA, operand1, operatorB, operatorC, operand2 }; // Act var postfix1 = shuntingYard.ToPostfix(infix).ToList(); var postfix2 = expression.ToPostfix().ToList(); // Assert Assert.Equal(postfix1.Count, postfix2.Count); for (var i = 0; i < postfix1.Count; i++) { Assert.Equal(postfix1[i].Position, postfix2[i].Position); Assert.Equal(postfix1[i].Lexeme, postfix2[i].Lexeme); } }
static Token EvalBinaryOperators( Token root, Func <Token, BinaryOperatorToken> selector) { while (true) { var binaryOperator = selector(root); if (binaryOperator == null) { return(root.FindRoot()); } if (binaryOperator.Previous == null || binaryOperator.Previous.Type != TokenType.Operand) { throw new EvaluationException(Inv($"Missing left operand for binary operator \"{binaryOperator.Operator.Symbol}\".")); } if (binaryOperator.Next == null || binaryOperator.Next.Type != TokenType.Operand) { throw new EvaluationException(Inv($"Missing right operand for binary operator \"{binaryOperator.Operator.Symbol}\".")); } var leftOperand = binaryOperator.Previous.As <OperandToken>().Value; var rightOperand = binaryOperator.Next.As <OperandToken>().Value; var computed = binaryOperator.Operator.Compute(leftOperand, rightOperand); root = new OperandToken(computed); root.ReplacePrevious(binaryOperator.Previous.Previous); root.ReplaceNext(binaryOperator.Next.Next); } }
public void ToPostfixWithFunctionRequiringTwoParametersConvertsCorrectly() { // Arrange var power = new OperatorToken { Position = 0, Lexeme = "pow", Type = Operator.Function }; var meta1 = new MetaToken { Position = 3, Lexeme = "(", Type = Meta.LeftParenthesis }; var operand1 = new OperandToken { Position = 4, Lexeme = "2", Type = Operand.Numeric }; var meta2 = new MetaToken { Position = 5, Lexeme = ",", Type = Meta.Comma }; var operand2 = new OperandToken { Position = 6, Lexeme = "3", Type = Operand.Numeric }; var meta3 = new MetaToken { Position = 7, Lexeme = ")", Type = Meta.RightParenthesis }; var infix = new List <IToken> { power, meta1, operand1, meta2, operand2, meta3 }; // Act var postfix = shuntingYard.ToPostfix(infix).ToList(); // Assert Assert.Equal(3, postfix.Count); Assert.Same(operand1, postfix[0]); Assert.Same(operand2, postfix[1]); Assert.Same(power, postfix[2]); }
public void ToPostfixWithTwoUnaryOperandsAndBinaryOperandConvertsCorrectly() { // Arrange var operatorA = new OperatorToken { Position = 0, Lexeme = "+", Type = Operator.UnaryPlus }; var operand1 = new OperandToken { Position = 1, Lexeme = "26", Type = Operand.Numeric }; var operatorB = new OperatorToken { Position = 3, Lexeme = "-", Type = Operator.Subtraction }; var operatorC = new OperatorToken { Position = 4, Lexeme = "-", Type = Operator.UnaryMinus }; var operand2 = new OperandToken { Position = 5, Lexeme = "8", Type = Operand.Numeric }; var infix = new List <IToken> { operatorA, operand1, operatorB, operatorC, operand2 }; // Act var postfix = shuntingYard.ToPostfix(infix).ToList(); // Assert Assert.Equal(5, postfix.Count); Assert.Same(operand1, postfix[0]); Assert.Same(operatorA, postfix[1]); Assert.Same(operand2, postfix[2]); Assert.Same(operatorC, postfix[3]); Assert.Same(operatorB, postfix[4]); }
public void ToPostfixWithFunctionAndExpressionParameterConvertsCorrectly() { // Arrange var sinus = new OperatorToken { Position = 0, Lexeme = "sin", Type = Operator.Function }; var meta1 = new MetaToken { Position = 3, Lexeme = "(", Type = Meta.LeftParenthesis }; var operandA = new OperandToken { Position = 4, Lexeme = "8", Type = Operand.Numeric }; var operator1 = new OperatorToken { Position = 5, Lexeme = "+", Type = Operator.Addition }; var operandB = new OperandToken { Position = 6, Lexeme = "56", Type = Operand.Numeric }; var meta2 = new MetaToken { Position = 8, Lexeme = ")", Type = Meta.RightParenthesis }; var infix = new List <IToken> { sinus, meta1, operandA, operator1, operandB, meta2 }; // Act var postfix = shuntingYard.ToPostfix(infix).ToList(); // Assert Assert.Equal(4, postfix.Count); Assert.Same(operandA, postfix[0]); Assert.Same(operandB, postfix[1]); Assert.Same(operator1, postfix[2]); Assert.Same(sinus, postfix[3]); }
static Token EvalParenthesis( Token root) { var openingParenthesis = root.FindLast(TokenType.OpeningParenthesis); while (openingParenthesis != null) { var closingParenthesis = openingParenthesis.Find(TokenType.ClosingParenthesis); if (closingParenthesis == null) { throw new EvaluationException("Missing closing parenthesis."); } var previous = openingParenthesis.TruncatePrevious(); var next = closingParenthesis.TruncateNext(); openingParenthesis = openingParenthesis.TruncateNext(); closingParenthesis = closingParenthesis.TruncatePrevious(); var token = EvalFunctionsAndOperators(openingParenthesis); var value = token.As <OperandToken>().Value; root = new OperandToken(value); root.ReplacePrevious(previous); root.ReplaceNext(next); openingParenthesis = root.Find(TokenType.OpeningParenthesis, true); } return(root.FindRoot()); }
public void ToPostfixWithTwoBinaryOperatorsWithDifferentPrecedence() { var operand1 = new OperandToken { Position = 0, Lexeme = "26", Type = Operand.Numeric }; var operatorA = new OperatorToken { Position = 2, Lexeme = "+", Type = Operator.Addition }; var operand2 = new OperandToken { Position = 3, Lexeme = "4", Type = Operand.Numeric }; var operatorB = new OperatorToken { Position = 4, Lexeme = "*", Type = Operator.Multiplication }; var operand3 = new OperandToken { Position = 5, Lexeme = "8", Type = Operand.Numeric }; var infix = new List <IToken> { operand1, operatorA, operand2, operatorB, operand3 }; // Act var postfix = shuntingYard.ToPostfix(infix).ToList(); // Assert Assert.Equal(5, postfix.Count); Assert.Same(operand1, postfix[0]); Assert.Same(operand2, postfix[1]); Assert.Same(operand3, postfix[2]); Assert.Same(operatorB, postfix[3]); Assert.Same(operatorA, postfix[4]); }
public void ToPostFixWithBinaryOperatorPutsOperatorAtTheEnd() { // Arrange var leftOperand = new OperandToken { Position = 0, Lexeme = "26", Type = Operand.Numeric }; var binaryOperator = new OperatorToken { Position = 2, Lexeme = "*", Type = Operator.Multiplication }; var rightOperand = new OperandToken { Position = 3, Lexeme = "4", Type = Operand.Numeric }; var infix = new List <IToken> { leftOperand, binaryOperator, rightOperand }; // Act var postfix = shuntingYard.ToPostfix(infix).ToList(); // Assert Assert.Equal(3, postfix.Count); Assert.Same(leftOperand, postfix[0]); Assert.Same(rightOperand, postfix[1]); Assert.Same(binaryOperator, postfix[2]); }
private static int loadUnaryOperatorSpecial(ref Stack <OperandToken> operands, List <Token> tokens, int position) { Stack <Token> brackets = new Stack <Token>(); int startingIndexFirstParenthesis = -1; int endingIndexFirstParenthesis = -1; // first token after nary operator must be left parenthesis if (position + 1 >= tokens.Count || tokens[position + 1].TypeProperty != Token.Type.LeftParenthesis) { throw new Exception("First token after nary operator must be a left parenthesis"); } startingIndexFirstParenthesis = position + 1; brackets.Push(leftParenthesisToken.clone()); for (int i = startingIndexFirstParenthesis + 1; i < tokens.Count; i++) { if (IsLeftBracket(tokens[i])) { brackets.Push(tokens[i]); } else if (IsRightBracket(tokens[i])) { if (!AreMatchingBrackets(brackets.Pop(), tokens[i])) { throw new Exception("Mismatched parentheses"); } else { if (brackets.Count == 0) { endingIndexFirstParenthesis = i; break; } } } } if (startingIndexFirstParenthesis == -1 || endingIndexFirstParenthesis == -1) { throw new Exception("Starting or ending values have not been determined"); } //MessageBox.Show(tokens.Count + "\n" + startingIndexFirstParenthesis + " " + endingIndexFirstParenthesis + "\n" + startingIndexSecondParenthesis + " " + endingIndexSecondParenthesis); List <Token> firstOperand = tokens.GetRange(startingIndexFirstParenthesis, endingIndexFirstParenthesis - startingIndexFirstParenthesis + 1); firstOperand = toPolishNotation(firstOperand); firstOperand.Insert(0, tokens[position]); OperandToken ot = new OperandToken(firstOperand); operands.Push(ot); //MessageBox.Show("Ending!"); return(endingIndexFirstParenthesis); }
private static void loadUnaryOperator(ref Stack <OperandToken> operands, ref Stack <Token> operators) { Token t = operators.Pop(); OperandToken otSingle = operands.Pop(); otSingle.Tokens.Insert(0, t); operands.Push(otSingle); }
private int Compare(OperandToken left, OperandToken right) { if (left == null || right == null) { throw new InvalidOperationException("Failed to compare because the specified arguments contain null."); } return(String.Compare(left.Value, right.Value)); }
private static void loadBinaryOperator(ref Stack <OperandToken> operands, ref Stack <Token> operators) { Token t = operators.Pop(); OperandToken otRight = operands.Pop(); OperandToken otLeft = operands.Pop(); otLeft.Tokens.Insert(0, t); otLeft.Tokens.AddRange(otRight.Tokens); operands.Push(otLeft); }
public void ToPostfixCalledWithSingleNumberReturnsThatNumber() { // Arrange var number = new OperandToken { Position = 0, Lexeme = "24", Type = Operand.Numeric }; var infix = new List <IToken> { number }; // Act var postfix = shuntingYard.ToPostfix(infix).ToList(); // Assert Assert.Equal(1, postfix.Count); Assert.Same(number, postfix[0]); }
public void ToPostfixWithTwoNumbersRetursThoseNumbers() { // Arrange var numberA = new OperandToken { Position = 0, Lexeme = "24", Type = Operand.Numeric }; var numberB = new OperandToken { Position = 3, Lexeme = "12", Type = Operand.Numeric }; var infix = new List <IToken> { numberA, numberB }; // Act var postfix = shuntingYard.ToPostfix(infix).ToList(); // Assert Assert.Equal(2, postfix.Count); Assert.Same(numberA, postfix[0]); Assert.Same(numberB, postfix[1]); }
public void ToPostfixWithUnaryOperatorReversesOrder() { // Arrange var unaryOp = new OperatorToken { Position = 0, Lexeme = "-", Type = Operator.UnaryMinus }; var number = new OperandToken { Position = 1, Lexeme = "25", Type = Operand.Numeric }; var infix = new List <IToken> { unaryOp, number }; // Act var postfix = shuntingYard.ToPostfix(infix).ToList(); // Assert Assert.Equal(2, postfix.Count); Assert.Same(number, postfix[0]); Assert.Same(unaryOp, postfix[1]); }
public void ToPostfixWithTwoBinaryOperatorsWithDifferentPrecedenceButCorrectedWithParenthesis() { var lpar = new MetaToken { Position = 0, Lexeme = "(", Type = Meta.LeftParenthesis }; var operand1 = new OperandToken { Position = 1, Lexeme = "26", Type = Operand.Numeric }; var operatorA = new OperatorToken { Position = 3, Lexeme = "+", Type = Operator.Addition }; var operand2 = new OperandToken { Position = 4, Lexeme = "4", Type = Operand.Numeric }; var rpar = new MetaToken { Position = 5, Lexeme = ")", Type = Meta.RightParenthesis }; var operatorB = new OperatorToken { Position = 6, Lexeme = "*", Type = Operator.Multiplication }; var operand3 = new OperandToken { Position = 7, Lexeme = "8", Type = Operand.Numeric }; var infix = new List <IToken> { lpar, operand1, operatorA, operand2, rpar, operatorB, operand3 }; // Act var postfix = shuntingYard.ToPostfix(infix).ToList(); // Assert Assert.Equal(5, postfix.Count); Assert.Same(operand1, postfix[0]); Assert.Same(operand2, postfix[1]); Assert.Same(operatorA, postfix[2]); Assert.Same(operand3, postfix[3]); Assert.Same(operatorB, postfix[4]); }
static Token EvalFunctions( Token root) { while (true) { var function = root.FindFunction(); if (function == null) { return(root.FindRoot()); } if (function.Previous == null || function.Previous.Type != TokenType.Operand) { if (function.Next == null || function.Next.Type != TokenType.Operand) { throw new EvaluationException(Inv($"Missing operand for function \"{function.Function.Symbol}\".")); } var operand = function.Next.As <OperandToken>().Value; var computed = function.Function.Compute(operand); root = new OperandToken(computed); root.ReplacePrevious(function.Previous); root.ReplaceNext(function.Next.Next); } else { if (function.Next == null) { return(function.FindRoot()); } root = function.Next; } } }
public void ToPostfixWithTwoBinaryOperatorsWithNoClosingParenthesisThrowsParserException() { // Arrange var lpar = new MetaToken { Position = 0, Lexeme = "(", Type = Meta.LeftParenthesis }; var operand1 = new OperandToken { Position = 1, Lexeme = "26", Type = Operand.Numeric }; var operatorA = new OperatorToken { Position = 3, Lexeme = "+", Type = Operator.Addition }; var operand2 = new OperandToken { Position = 4, Lexeme = "4", Type = Operand.Numeric }; var operatorB = new OperatorToken { Position = 5, Lexeme = "*", Type = Operator.Multiplication }; var operand3 = new OperandToken { Position = 6, Lexeme = "8", Type = Operand.Numeric }; var infix = new List <IToken> { lpar, operand1, operatorA, operand2, operatorB, operand3 }; // Act and assert try { shuntingYard.ToPostfix(infix); Assert.True(false, "No ParserException was thrown"); } catch (ParserException e) { Console.WriteLine(e.Message); Assert.Equal(e.Position, lpar.Position); Assert.Equal(e.Lexeme, lpar.Lexeme); } }
static Token EvalUnaryOperators( Token root) { while (true) { var unaryOperator = root.FindUnaryOperator(); if (unaryOperator == null) { return(root.FindRoot()); } if (unaryOperator.Previous == null || unaryOperator.Previous.Type != TokenType.Operand) { if (unaryOperator.Next == null || unaryOperator.Next.Type != TokenType.Operand) { throw new EvaluationException(Inv($"Missing operand for unary operator \"{unaryOperator.Operator.Symbol}\".")); } var operand = unaryOperator.Next.As <OperandToken>().Value; var computed = unaryOperator.Operator.Compute(operand); root = new OperandToken(computed); root.ReplacePrevious(unaryOperator.Previous); root.ReplaceNext(unaryOperator.Next.Next); } else { if (unaryOperator.Next == null) { return(unaryOperator.FindRoot()); } root = unaryOperator.Next; } } }
public static List <Token> toPolishNotation(List <Token> tokens) { //MessageBox.Show("Begginging polish"); Stack <OperandToken> operands = new Stack <OperandToken>(); Stack <Token> operators = new Stack <Token>(); try { for (int i = 0; i < tokens.Count; i++) { Token t = tokens[i]; int opsInBrackets = IsSpecialNaryOperator(t); if (t.TypeProperty == Token.Type.Symbol || t.TypeProperty == Token.Type.Constant || t.TypeProperty == Token.Type.Literal) { operands.Push(new OperandToken(t)); } else if (opsInBrackets == 1) { i = loadUnaryOperatorSpecial(ref operands, tokens, i); } else if (opsInBrackets == 2) { i = loadBinaryOperatorSpecial(ref operands, tokens, i); } else if (IsLeftBracket(t) || operators.Count == 0 || t.PrecedenceProperty > operators.Peek().PrecedenceProperty) { operators.Push(t); } else if (IsRightBracket(t)) { while (!IsLeftBracket(operators.Peek())) { Token tmpToken = operators.Peek(); if (tmpToken.IsUnary) { loadUnaryOperator(ref operands, ref operators); } else { loadBinaryOperator(ref operands, ref operators); } } OperandToken ot = operands.Pop(); List <Token> temp = new List <Token>(); Token leftBracket = operators.Pop(); if (!AreMatchingBrackets(leftBracket, t)) { throw new Exception("Mistmatched brackets!"); } temp.Add(leftBracket); temp.AddRange(ot.Tokens); temp.Add(t); ot.Tokens = temp; operands.Push(ot); } else if (t.PrecedenceProperty <= operators.Peek().PrecedenceProperty) { while (operators.Count != 0 && t.PrecedenceProperty <= operators.Peek().PrecedenceProperty) { Token tmpToken = operators.Peek(); if (tmpToken.IsUnary) { loadUnaryOperator(ref operands, ref operators); } else { loadBinaryOperator(ref operands, ref operators); } } operators.Push(t); } } while (operators.Count != 0) { Token tmpToken = operators.Peek(); if (tmpToken.IsUnary) { loadUnaryOperator(ref operands, ref operators); } else { loadBinaryOperator(ref operands, ref operators); } } } catch (Exception) { // MessageBox.Show(e.Message); return(null); } // MessageBox.Show("ending polish"); return((operands.Count == 1)?operands.Pop().Tokens:null); }
static TokenSeqToTerm() { SeqStartToken = new OperandToken(TT.BoS); SeqEndToken = new OperandToken(TT.EoS); }