private FactoryResult TryGetFunction(string equationString, IEquationMember previousMember) { FactoryResult result = RegularExpressionParser( Function.RegularExpression, equationString, (x) => new Function(x)); return(result); }
/* * https://en.wikipedia.org/wiki/Shunting-yard_algorithm * http://wcipeg.com/wiki/Shunting_yard_algorithm#Unary_operators * http://tutplusplus.blogspot.com/2011/12/c-tutorial-arithmetic-expression.html * http://tutplusplus.blogspot.com/2010/12/c-tutorial-equation-calculator.html */ /// <summary> /// Using Shunting yard algorithm /// </summary> /// <param name="equationString"></param> /// <param name="varFinder"></param> /// <returns></returns> private Queue <IEquationMember> CreateReversePolishNotationQueue(string equationString, IList <string> parameterNames) { if (string.IsNullOrEmpty(equationString)) { throw new ArgumentNullException(nameof(equationString)); } Stack <IPrecedenceMember> precedenceStack = new Stack <IPrecedenceMember>(); Stack <Function> functionStack = new Stack <Function>(); Queue <IEquationMember> outputQueue = new Queue <IEquationMember>(); IEquationMember previousToken = null; int totalNumbers = 0; int totalBinaryOpts = 0; while (equationString.Length > 0 && !string.IsNullOrWhiteSpace(equationString)) { int startingLength = equationString.Length; FactoryResult result = EquationMemberFactory.CreateEquationMember(equationString, previousToken, parameterNames); previousToken = result?.Member; equationString = result?.RemainingString; if (previousToken is Number || previousToken is Variable) { totalNumbers++; } if (previousToken is BinaryOperator) { totalBinaryOpts++; } previousToken = HandleToken(precedenceStack, functionStack, outputQueue, previousToken); // if we didn't do anything in a loop, then there are unsupported strings if (equationString == null || startingLength == equationString.Length) { throw new ArgumentException(); } } if (totalNumbers != totalBinaryOpts + 1 && totalBinaryOpts > 0) { throw new ArgumentException("Binary Operators must have at 2 numbers to interact with"); } while (precedenceStack.Count > 0) { if (precedenceStack.Peek() is Bracket) { throw new ArgumentException(); } outputQueue.Enqueue(precedenceStack.Pop()); } EquationArguments = (IReadOnlyList <string>)parameterNames; return(outputQueue); }
private FactoryResult TryToExtractVariable(string equationString, IEquationMember previousMember, IList <string> parameterNames) { return(RegularExpressionParser( Variable.RegularExpression, Variable.ReplaceRegularExpression, equationString, (x) => { if (!parameterNames.Contains(x)) { parameterNames.Add(x); parameterNames.OrderBy(name => name); } return new Variable(parameterNames.IndexOf(x)); })); }
private FactoryResult TryToExtractANumber(string equationString, IEquationMember previousMember) { FactoryResult result = RegularExpressionParser( Number.RegularExpression, equationString, (x) => new Number(double.Parse(x))); if (result != null) { return(result); } return(RegularExpressionParser( @"^\s*PI", equationString, (x) => new Number(Math.PI))); }
/// <summary> /// /// </summary> /// <param name="charArr">Changes only if a this method returns true</param> /// <param name="previousMember"></param> /// <param name="opt">null if BinaryOperator cannot be made</param> /// <returns>True if object can be created</returns> private FactoryResult TryGetBinaryOperator(string equationString, IEquationMember previousMember) { if (BinaryOperatorHasValidPreviousOperator(previousMember)) { foreach (IOperatorMember obj in BinaryOperator.AllOperators) { FactoryResult result = RegularExpressionParser( obj.RegularExpression, equationString, (x) => obj); if (result != null) { return(result); } } } return(null); }
internal FactoryResult CreateEquationMember( string equationString, IEquationMember previousMember, IList <string> parameterNames) { FactoryResult result = null; string refinedEquation = new Regex(@"\s").Replace(equationString, ""); foreach (var fun in GetParsers(parameterNames)) { result = fun(refinedEquation, previousMember); if (result != null) { break; } } return(result); }
private IEquationMember HandleToken( Stack <IPrecedenceMember> precedenceStack, Stack <Function> functionStack, Queue <IEquationMember> outputQueue, IEquationMember previousToken) { if (previousToken is Number num) { outputQueue.Enqueue(num); } else if (previousToken is Variable mVar) { outputQueue.Enqueue(mVar); } else if (previousToken is Function fun) { precedenceStack.Push(fun); functionStack.Push(fun); } else if (previousToken is IOperatorMember opt) { while (TopOfStackHasHigherPriorityOperator(precedenceStack, opt)) { outputQueue.Enqueue(precedenceStack.Pop()); } precedenceStack.Push(opt); } else if (previousToken is Bracket bracket) { BracketHelper(precedenceStack, outputQueue, functionStack, bracket); } else if (previousToken is FunctionArgumentSeparator funSep) { if (functionStack.Count() < 1) { throw new ArgumentException(); } functionStack.Peek().TotalParameters++; previousToken = null; } return(previousToken); }
public double Evaluate(params double[] args) { Stack <double> numStack = new Stack <double>(); Queue <IEquationMember> newQueue = new Queue <IEquationMember>(); while (ReversePolishNotationQueue.Count > 0) { IEquationMember curMember = ReversePolishNotationQueue.Dequeue(); newQueue.Enqueue(curMember); if (curMember is IOperatorMember opt) { numStack.Push(opt.Evaluate(numStack)); } else if (curMember is Number num) { numStack.Push(num.Value); } else if (curMember is Variable variable) { if (args == null || variable.Index > args.Length - 1) { throw new ArgumentException($"This equation requires at least {variable.Index + 1} arguments"); } numStack.Push(args[variable.Index]); } else { throw new NotImplementedException(); } } if (numStack.Count != 1) { throw new ArgumentException(); } ReversePolishNotationQueue = newQueue; return(numStack.Peek()); }
/// <summary> /// true if the previous is valid for a unary operator /// </summary> /// <param name="previousMember"></param> /// <returns></returns> private bool UnaryOperatorHasValidPreviousOperator(IEquationMember previousMember) { return(!BinaryOperatorHasValidPreviousOperator(previousMember)); }
/// <summary> /// true if the previous is valid for a binary operator /// </summary> /// <param name="previousToken"></param> /// <returns></returns> private bool BinaryOperatorHasValidPreviousOperator(IEquationMember previousMember) { return(previousMember != null && (!(previousMember is IOperatorMember) || previousMember.Equals(Bracket.RightBracket))); }