Это просто работает. Однако это не проще, чем yacc / bison.
%?-eval('11*(7+5-2)^2*(11+8)').
eval(A) :- lex(A,L), evallist(L).
%?-evallist([11,*,'(',7,+,5,-,2,')',^,2,*,'(',11,+,8,')']).
evallist(L) :- e(R,L,[]),write(R),!.
e(N) --> t(N1), erest(N1,N).
erest(N1,N) --> [+], !, t(N2), {N3 is N1+N2}, erest(N3,N);
[-], !, t(N2), {N3 is N1-N2}, erest(N3,N).
erest(N,N) --> [].
t(N) --> f(N1), trest(N1,N).
trest(N1,N) --> [*], !, f(N2), {N3 is N1*N2}, trest(N3,N);
[/], !, f(N2), {N3 is N1/N2}, trest(N3,N).
trest(N,N) --> [].
f(N) --> n(N);
n(N1), [^], f(N2), {N is N1**N2}.
n(N) --> ['('], !, e(N), [')'];
[-], !, e(N1), {N is -N1};
num(N).
num(N) --> [N], {number(N)}.
lex(A,NL) :-
atom_chars(A,L), lex0(_,L,NL).
lex0(S,L,NL) :-
L=[], (number(S), NL=[S], !; NL=[]), !;
L=[E|R], (d(E,N), (number(S), !; S=0), S1 is S*10+N, lex0(S1, R, NL), !;
lex0(_,R,NR), (number(S), NL=[S|[E|NR]], !;
NL=[E|NR])).
d(I,N) :-
char_code(I,C), C > 47, C < 58, N is C - 48.