OK. Scratch that attempt - it's not really any improvement. Let's go back to your first listing.
My suggestion is to re-think your implementations of express() and term() so that you don't expect to successfully call term() and primary() more than once. The reason is that if, for example, express() is called with the input buffer containing a term and a minus then the first test, for term and a plus, would fail even though term() was successful and incremented the index. Then next check, for term and a minus, which you would expect to succeed will fail as well. This time because term() now won't match the character at the new index position (because it's now a minus).
Instead of thinking of an expression as three alternatives (either a term followed by a plus or a term followed by a minus or a term on its own) which leads to checking for a term three times, try thinking sequentially: Have I got a term? If not, I haven't got an expression. If so, have I got a plus or a minus? If not, I have got an expression. If so, have I got an expression?... and so on.