public Expression(string inputExpression) { InputExpression = inputExpression.Trim(); try { ExpressionList = ExpressionManipulation.GetExpressionInListForm(inputExpression); IsValid = IsExpressionValid(); } catch (Exception) { IsValid = false; } }
/** <summary>If the expression is valid, the method solves the expression. Otherwise, it will return null * if the method is called and the validity of the expression is false, it will return null </summary> * * <remarks>The method turns the expression (which is in infix notation) into its postfix expression using the * <see cref="ExpressionManipulation.InfixToPostfix(string[])"/> function, then solves the expression using * a postfix expression solving algorithm described * <a href="https://runestone.academy/runestone/books/published/pythonds/BasicDS/InfixPrefixandPostfixExpressions.html">here</a>. * </remarks>. */ // ReSharper disable once CognitiveComplexity public double?Solve() { if (!IsValid) { AnsiConsole.MarkupLine("[red]Cannot solve expression as it is invalid![/]"); return(null); } //If the expression is a lone number, output it back if (CheckMethods.IsANumber(InputExpression)) { var value = double.Parse(InputExpression); Variables.SetAns(value.ToString()); return(value); } //If the expression is a lone variable, output its value back if (CheckMethods.IsAVariable(InputExpression) && ExpressionList.Count == 1) { var value = Variables.GetValue(InputExpression); if (value is not null) { Variables.SetAns(value.ToString()); return(value); } AnsiConsole.MarkupLine($"[red]The variable \"{InputExpression}\" is not initialized![/]"); return(null); } //Creates a copy of the list int o a string array var tempExpressionList = new string[ExpressionList.Count]; for (var i = 0; i < ExpressionList.Count; i++) { tempExpressionList[i] = ExpressionList[i]; } //substitutes the values of the variables in the expression. At this point, ALL variables are defined (checked). //A copy is used so the expression can mamintain its variables, so the value of a variable can change if the //vaues in its variables (if it has any) change. for (var i = 0; i < tempExpressionList.Length; i++) { if (CheckMethods.IsAFunction(tempExpressionList[i])) { continue; } if (!CheckMethods.IsAVariable(tempExpressionList[i])) { continue; } tempExpressionList[i] = Variables.GetValue(tempExpressionList[i]).ToString(); } var postfixExpression = ExpressionManipulation.InfixToPostfix(tempExpressionList); Stack <double> operandStack = new Stack <double>(); foreach (var token in postfixExpression) { if (CheckMethods.IsANumber(token)) { operandStack.Push(double.Parse(token)); continue; } //if it is a trigonometric function, it only needs the top of the stack. So it pops, calculates, then //pushes again. if (CheckMethods.IsAFunction(token)) { operandStack.Push(Computation.Compute(operandStack.Pop(), token)); continue; } //if its not a number, it is an operator var number2 = operandStack.Pop(); var number1 = operandStack.Pop(); operandStack.Push(Computation.Compute(number1, number2, token)); } if (operandStack.Count == 1) { var value = operandStack.Pop(); Variables.SetAns(value.ToString()); //sets the "ans" variable to this value return(value); } AnsiConsole.MarkupLine("[red]Invalid Expression (at Solve)[/]"); return(null); }