コード例 #1
0
        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);
            }
        }
コード例 #2
0
        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);
            }
        }
コード例 #3
0
        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]);
        }
コード例 #4
0
        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]);
        }
コード例 #5
0
        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]);
        }
コード例 #6
0
        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());
        }
コード例 #7
0
        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]);
        }
コード例 #8
0
        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]);
        }
コード例 #9
0
        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);
        }
コード例 #10
0
        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);
        }
コード例 #11
0
        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));
        }
コード例 #12
0
        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);
        }
コード例 #13
0
        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]);
        }
コード例 #14
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]);
        }
コード例 #15
0
        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]);
        }
コード例 #16
0
        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]);
        }
コード例 #17
0
        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;
                }
            }
        }
コード例 #18
0
        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);
            }
        }
コード例 #19
0
        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;
                }
            }
        }
コード例 #20
0
        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);
        }
コード例 #21
0
 static TokenSeqToTerm()
 {
     SeqStartToken = new OperandToken(TT.BoS);
     SeqEndToken   = new OperandToken(TT.EoS);
 }