Ejemplo n.º 1
0
        /// <summary>
        /// Parses operator
        /// </summary>
        /// <param name="input">Input character</param>
        /// <param name="precedingItem">Preceding item type</param>
        /// <param name="postfixStack">Postfix stack</param>
        /// <param name="operatorsStack">Operators stack</param>
        /// <returns>Returns true if successful; false, otherwise</returns>
        private bool ParseOperator(char input, ref PrecedingItem precedingItem, Stack <PostfixItem> postfixStack, Stack <PostfixItem> operatorsStack)
        {
            string name = char.ToString(input);

            OperatorCallbacks.OperatorFunction function = ResolveOperator(name);
            if (function != null)
            {
                if (precedingItem == PrecedingItem.Operator || precedingItem == PrecedingItem.OperatorUnary ||
                    precedingItem == PrecedingItem.ParenthesesStart)
                {
                    return(false);
                }

                while (operatorsStack.Count > 0)
                {
                    PostfixItem current = operatorsStack.Peek();

                    if (current is InternalCommandBlock)
                    {
                        break;
                    }

                    Operator op;
                    if ((op = current as Operator) != null && IsHigherPrecedence(op.Name, name))
                    {
                        break;
                    }

                    OperatorUnary opu;
                    if ((opu = current as OperatorUnary) != null && IsHigherPrecedence(opu.Name, name))
                    {
                        break;
                    }

                    operatorsStack.Pop();
                    postfixStack.Push(current);
                }

                operatorsStack.Push(new Operator {
                    Name     = name,
                    Function = function
                });

                precedingItem = PrecedingItem.Operator;
                return(true);
            }

            return(false);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Parse infix representation to postfix representation
        /// </summary>
        /// <param name="input">Infix representation of arithmetic expression</param>
        private unsafe void ParseToPostfix(string input)
        {
            variableName = null;

            Stack <PostfixItem> postfixStack   = new Stack <PostfixItem>();
            Stack <PostfixItem> operatorsStack = new Stack <PostfixItem>();

            int           level     = 0;
            PrecedingItem preceding = PrecedingItem.ParenthesesStart;

            int length = input.Length;

            fixed(char *ptr = input)
            {
                for (int i = 0; i < length; i++)
                {
                    if (char.IsDigit(ptr[i]) || ptr[i] == '.' ||
                        ((preceding == PrecedingItem.Operator || preceding == PrecedingItem.ParenthesesStart) && (ptr[i] == '-' || ptr[i] == '+')))
                    {
                        // Number
                        if (preceding == PrecedingItem.Number || preceding == PrecedingItem.OperatorUnary || preceding == PrecedingItem.ParenthesesEnd)
                        {
                            throw new SyntaxException(input, i, SyntaxException.Type.Unknown);
                        }

                        double number = ExtractNumber(ptr, length, ref i);
                        if (double.IsNaN(number))
                        {
                            throw new SyntaxException(input, i, SyntaxException.Type.InvalidNumber);
                        }

                        postfixStack.Push(new Constant {
                            Value = number
                        });

                        preceding = PrecedingItem.Number;
                    }
                    else if (char.IsLetter(ptr[i]))
                    {
                        // Function/constant/variable
                        string name = ExtractName(ptr, length, ref i);
                        OperatorCallbacks.OperatorUnaryFunction function = ResolveOperatorUnary(name);
                        if (function != null)
                        {
                            if (preceding == PrecedingItem.OperatorUnary || preceding == PrecedingItem.ParenthesesEnd)
                            {
                                throw new SyntaxException(input, i, SyntaxException.Type.Unknown);
                            }

                            // Insert multiply between number and function
                            if (preceding == PrecedingItem.Number)
                            {
                                ParseOperator('*', ref preceding, postfixStack, operatorsStack);
                            }

                            operatorsStack.Push(new OperatorUnary {
                                Name     = name,
                                Function = function
                            });

                            preceding = PrecedingItem.OperatorUnary;
                        }
                        else
                        {
                            if (preceding == PrecedingItem.OperatorUnary || preceding == PrecedingItem.ParenthesesEnd)
                            {
                                throw new SyntaxException(input, i, SyntaxException.Type.Unknown);
                            }

                            // Insert multiply between number and constant/variable
                            if (preceding == PrecedingItem.Number)
                            {
                                ParseOperator('*', ref preceding, postfixStack, operatorsStack);
                            }

                            if (name == "e" || name == "E")
                            {
                                postfixStack.Push(new Constant {
                                    Value = callbacks.E
                                });
                            }
                            else if (name == "pi" || name == "PI")
                            {
                                postfixStack.Push(new Constant {
                                    Value = callbacks.PI
                                });
                            }
                            else
                            {
                                if (variableName != null && variableName != name)
                                {
                                    throw new SyntaxException(input, i - name.Length + 1, SyntaxException.Type.DistinctVariableCountExceeded);
                                }

                                postfixStack.Push(new Variable());

                                variableName = name;
                            }

                            preceding = PrecedingItem.Number;
                        }
                    }
                    else if (ptr[i] == '(')
                    {
                        // Open parenthesis
                        if (preceding == PrecedingItem.Number || preceding == PrecedingItem.ParenthesesEnd)
                        {
                            throw new SyntaxException(input, i, SyntaxException.Type.Unknown);
                        }

                        operatorsStack.Push(new InternalCommandBlock {
                            Value = "("
                        });

                        preceding = PrecedingItem.ParenthesesStart;
                        level++;
                    }
                    else if (ptr[i] == ')')
                    {
                        // Close parenthesis
                        if (preceding == PrecedingItem.Operator || preceding == PrecedingItem.OperatorUnary ||
                            preceding == PrecedingItem.ParenthesesStart)
                        {
                            throw new SyntaxException(input, i, SyntaxException.Type.Unknown);
                        }

                        while (operatorsStack.Count > 0)
                        {
                            InternalCommandBlock commandBlock = operatorsStack.Peek() as InternalCommandBlock;
                            if (commandBlock != null && commandBlock.Value == "(")
                            {
                                break;
                            }

                            PostfixItem item = operatorsStack.Pop();
                            postfixStack.Push(item);
                        }

                        if (operatorsStack.Count == 0)
                        {
                            throw new SyntaxException(input, i, SyntaxException.Type.ParenthesesCountMismatch);
                        }

                        operatorsStack.Pop();

                        preceding = PrecedingItem.ParenthesesEnd;
                        level--;
                    }
                    else if (ptr[i] == '#')
                    {
                        // Comment
                        break;
                    }
                    else if (ptr[i] != ' ')
                    {
                        // Operator
                        if (!ParseOperator(ptr[i], ref preceding, postfixStack, operatorsStack))
                        {
                            throw new SyntaxException(input, i, SyntaxException.Type.Unknown);
                        }
                    }
                }
            }

            // Check proper ending of arithmetic expression
            if (level > 0)
            {
                throw new SyntaxException(input, input.Length - 1, SyntaxException.Type.ParenthesesCountMismatch);
            }
            if (preceding == PrecedingItem.Operator || preceding == PrecedingItem.OperatorUnary || preceding == PrecedingItem.ParenthesesStart)
            {
                throw new SyntaxException(input, input.Length - 1, SyntaxException.Type.Unknown);
            }

            // Empty "operators" stack
            while (operatorsStack.Count > 0)
            {
                PostfixItem item = operatorsStack.Pop();
                postfixStack.Push(item);
            }

            postfix = postfixStack.ToArray();
        }