/// <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); }
/// <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(); }