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
Here's a Python function that evaluates expressions based on the given BNF-style grammar:
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 | import math def evaluate(expression): tokens = tokenize(expression) return parse_expression(tokens) def tokenize(expression): tokens = [] i = 0 while i < len(expression): if expression[i].isdigit(): num = "" while i < len(expression) and expression[i].isdigit(): num += expression[i] i += 1 tokens.append(num) elif expression[i] in "+-*/()": tokens.append(expression[i]) i += 1 elif expression[i:i+3] == "sin": tokens.append("sin") i += 3 elif expression[i:i+3] == "cos": tokens.append("cos") i += 3 elif expression[i].isspace(): i += 1 else: raise ValueError(f"Invalid character: {expression[i]}") return tokens def parse_expression(tokens): value = parse_term(tokens) while tokens and tokens[0] in "+-": op = tokens.pop(0) term = parse_term(tokens) if op == "+": value += term else: value -= term return value def parse_term(tokens): value = parse_factor(tokens) while tokens and tokens[0] in "*/": op = tokens.pop(0) factor = parse_factor(tokens) if op == "*": value *= factor else: value /= factor return value def parse_factor(tokens): if not tokens: raise ValueError("Unexpected end of expression") token = tokens.pop(0) if token.isdigit(): return float(token) elif token == "(": value = parse_expression(tokens) if not tokens or tokens.pop(0) != ")": raise ValueError("Mismatched parentheses") return value elif token in ["sin", "cos"]: factor = parse_factor(tokens) return math.sin(factor) if token == "sin" else math.cos(factor) else: raise ValueError(f"Unexpected token: {token}") # Example usage expression = "sin(3 + 2 * 4) - cos(15)" result = evaluate(expression) print(f"{expression} = {result:.6f}") |
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 73 74 75 | import math def evaluate(expression): tokens = tokenize(expression) return parse_expression(tokens) def tokenize(expression): tokens = [] i = 0 while i < len(expression): if expression[i].isdigit(): num = "" while i < len(expression) and expression[i].isdigit(): num += expression[i] i += 1 tokens.append(num) elif expression[i] in "+-*/()": tokens.append(expression[i]) i += 1 elif expression[i:i+3] == "sin": tokens.append("sin") i += 3 elif expression[i:i+3] == "cos": tokens.append("cos") i += 3 elif expression[i].isspace(): i += 1 else: raise ValueError(f"Invalid character: {expression[i]}") return tokens def parse_expression(tokens): value = parse_term(tokens) while tokens and tokens[0] in "+-": op = tokens.pop(0) term = parse_term(tokens) if op == "+": value += term else: value -= term return value def parse_term(tokens): value = parse_factor(tokens) while tokens and tokens[0] in "*/": op = tokens.pop(0) factor = parse_factor(tokens) if op == "*": value *= factor else: value /= factor return value def parse_factor(tokens): if not tokens: raise ValueError("Unexpected end of expression") token = tokens.pop(0) if token.isdigit(): return float(token) elif token == "(": value = parse_expression(tokens) if not tokens or tokens.pop(0) != ")": raise ValueError("Mismatched parentheses") return value elif token in ["sin", "cos"]: factor = parse_factor(tokens) return math.sin(factor) if token == "sin" else math.cos(factor) else: raise ValueError(f"Unexpected token: {token}") # Example usage expression = "sin(3 + 2 * 4) - cos(15)" result = evaluate(expression) print(f"{expression} = {result:.6f}") |
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 82 83 84 | import math def evaluate(expression): tokens = tokenize(expression) return parse_expression(tokens) def tokenize(expression): tokens = [] i = 0 while i < len(expression): if expression[i].isdigit(): num = "" while i < len(expression) and expression[i].isdigit(): num += expression[i] i += 1 tokens.append(num) elif expression[i] in "+-*/()": tokens.append(expression[i]) i += 1 elif expression[i:i+3] == "sin": tokens.append("sin") i += 3 elif expression[i:i+3] == "cos": tokens.append("cos") i += 3 elif expression[i].isspace(): i += 1 else: raise ValueError(f"Invalid character: {expression[i]}") return tokens def parse_expression(tokens): value = parse_term(tokens) while tokens and tokens[0] in "+-": op = tokens.pop(0) term = parse_term(tokens) if op == "+": value += term else: value -= term return value def parse_term(tokens): value = parse_factor(tokens) while tokens and tokens[0] in "*/": op = tokens.pop(0) factor = parse_factor(tokens) if op == "*": value *= factor else: value /= factor return value def parse_factor(tokens): if not tokens: raise ValueError("Unexpected end of expression") token = tokens.pop(0) if token.isdigit(): return float(token) elif token == "(": value = parse_expression(tokens) if not tokens or tokens.pop(0) != ")": raise ValueError("Mismatched parentheses") return value elif token in ["sin", "cos"]: factor = parse_factor(tokens) return math.sin(factor) if token == "sin" else math.cos(factor) else: raise ValueError(f"Unexpected token: {token}") # Example usage expression = "sin(3 + 2 * 4) - cos(15)" result = evaluate(expression) print(f"{expression} = {result:.6f}") 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') |
sin(3 + 2 * 4) - cos(15) = -0.240302
All tests passed
Testing if the previous output contains the string All tests passed
: True
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
Here's a Python function that evaluates expressions based on the given BNF-style grammar:
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 | import math def evaluate(expression): tokens = tokenize(expression) return parse_expression(tokens) def tokenize(s): tokens = [] i = 0 while i < len(s): if s[i].isdigit(): num = '' while i < len(s) and s[i].isdigit(): num += s[i] i += 1 tokens.append(('NUMBER', float(num))) elif s[i] in '+-*/()': tokens.append(('OPERATOR', s[i])) i += 1 elif s[i:i+3] == 'sin': tokens.append(('FUNCTION', 'sin')) i += 3 elif s[i:i+3] == 'cos': tokens.append(('FUNCTION', 'cos')) i += 3 elif s[i].isspace(): i += 1 else: raise ValueError(f"Invalid character: {s[i]}") return tokens def parse_expression(tokens): value = parse_term(tokens) while tokens and tokens[0][1] in '+-': op = tokens.pop(0)[1] term = parse_term(tokens) if op == '+': value += term else: value -= term return value def parse_term(tokens): value = parse_factor(tokens) while tokens and tokens[0][1] in '*/': op = tokens.pop(0)[1] factor = parse_factor(tokens) if op == '*': value *= factor else: value /= factor return value def parse_factor(tokens): if not tokens: raise ValueError("Unexpected end of expression") token = tokens.pop(0) if token[0] == 'NUMBER': return token[1] elif token[1] == '(': value = parse_expression(tokens) if not tokens or tokens.pop(0)[1] != ')': raise ValueError("Mismatched parentheses") return value elif token[0] == 'FUNCTION': factor = parse_factor(tokens) if token[1] == 'sin': return math.sin(factor) elif token[1] == 'cos': return math.cos(factor) else: raise ValueError(f"Unexpected token: {token}") # Example usage expression = "sin(3 + 2 * 4) - cos(15)" result = evaluate(expression) print(f"{expression} = {result:.6f}") |
1 | sin(3 + 2 * 4) - cos(15) = -0.240302 |
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 73 | import math def evaluate(expression): tokens = tokenize(expression) return parse_expression(tokens) def tokenize(s): tokens = [] i = 0 while i < len(s): if s[i].isdigit(): num = '' while i < len(s) and s[i].isdigit(): num += s[i] i += 1 tokens.append(('NUMBER', float(num))) elif s[i] in '+-*/()': tokens.append(('OPERATOR', s[i])) i += 1 elif s[i:i+3] == 'sin': tokens.append(('FUNCTION', 'sin')) i += 3 elif s[i:i+3] == 'cos': tokens.append(('FUNCTION', 'cos')) i += 3 elif s[i].isspace(): i += 1 else: raise ValueError(f"Invalid character: {s[i]}") return tokens def parse_expression(tokens): value = parse_term(tokens) while tokens and tokens[0][1] in '+-': op = tokens.pop(0)[1] term = parse_term(tokens) if op == '+': value += term else: value -= term return value def parse_term(tokens): value = parse_factor(tokens) while tokens and tokens[0][1] in '*/': op = tokens.pop(0)[1] factor = parse_factor(tokens) if op == '*': value *= factor else: value /= factor return value def parse_factor(tokens): if not tokens: raise ValueError("Unexpected end of expression") token = tokens.pop(0) if token[0] == 'NUMBER': return token[1] elif token[1] == '(': value = parse_expression(tokens) if not tokens or tokens.pop(0)[1] != ')': raise ValueError("Mismatched parentheses") return value elif token[0] == 'FUNCTION': factor = parse_factor(tokens) if token[1] == 'sin': return math.sin(factor) elif token[1] == 'cos': return math.cos(factor) else: raise ValueError(f"Unexpected token: {token}") |
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 82 | import math def evaluate(expression): tokens = tokenize(expression) return parse_expression(tokens) def tokenize(s): tokens = [] i = 0 while i < len(s): if s[i].isdigit(): num = '' while i < len(s) and s[i].isdigit(): num += s[i] i += 1 tokens.append(('NUMBER', float(num))) elif s[i] in '+-*/()': tokens.append(('OPERATOR', s[i])) i += 1 elif s[i:i+3] == 'sin': tokens.append(('FUNCTION', 'sin')) i += 3 elif s[i:i+3] == 'cos': tokens.append(('FUNCTION', 'cos')) i += 3 elif s[i].isspace(): i += 1 else: raise ValueError(f"Invalid character: {s[i]}") return tokens def parse_expression(tokens): value = parse_term(tokens) while tokens and tokens[0][1] in '+-': op = tokens.pop(0)[1] term = parse_term(tokens) if op == '+': value += term else: value -= term return value def parse_term(tokens): value = parse_factor(tokens) while tokens and tokens[0][1] in '*/': op = tokens.pop(0)[1] factor = parse_factor(tokens) if op == '*': value *= factor else: value /= factor return value def parse_factor(tokens): if not tokens: raise ValueError("Unexpected end of expression") token = tokens.pop(0) if token[0] == 'NUMBER': return token[1] elif token[1] == '(': value = parse_expression(tokens) if not tokens or tokens.pop(0)[1] != ')': raise ValueError("Mismatched parentheses") return value elif token[0] == 'FUNCTION': factor = parse_factor(tokens) if token[1] == 'sin': return math.sin(factor) elif token[1] == 'cos': return math.cos(factor) else: raise ValueError(f"Unexpected token: {token}") 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') |
All tests passed
Testing if the previous output contains the string All tests passed
: True
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
To implement an evaluator for this grammar, we'll use a recursive descent parser along with a tokenizer. Here's a Python implementation that should handle the given grammar:
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 82 83 84 85 86 87 88 89 | import math import re class Token: def __init__(self, type, value): self.type = type self.value = value def tokenize(expression): token_specification = [ ('NUMBER', r'\d+(\.\d*)?'), ('PLUS', r'\+'), ('MINUS', r'-'), ('MULTIPLY', r'\*'), ('DIVIDE', r'/'), ('LPAREN', r'\('), ('RPAREN', r'\)'), ('SIN', r'sin'), ('COS', r'cos'), ('SKIP', r'[ \t]+'), ] tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification) for mo in re.finditer(tok_regex, expression): kind = mo.lastgroup value = mo.group() if kind == 'NUMBER': value = float(value) elif kind == 'SKIP': continue yield Token(kind, value) class Parser: def __init__(self, tokens): self.tokens = tokens self.current_token = next(self.tokens, None) def eat(self, token_type): if self.current_token and self.current_token.type == token_type: self.current_token = next(self.tokens, None) else: raise ValueError(f'Expected {token_type}') def factor(self): if self.current_token.type == 'NUMBER': value = self.current_token.value self.eat('NUMBER') return value elif self.current_token.type == 'LPAREN': self.eat('LPAREN') result = self.expression() self.eat('RPAREN') return result elif self.current_token.type in ['SIN', 'COS']: op = self.current_token.type self.eat(op) value = self.factor() return math.sin(value) if op == 'SIN' else math.cos(value) else: raise ValueError('Invalid factor') def term(self): result = self.factor() while self.current_token and self.current_token.type in ['MULTIPLY', 'DIVIDE']: if self.current_token.type == 'MULTIPLY': self.eat('MULTIPLY') result *= self.factor() elif self.current_token.type == 'DIVIDE': self.eat('DIVIDE') result /= self.factor() return result def expression(self): result = self.term() while self.current_token and self.current_token.type in ['PLUS', 'MINUS']: if self.current_token.type == 'PLUS': self.eat('PLUS') result += self.term() elif self.current_token.type == 'MINUS': self.eat('MINUS') result -= self.term() return result def evaluate(expression): tokens = tokenize(expression) parser = Parser(tokens) return parser.expression() # Test the function 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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | import math import re class Token: def __init__(self, type, value): self.type = type self.value = value def tokenize(expression): token_specification = [ ('NUMBER', r'\d+(\.\d*)?'), ('PLUS', r'\+'), ('MINUS', r'-'), ('MULTIPLY', r'\*'), ('DIVIDE', r'/'), ('LPAREN', r'\('), ('RPAREN', r'\)'), ('SIN', r'sin'), ('COS', r'cos'), ('SKIP', r'[ \t]+'), ] tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification) for mo in re.finditer(tok_regex, expression): kind = mo.lastgroup value = mo.group() if kind == 'NUMBER': value = float(value) elif kind == 'SKIP': continue yield Token(kind, value) class Parser: def __init__(self, tokens): self.tokens = tokens self.current_token = next(self.tokens, None) def eat(self, token_type): if self.current_token and self.current_token.type == token_type: self.current_token = next(self.tokens, None) else: raise ValueError(f'Expected {token_type}') def factor(self): if self.current_token.type == 'NUMBER': value = self.current_token.value self.eat('NUMBER') return value elif self.current_token.type == 'LPAREN': self.eat('LPAREN') result = self.expression() self.eat('RPAREN') return result elif self.current_token.type in ['SIN', 'COS']: op = self.current_token.type self.eat(op) value = self.factor() return math.sin(value) if op == 'SIN' else math.cos(value) else: raise ValueError('Invalid factor') def term(self): result = self.factor() while self.current_token and self.current_token.type in ['MULTIPLY', 'DIVIDE']: if self.current_token.type == 'MULTIPLY': self.eat('MULTIPLY') result *= self.factor() elif self.current_token.type == 'DIVIDE': self.eat('DIVIDE') result /= self.factor() return result def expression(self): result = self.term() while self.current_token and self.current_token.type in ['PLUS', 'MINUS']: if self.current_token.type == 'PLUS': self.eat('PLUS') result += self.term() elif self.current_token.type == 'MINUS': self.eat('MINUS') result -= self.term() return result def evaluate(expression): tokens = tokenize(expression) parser = Parser(tokens) return parser.expression() # Test the function 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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | import math import re class Token: def __init__(self, type, value): self.type = type self.value = value def tokenize(expression): token_specification = [ ('NUMBER', r'\d+(\.\d*)?'), ('PLUS', r'\+'), ('MINUS', r'-'), ('MULTIPLY', r'\*'), ('DIVIDE', r'/'), ('LPAREN', r'\('), ('RPAREN', r'\)'), ('SIN', r'sin'), ('COS', r'cos'), ('SKIP', r'[ \t]+'), ] tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification) for mo in re.finditer(tok_regex, expression): kind = mo.lastgroup value = mo.group() if kind == 'NUMBER': value = float(value) elif kind == 'SKIP': continue yield Token(kind, value) class Parser: def __init__(self, tokens): self.tokens = tokens self.current_token = next(self.tokens, None) def eat(self, token_type): if self.current_token and self.current_token.type == token_type: self.current_token = next(self.tokens, None) else: raise ValueError(f'Expected {token_type}') def factor(self): if self.current_token.type == 'NUMBER': value = self.current_token.value self.eat('NUMBER') return value elif self.current_token.type == 'LPAREN': self.eat('LPAREN') result = self.expression() self.eat('RPAREN') return result elif self.current_token.type in ['SIN', 'COS']: op = self.current_token.type self.eat(op) value = self.factor() return math.sin(value) if op == 'SIN' else math.cos(value) else: raise ValueError('Invalid factor') def term(self): result = self.factor() while self.current_token and self.current_token.type in ['MULTIPLY', 'DIVIDE']: if self.current_token.type == 'MULTIPLY': self.eat('MULTIPLY') result *= self.factor() elif self.current_token.type == 'DIVIDE': self.eat('DIVIDE') result /= self.factor() return result def expression(self): result = self.term() while self.current_token and self.current_token.type in ['PLUS', 'MINUS']: if self.current_token.type == 'PLUS': self.eat('PLUS') result += self.term() elif self.current_token.type == 'MINUS': self.eat('MINUS') result -= self.term() return result def evaluate(expression): tokens = tokenize(expression) parser = Parser(tokens) return parser.expression() # Test the function 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') |
-0.24030229369188216
All tests passed
Testing if the previous output contains the string All tests passed
: True
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
Here's a Python function that evaluates expressions based on the given BNF-style grammar:
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 | import math def evaluate(expr): def parse_expression(): nonlocal index result = parse_term() while index < len(expr) and expr[index] in ['+', '-']: op = expr[index] index += 1 if op == '+': result += parse_term() else: result -= parse_term() return result def parse_term(): nonlocal index result = parse_factor() while index < len(expr) and expr[index] in ['*', '/']: op = expr[index] index += 1 if op == '*': result *= parse_factor() else: result /= parse_factor() return result def parse_factor(): nonlocal index if expr[index].isdigit(): return parse_number() elif expr[index] == '(': index += 1 result = parse_expression() index += 1 # Skip closing parenthesis return result else: return parse_prefix_op() def parse_prefix_op(): nonlocal index if expr[index:index+3] == 'sin': index += 3 return math.sin(parse_factor()) elif expr[index:index+3] == 'cos': index += 3 return math.cos(parse_factor()) else: raise ValueError("Invalid prefix operator") def parse_number(): nonlocal index number = 0 while index < len(expr) and expr[index].isdigit(): number = number * 10 + int(expr[index]) index += 1 return number index = 0 expr = expr.replace(" ", "") # Remove all spaces return parse_expression() # Test the function print(evaluate("sin(3 + 2 * 4) - cos(15)")) # Should print approximately -0.240302 |
1 2 3 | print(evaluate("2 + 3 * 4")) # Should print 14 print(evaluate("(2 + 3) * 4")) # Should print 20 print(evaluate("sin(30) + cos(60)")) # Should print approximately 0.9996 |
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 | import math def evaluate(expr): def parse_expression(): nonlocal index result = parse_term() while index < len(expr) and expr[index] in ['+', '-']: op = expr[index] index += 1 if op == '+': result += parse_term() else: result -= parse_term() return result def parse_term(): nonlocal index result = parse_factor() while index < len(expr) and expr[index] in ['*', '/']: op = expr[index] index += 1 if op == '*': result *= parse_factor() else: result /= parse_factor() return result def parse_factor(): nonlocal index if expr[index].isdigit(): return parse_number() elif expr[index] == '(': index += 1 result = parse_expression() index += 1 # Skip closing parenthesis return result else: return parse_prefix_op() def parse_prefix_op(): nonlocal index if expr[index:index+3] == 'sin': index += 3 return math.sin(parse_factor()) elif expr[index:index+3] == 'cos': index += 3 return math.cos(parse_factor()) else: raise ValueError("Invalid prefix operator") def parse_number(): nonlocal index number = 0 while index < len(expr) and expr[index].isdigit(): number = number * 10 + int(expr[index]) index += 1 return number index = 0 expr = expr.replace(" ", "") # Remove all spaces return parse_expression() |
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 | import math def evaluate(expr): def parse_expression(): nonlocal index result = parse_term() while index < len(expr) and expr[index] in ['+', '-']: op = expr[index] index += 1 if op == '+': result += parse_term() else: result -= parse_term() return result def parse_term(): nonlocal index result = parse_factor() while index < len(expr) and expr[index] in ['*', '/']: op = expr[index] index += 1 if op == '*': result *= parse_factor() else: result /= parse_factor() return result def parse_factor(): nonlocal index if expr[index].isdigit(): return parse_number() elif expr[index] == '(': index += 1 result = parse_expression() index += 1 # Skip closing parenthesis return result else: return parse_prefix_op() def parse_prefix_op(): nonlocal index if expr[index:index+3] == 'sin': index += 3 return math.sin(parse_factor()) elif expr[index:index+3] == 'cos': index += 3 return math.cos(parse_factor()) else: raise ValueError("Invalid prefix operator") def parse_number(): nonlocal index number = 0 while index < len(expr) and expr[index].isdigit(): number = number * 10 + int(expr[index]) index += 1 return number index = 0 expr = expr.replace(" ", "") # Remove all spaces return parse_expression() 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') |
All tests passed
Testing if the previous output contains the string All tests passed
: True
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
To evaluate expressions based on the given BNF-style grammar, we can implement a recursive descent parser along with an evaluation mechanism. Here's a Python function that accomplishes this:
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 | import math def evaluate(expr): def parse_expression(): result = parse_term() while True: if peek() == '+': consume() result += parse_term() elif peek() == '-': consume() result -= parse_term() else: return result def parse_term(): result = parse_factor() while True: if peek() == '*': consume() result *= parse_factor() elif peek() == '/': consume() divisor = parse_factor() if divisor == 0: raise ValueError("Division by zero") result /= divisor else: return result def parse_factor(): if peek() == '(': consume() result = parse_expression() if peek() != ')': raise ValueError("Mismatched parentheses") consume() return result elif peek() in ['s', 'c']: # sin or cos op = consume(3) if op == 'sin': return math.sin(parse_factor()) elif op == 'cos': return math.cos(parse_factor()) else: return parse_number() def parse_number(): num = '' while peek() and peek().isdigit(): num += consume() if not num: raise ValueError("Expected number") return float(num) def peek(): return expr[0] if expr else '' def consume(n=1): nonlocal expr token = expr[:n] expr = expr[n:] return token # Remove whitespace expr = ''.join(expr.split()) result = parse_expression() if expr: # If there's anything left in the expression, it's invalid raise ValueError("Invalid expression") return result # Test the function print(evaluate("sin(3 + 2 * 4) - cos(15)")) # Should output approximately -0.240302 |
1 2 3 | print(evaluate("2 + 3 * 4")) # Should output 14 print(evaluate("sin(0) + cos(0)")) # Should output 1 print(evaluate("(1 + 2) * (3 + 4)")) # Should output 21 |
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 | import math def evaluate(expr): def parse_expression(): result = parse_term() while True: if peek() == '+': consume() result += parse_term() elif peek() == '-': consume() result -= parse_term() else: return result def parse_term(): result = parse_factor() while True: if peek() == '*': consume() result *= parse_factor() elif peek() == '/': consume() divisor = parse_factor() if divisor == 0: raise ValueError("Division by zero") result /= divisor else: return result def parse_factor(): if peek() == '(': consume() result = parse_expression() if peek() != ')': raise ValueError("Mismatched parentheses") consume() return result elif peek() in ['s', 'c']: # sin or cos op = consume(3) if op == 'sin': return math.sin(parse_factor()) elif op == 'cos': return math.cos(parse_factor()) else: return parse_number() def parse_number(): num = '' while peek() and peek().isdigit(): num += consume() if not num: raise ValueError("Expected number") return float(num) def peek(): return expr[0] if expr else '' def consume(n=1): nonlocal expr token = expr[:n] expr = expr[n:] return token # Remove whitespace expr = ''.join(expr.split()) result = parse_expression() if expr: # If there's anything left in the expression, it's invalid raise ValueError("Invalid expression") return result |
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 | import math def evaluate(expr): def parse_expression(): result = parse_term() while True: if peek() == '+': consume() result += parse_term() elif peek() == '-': consume() result -= parse_term() else: return result def parse_term(): result = parse_factor() while True: if peek() == '*': consume() result *= parse_factor() elif peek() == '/': consume() divisor = parse_factor() if divisor == 0: raise ValueError("Division by zero") result /= divisor else: return result def parse_factor(): if peek() == '(': consume() result = parse_expression() if peek() != ')': raise ValueError("Mismatched parentheses") consume() return result elif peek() in ['s', 'c']: # sin or cos op = consume(3) if op == 'sin': return math.sin(parse_factor()) elif op == 'cos': return math.cos(parse_factor()) else: return parse_number() def parse_number(): num = '' while peek() and peek().isdigit(): num += consume() if not num: raise ValueError("Expected number") return float(num) def peek(): return expr[0] if expr else '' def consume(n=1): nonlocal expr token = expr[:n] expr = expr[n:] return token # Remove whitespace expr = ''.join(expr.split()) result = parse_expression() if expr: # If there's anything left in the expression, it's invalid raise ValueError("Invalid expression") return result 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') |
All tests passed
Testing if the previous output contains the string All tests passed
: True