If you decide to write this from scratch, your algorithm looks good. I'll provide a few of my thoughts.
You may want to move step 5 (replace variables) into step 6 (prefix the expression and calculate it). In other words, instead of just doing a textual find-and-replace for the variables, do it during the calculation whenever need to evaluate a variable. This could open up more possibilities later, possibly making it easier to graph your functions or have variables with values that depend on other variables. Your way should work for the simple case, though.
A possible implementation for the sin
and cos
functions, making it easier to define additional functions in the future, could be having a Dictionary<string, Func<double,double>>
, something like:
private var functions = new Dictionary<string, Func<double,double>>(StringComparer.OrdinalIgnoreCase) { { "sin", Math.Sin }, { "cos", Math.Cos }, { "sec", Secant } };. . . // checking whether a token is a defined function or a variableif (functions.ContainsKey(token)){ // determine the value of the argument to the function double inputValue = getArgument(); double result = functions[token](inputValue); . . .}. . .private static double Secant(double x){ return 1.0 / Math.Cos(x);}