Indeed in the case of simple expression like this, one can use recursive descent or the shunting yard algorithm to evaluate the result.
http://en.wikipedia.org/wiki/Recursive_descent_parser
http://en.wikipedia.org/wiki/Shunting-yard_algorithm
I wonder, since I do not know Python, if the expression is evaluated in the context of the location of the eval's call. I mean, do the variables in such expression get bound to their values in the surrounding scope? If this is the case (and it probably is), IMO language support is necessary.
Another approach is used in Lisp/Scheme that I like very much. The expression to be evaluated is in the form of list, not string. The parsing step of eval can then be omitted from the run-time phase (although the whole language is interpreted). Every element of the list is either identifier (called symbol), or literal constant, or sub-expression, which in turn is again a list. The upside is not only that the parsing is skipped, but also, since this is essentially a data structure, the program can very easily manipulate it programmatically. For example, you can walk the list and substitute certain identifiers with others. The whole program itself is one such list. The only downside is that the parse-less interpreter is not so strong if you need complex syntactical analysis, like the one in languages with static typing. The context for variable binding is either the current one, or is provided by a map between identifiers and associated values (or storage, I forgot). There are different mechanisms for different purposes.
Just felt the urge to say smth.
Regards