Una forma de evaluar una expresión es con un analizador de descenso recursivo. http://en.wikipedia.org/wiki/Recursive_descent_parser
Así es una gramática ejemplo en forma de BNF: http://en.wikipedia.org/wiki/Backus-Naur_form
Expr ::= Term ('+' Term | '-' Term)*
Term ::= Factor ('*' Factor | '/' Factor)*
Factor ::= ['-'] (Number | '(' Expr ')')
Number ::= Digit+
aquí * significa que el elemento precedente se repite cero o más veces, + significa una o más repeticiones, corchetes medio opcional.
La gramática garantiza que los elementos de mayor precedencia se recopilan juntos primero o, en este caso, se evalúan primero. Al visitar cada nodo en la gramática, en lugar de crear un árbol de sintaxis abstracto, evalúa el nodo actual y devuelve el valor.
Ejemplo de código (no es perfecto, pero debe darle una idea de cómo asignar BNF de código):
def parse_expr():
term = parse_term()
while 1:
if match('+'):
term = term + parse_term()
elif match('-'):
term = term - parse_term()
else: return term
def parse_term():
factor = parse_factor()
while 1:
if match('*'):
factor = factor * parse_factor()
elif match('/'):
factor = factor/parse_factor()
else: return factor
def parse_factor():
if match('-'):
negate = -1
else: negate = 1
if peek_digit():
return negate * parse_number()
if match('('):
expr = parse_expr()
if not match(')'): error...
return negate * expr
error...
def parse_number():
num = 0
while peek_digit():
num = num * 10 + read_digit()
return num
para mostrar cómo el ejemplo de 1 + 2 * 10 - 2
evaluaría:
call parse_expr stream is 1 + 2 * 10 - 2
call parse term
call parse factor
call parse number which returns 1 stream is now + 2 * 10 - 2
match '+' stream is now 2 * 10 - 2
call parse factor
call parse number which returns 2 stream is now * 10 - 2
match '*' stream is now 10 - 2
call parse number which returns 10 stream is now - 2
computes 2 * 10, return 20
compute 1 + 20 -> 21
match '-' stream is now 2
call parse factor
call parse number which returns 2 stream is empty
compute 21 - 2, return 19
return 19
Hay muchas maneras de evaluarlo. Aquí hay uno: http://en.wikipedia.org/wiki/Shunting-yard_algorithm –
¿Algún idioma que prefiera? Aquí hay un ejemplo en .Net usando Irony.net. http://blog.miraclespain.com/archive/2009/Oct-07.html – gjvdkamp