It is probably easiest ot first replace all occurences of x by the user supplied value.
Then check input string $s to see if it is an expression -> split up into operator, left hand side (LHS) and RHS (if it is not a unary operator, such as sin()). Recurse on LHS, recurse ON RHS. return operator(LHS, RHS) such as pow(LHS, RHS) or plus(LHS, RHS).
If it is not an expression, it is numeric: return $s.
But if you wish to be able to calculate several points in a row, it will be more efficient to tokenize the input string and restructure it into something like a stack based calculator, leaving the Xs intact. Then as you run through the calculation stack, replace any occurence of X with it's current input value. That is, the above expression would yield an array along the likes of
x
2
^
x
sin
+
So, when you encounter X, you replace by 3. Each time you encoutner an operator, you call it with the previously encountered value if it's a unary operator, or values if it is a binary operator. This way you can reuse the same calculator stack by running through it once per supplied value of x.
It can even be used to "solve the function" (crudely), by starting at some X, solve for said X, then loop by incrementing X by some small value and run until some end value. I say crudely, since this would not be able to figure out in what points and/or ranges the expression is defined, which means that you yourself would have to take care to only supply input ranges and values for which it is defined.