I'm new here and have a generall question. I'm trying to create a recursive descent parser for the evaluation of mathematic expressions, and the parser I have crafted until now also works very good for integers and floategers. But now I am trying to extend it with the evaluation of functions, like 'log', 'ln' or 'cbrt'. My parser is build up of eight function, excluding the function for evaluating. I crafted also one function for scanning the input string. This function will return a list of the expression with the syntax [5.0, '+', ....] if the string is '5+....'. This function works well and here is not the problem I have. My problem is, that the parser raises a 'list index out of range' error and I do not understand why. When I insert an expression without any function to evaluate, the parser delivers the correct abstract syntax tree and my evaluation function calculates the correct value. I found now a way to evaluate expressions with the shape 'function( expr )' (the parser does not throw an error), but when trying something like 'function1( expr1 ) + function2( expr2 )' or 'value + function( expr )', there is always the 'list index out of range error' thrown.
def expect_token( a, i ):
if a[i] is None:
raise SyntaxError( 'Unexpected end of input' )
else:
return a[i]
def atom( a, i, functions, dispatch ):
t = expect_token( a, i )
if isinstance( t, float ):
return i+1, a[i]
elif t == '(':
i, x = expression( a, i+1, functions, dispatch )
if expect_token( a, i ) != ')':
raise SyntaxError( '")" was expected, but it came "{}"'.format( a[i] ) )
return i+1, x
elif t in dispatch.keys():
i, x = expression( a, i+1, functions, dispatch )
return i+1, a[i]
else:
raise SyntaxError( 'Unexpected symbol: "{}"'.format( t ) )
def power( a, i, functions, dispatch ):
i, x = atom( a, i, functions, dispatch )
if a[i] == '^':
i, y = negation( a, i+1, functions, dispatch )
return i, ['^', x, y]
else:
return i, x
def negation( a, i, functions, dispatch ):
if a[i] == '-':
i, x = power( a, i+1, functions, dispatch )
return i, ['~', x]
else:
return power( a, i, functions, dispatch )
def multiplication( a, i, functions, dispatch ):
i, x = negation( a, i, functions, dispatch )
op = a[i]
while op == '*' or op == '/':
i, y = negation( a, i+1, functions, dispatch )
x = [op, x, y]
op = a[i]
return i, x
def addition( a, i, functions, dispatch ):
i, x = multiplication( a, i, functions, dispatch )
op = a[i]
while op == '+' or op == '-':
i, y = multiplication( a, i+1, functions, dispatch )
x = [op, x, y]
op = a[i]
return i, x
def expression( a, i, functions, dispatch ):
if a[i] in functions:
i_, y = expression( a, i+1, functions, dispatch )
x = [a[i], y]
return i_, x
return addition( a, i, functions, dispatch )
def ast( a, functions, dispatch ):
i, t = expression( a, 0, functions, dispatch )
if a[i] is None:
return t
else:
raise SyntaxError( 'End of input expected, but there came "{}"'.format( a[i] ) )
dispatch_ = {'+': lambda x, y: x+y,
'-': lambda x, y: x-y,
'*': lambda x, y: x*y,
'/': lambda x, y: x/y,
'^': lambda x, y: x**y,
'~': lambda x: -x,
'log': lambda x: log( x, 10 ),
'ln': lambda x: log( x ),
'sqrt': lambda x: sqrt( x ),
'cbrt': lambda x: pow( x, 1/3 )
}
functions_ = [ 'log', 'ln', 'sqrt', 'cbrt' ]
´´´
I don't know if it important, but I import log and sqrt from the 'math' libary.
I debugged the program very often and found that the error is caused by the 'atom function', but I do not know how to fix it.
-> cbrt( 8 )+ log( 10 )
> Traceback (most recent call last): File
> "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line
> 150, in <module>
> run() File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line
> 140, in run
> t = ast( a, functions_, dispatch_ ) File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line
> 100, in ast
> i, t = expression( a, 0, functions, dispatch ) File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line
> 94, in expression
> i_, y = expression( a, i+1, functions, dispatch ) File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line
> 97, in expression
> return addition( a, i, functions, dispatch ) File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line
> 87, in addition
> i, y = multiplication( a, i+1, functions, dispatch ) File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line
> 75, in multiplication
> i, x = negation( a, i, functions, dispatch ) File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line
> 72, in negation
> return power( a, i, functions, dispatch ) File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line
> 61, in power
> if a[i] == '^': IndexError: list index out of range
´´´ When trying to evaluate '5+sqrt( 4 )', the same error is thrown.
My question is, where exactly is the bug in the program and how can I fix it. If you want, I will also show you my scanning and evaluating routine. Thank you for your future help.
EDIT:
This is my scanning routine:
def is_sign( sign ):
if sign in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':
return True
return False
def scan( s ):
a = []
i = 0
n = len( s )
while i < n:
if s[i] in '+-*/^()':
a.append( s[i] )
i += 1
elif s[i].isdigit():
j = i
while i < n and ( s[i].isdigit() or s[i] == '.' ):
i += 1
a.append( float( s[j:i] ) )
elif s[i].isspace():
i += 1
elif is_sign( s[i] ):
j = i
while i < n and is_sign( s[i] ):
i += 1
a.append( s[j:i] )
else:
raise SyntaxError( 'Unexpected character: "{}"'.format( s[i] ) )
a.append( None )
return a
# And for evaluation I use this function:
def evaluate( t ):
if isinstance( t, float ):
return t
else:
return dispatch_[t[0]]( *map( evaluate, t[1:] ) )
´´´
Examples:
expr = '3+5*( 5+3-6 )-9'
-> tree = ['-', [ '+', 3.0, ['*', 5.0, ['-', ['+', 5.0, 3.0], 6.0]]], 9.0]
-> sol = 4.0
expr = 'cbrt( 4*3-4 )'
-> tree = ['cbrt', ['-', ['*', 4.0, 3.0], 4.0]]
-> sol = 2.0
expr = '3*log( 4-9 )'
-> error:
Traceback (most recent call last):
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 150, in <module>
run()
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 140, in run
t = ast( a, functions_, dispatch_ )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 100, in ast
i, t = expression( a, 0, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 97, in expression
return addition( a, i, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 84, in addition
i, x = multiplication( a, i, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 78, in multiplication
i, y = negation( a, i+1, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 72, in negation
return power( a, i, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 61, in power
if a[i] == '^':
IndexError: list index out of range
expr = 'sqrt( 4 ) - ln( 2.7 )'
-> error:
Traceback (most recent call last):
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 150, in <module>
run()
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 140, in run
t = ast( a, functions_, dispatch_ )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 100, in ast
i, t = expression( a, 0, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 94, in expression
i_, y = expression( a, i+1, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 97, in expression
return addition( a, i, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 87, in addition
i, y = multiplication( a, i+1, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 75, in multiplication
i, x = negation( a, i, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 72, in negation
return power( a, i, functions, dispatch )
File "F:\Privat\Programms\Python\Projects\Calculator\calc_tools.py", line 61, in power
if a[i] == '^':
IndexError: list index out of range
´´´
I hope this additional information will help you to support me.