Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302
Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302
**Evaluating Mathematical Expressions** ===================================== We will implement a recursive descent parser to evaluate the given mathematical expressions. The parser will use a top-down approach to parse the input string and evaluate the expression. **Code** --------
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | import math def evaluate(str): """ Evaluates a mathematical expression. Args: str (str): The mathematical expression to evaluate. Returns: float: The result of the evaluation. """ pos = 0 def parse_expression(): nonlocal pos result = parse_term() while pos < len(str) and str[pos] in '+-': if str[pos] == '+': pos += 1 result += parse_term() elif str[pos] == '-': pos += 1 result -= parse_term() return result def parse_term(): nonlocal pos result = parse_factor() while pos < len(str) and str[pos] in '*/': if str[pos] == '*': pos += 1 result *= parse_factor() elif str[pos] == '/': pos += 1 result /= parse_factor() return result def parse_factor(): nonlocal pos if str[pos].isdigit(): return parse_number() elif str[pos] == '(': pos += 1 result = parse_expression() pos += 1 # consume ')' return result elif str[pos:pos+3] == 'sin': pos += 3 result = math.sin(parse_factor()) return result elif str[pos:pos+3] == 'cos': pos += 3 result = math.cos(parse_factor()) return result else: raise ValueError("Invalid character") def parse_number(): nonlocal pos result = 0 while pos < len(str) and str[pos].isdigit(): result = result * 10 + int(str[pos]) pos += 1 return result return parse_expression() # Example usage if __name__ == "__main__": print(evaluate("sin(3 + 2 * 4) - cos(15)")) |
I extracted the following code from that output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | import math def evaluate(str): """ Evaluates a mathematical expression. Args: str (str): The mathematical expression to evaluate. Returns: float: The result of the evaluation. """ pos = 0 def parse_expression(): nonlocal pos result = parse_term() while pos < len(str) and str[pos] in '+-': if str[pos] == '+': pos += 1 result += parse_term() elif str[pos] == '-': pos += 1 result -= parse_term() return result def parse_term(): nonlocal pos result = parse_factor() while pos < len(str) and str[pos] in '*/': if str[pos] == '*': pos += 1 result *= parse_factor() elif str[pos] == '/': pos += 1 result /= parse_factor() return result def parse_factor(): nonlocal pos if str[pos].isdigit(): return parse_number() elif str[pos] == '(': pos += 1 result = parse_expression() pos += 1 # consume ')' return result elif str[pos:pos+3] == 'sin': pos += 3 result = math.sin(parse_factor()) return result elif str[pos:pos+3] == 'cos': pos += 3 result = math.cos(parse_factor()) return result else: raise ValueError("Invalid character") def parse_number(): nonlocal pos result = 0 while pos < len(str) and str[pos].isdigit(): result = result * 10 + int(str[pos]) pos += 1 return result return parse_expression() # Example usage if __name__ == "__main__": print(evaluate("sin(3 + 2 * 4) - cos(15)")) |
Running the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | import math def evaluate(str): """ Evaluates a mathematical expression. Args: str (str): The mathematical expression to evaluate. Returns: float: The result of the evaluation. """ pos = 0 def parse_expression(): nonlocal pos result = parse_term() while pos < len(str) and str[pos] in '+-': if str[pos] == '+': pos += 1 result += parse_term() elif str[pos] == '-': pos += 1 result -= parse_term() return result def parse_term(): nonlocal pos result = parse_factor() while pos < len(str) and str[pos] in '*/': if str[pos] == '*': pos += 1 result *= parse_factor() elif str[pos] == '/': pos += 1 result /= parse_factor() return result def parse_factor(): nonlocal pos if str[pos].isdigit(): return parse_number() elif str[pos] == '(': pos += 1 result = parse_expression() pos += 1 # consume ')' return result elif str[pos:pos+3] == 'sin': pos += 3 result = math.sin(parse_factor()) return result elif str[pos:pos+3] == 'cos': pos += 3 result = math.cos(parse_factor()) return result else: raise ValueError("Invalid character") def parse_number(): nonlocal pos result = 0 while pos < len(str) and str[pos].isdigit(): result = result * 10 + int(str[pos]) pos += 1 return result return parse_expression() # Example usage if __name__ == "__main__": print(evaluate("sin(3 + 2 * 4) - cos(15)")) answer = round(evaluate('sin(35+2*4)-cos(15)'), 5) expected = -0.07209 assert answer == expected, f'Wrong answer; got {answer} instead of {expected}' print('All tests passed') |
Traceback (most recent call last):
File "/usr/src/app/main.py", line 73, in <module>
print(evaluate("sin(3 + 2 * 4) - cos(15)"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/app/main.py", line 68, in evaluate
return parse_expression()
^^^^^^^^^^^^^^^^^^
File "/usr/src/app/main.py", line 22, in parse_expression
result += parse_term()
^^^^^^^^^^^^
File "/usr/src/app/main.py", line 30, in parse_term
result = parse_factor()
^^^^^^^^^^^^^^
File "/usr/src/app/main.py", line 58, in parse_factor
raise ValueError("Invalid character")
ValueError: Invalid character
Testing if the previous output contains the string All tests passed
: False