public ExpressionEvaluator(string _expression, bool verbose = false) { this._expression = _expression.Replace(" ", ""); // space is just formatting _verbose = verbose; if (_verbose) { Console.WriteLine($"Expression: {_expression}"); } _operands = new Operands(this._expression.Length, _verbose); _operators = new Operators(this._expression.Length, _verbose); }
public double?Evaluate() { if (String.IsNullOrWhiteSpace(_expression)) { Console.WriteLine("expression invalid: empty"); return(null); } bool pushedOperator = true; for (int i = 0; i < _expression.Length; ++i) { string c = _expression[i].ToString(); if (_verbose) { Console.WriteLine($"Evaluate: {c}"); } if ( pushedOperator && Operators.IsPositiveOp(c) && i + 1 < _expression.Length ) // plus unary is not needed, skip to next character { continue; } else if ( pushedOperator && Operators.IsNegativeOp(c) && i + 1 < _expression.Length ) { _operators.ToggleNegation(); } else if ( Operands.IsEulerConst(c) ) { pushedOperator = false; _operands.Push(Math.E); } else if ( Operands.IsPiConst(c) ) { pushedOperator = false; _operands.Push(Math.PI); } else if ( Char.GetNumericValue(c[0]) != -1.0 || c == "." ) // this character represents the beginning of a number { var parsedNum = false; for (var j = _expression.Length - i; j > 0; --j) // try to find the end of the number by starting to parse the rest of the expression as a number, shorten the attempted parsed substring until success { if ( !(parsedNum = double.TryParse(_expression.Substring(i, j), out var num)) ) { continue; } // we found the longest possible number (e.g. 12 instead of 1) i += j - 1; pushedOperator = false; num = _operators.MakeNegative() ? -num : num; _operands.Push(num); break; } if (!parsedNum) { return(null); } } else if ( pushedOperator && Operators.IsOpenParenthesisOp(c) ) // binary expression whose second operand is a sub expression, don't treat as implicit multiplication, unless sub expression is negated { if (_operators.MakeNegative()) { _operands.Push(-1); _operators.Push(Operators.MultiplicationOp()); } pushedOperator = EvaluateUntilOperatorPush(c); if (!pushedOperator) { return(null); } } else if (!pushedOperator) // character is a binary operator { if (Operators.IsOpenParenthesisOp(c)) // treat as implicit multiplication { if (!EvaluateUntilOperatorPush(Operators.MultiplicationOp())) { return(null); } pushedOperator = EvaluateUntilOperatorPush(c); if (!pushedOperator) { return(null); } } else if ( Operators.IsBinaryOp(c) ) { pushedOperator = EvaluateUntilOperatorPush(c); if (!pushedOperator) { return(null); } } else if ( Operators.IsCloseParenthesisOp(c) ) { pushedOperator = false; if (!EvaluateUntilOpenParenthesis()) { return(null); } } else { Console.WriteLine($"character {c} is not a valid binary operator"); return(null); } } else { Console.WriteLine($"character {c} is not a valid operand or valid unary operator"); return(null); } } var done = EvaluateUntilDone(); if (!done) // there was error evaluating the expression { return(null); } while (_operands.CanPerformBinaryOperation()) // reduce operand stack to a single value by implicitly multiplying stack items together { _operands.Push(Multiplication()); } return(_operands.Peek()); }