Initial Query

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

LLM Generation

Query

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

Output

To evaluate expressions defined by the given BNF-style grammar in Python, we can use recursion to parse and evaluate the expressions according to the specified rules. Here is a Python function `evaluate(str)` 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
import math
import re

def evaluate(expr):
    def parse_expression(tokens):
        total = parse_term(tokens)
        while tokens and tokens[0] in ('+', '-'):
            op = tokens.pop(0)
            if op == '+':
                total += parse_term(tokens)
            elif op == '-':
                total -= parse_term(tokens)
        return total

    def parse_term(tokens):
        total = parse_factor(tokens)
        while tokens and tokens[0] in ('*', '/'):
            op = tokens.pop(0)
            if op == '*':
                total *= parse_factor(tokens)
            elif op == '/':
                total /= parse_factor(tokens)
        return total

    def parse_factor(tokens):
        token = tokens.pop(0)
        if token.isdigit():  # Number
            return float(token)
        elif token == '(':  # Parentheses
            total = parse_expression(tokens)
            tokens.pop(0)  # Removing the closing ')'
            return total
        elif token in ('sin', 'cos'):  # Prefix operators
            return parse_prefix_operation(token, tokens)
        else:
            raise ValueError("Unexpected token: " + token)

    def parse_prefix_operation(op, tokens):
        factor = parse_factor(tokens)
        if op == 'sin':
            return math.sin(factor)
        elif op == 'cos':
            return math.cos(factor)

    # Tokenize the input expression
    tokens = re.findall(r'\d+|[()+\-*/]|sin|cos', expr)
    return parse_expression(tokens)

# Example usage:
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output should be approximately -0.240302
### Explanation of the Code: 1. **Tokenization**: The input string is tokenized using regular expressions to capture numbers, operators, parentheses, and functions (`sin` and `cos`). 2. **Parsing Functions**: - `parse_expression`: Handles addition and subtraction. - `parse_term`: Handles multiplication and division. - `parse_factor`: Handles numbers, parentheses, and prefix operations. - `parse_prefix_operation`: Evaluates `sin` and `cos` functions. 3. **Recursion**: Each parsing function calls the next one to build up the expression tree according to the rules defined in the grammar. 4. **Evaluation**: The arithmetic operations and trigonometric functions are performed as the parsing progresses. ### Example Test You can test the function with various expressions to ensure it works as intended. The provided example `sin(3 + 2 * 4) - cos(15)` should yield approximately `-0.240302`.

Extract Code

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
import math
import re

def evaluate(expr):
    def parse_expression(tokens):
        total = parse_term(tokens)
        while tokens and tokens[0] in ('+', '-'):
            op = tokens.pop(0)
            if op == '+':
                total += parse_term(tokens)
            elif op == '-':
                total -= parse_term(tokens)
        return total

    def parse_term(tokens):
        total = parse_factor(tokens)
        while tokens and tokens[0] in ('*', '/'):
            op = tokens.pop(0)
            if op == '*':
                total *= parse_factor(tokens)
            elif op == '/':
                total /= parse_factor(tokens)
        return total

    def parse_factor(tokens):
        token = tokens.pop(0)
        if token.isdigit():  # Number
            return float(token)
        elif token == '(':  # Parentheses
            total = parse_expression(tokens)
            tokens.pop(0)  # Removing the closing ')'
            return total
        elif token in ('sin', 'cos'):  # Prefix operators
            return parse_prefix_operation(token, tokens)
        else:
            raise ValueError("Unexpected token: " + token)

    def parse_prefix_operation(op, tokens):
        factor = parse_factor(tokens)
        if op == 'sin':
            return math.sin(factor)
        elif op == 'cos':
            return math.cos(factor)

    # Tokenize the input expression
    tokens = re.findall(r'\d+|[()+\-*/]|sin|cos', expr)
    return parse_expression(tokens)

# Example usage:
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output should be approximately -0.240302

Run Code Interpreter

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
import math
import re

def evaluate(expr):
    def parse_expression(tokens):
        total = parse_term(tokens)
        while tokens and tokens[0] in ('+', '-'):
            op = tokens.pop(0)
            if op == '+':
                total += parse_term(tokens)
            elif op == '-':
                total -= parse_term(tokens)
        return total

    def parse_term(tokens):
        total = parse_factor(tokens)
        while tokens and tokens[0] in ('*', '/'):
            op = tokens.pop(0)
            if op == '*':
                total *= parse_factor(tokens)
            elif op == '/':
                total /= parse_factor(tokens)
        return total

    def parse_factor(tokens):
        token = tokens.pop(0)
        if token.isdigit():  # Number
            return float(token)
        elif token == '(':  # Parentheses
            total = parse_expression(tokens)
            tokens.pop(0)  # Removing the closing ')'
            return total
        elif token in ('sin', 'cos'):  # Prefix operators
            return parse_prefix_operation(token, tokens)
        else:
            raise ValueError("Unexpected token: " + token)

    def parse_prefix_operation(op, tokens):
        factor = parse_factor(tokens)
        if op == 'sin':
            return math.sin(factor)
        elif op == 'cos':
            return math.cos(factor)

    # Tokenize the input expression
    tokens = re.findall(r'\d+|[()+\-*/]|sin|cos', expr)
    return parse_expression(tokens)

# Example usage:
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output should be approximately -0.240302





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')
And got the output: -0.24030229369188216 All tests passed

Substring Evaluation

Testing if the previous output contains the string All tests passed: True

Initial Query

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

LLM Generation

Query

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

Output

To evaluate expressions according to the given BNF-style grammar, we can utilize Python's `re` module for parsing and a recursive approach to evaluate different parts of the expression. We'll define a function `evaluate` that handles the parsing and computation of the expression based on the grammar rules. Here's a complete implementation of the `evaluate` function:

 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 re
import math

def evaluate(expr):
    def parse_expression(tokens):
        """Parse an expression and return its value."""
        term_value = parse_term(tokens)
        
        while tokens and tokens[0] in ('+', '-'):
            op = tokens.pop(0)
            next_term_value = parse_term(tokens)
            if op == '+':
                term_value += next_term_value
            elif op == '-':
                term_value -= next_term_value
        
        return term_value

    def parse_term(tokens):
        """Parse a term and return its value."""
        factor_value = parse_factor(tokens)
        
        while tokens and tokens[0] in ('*', '/'):
            op = tokens.pop(0)
            next_factor_value = parse_factor(tokens)
            if op == '*':
                factor_value *= next_factor_value
            elif op == '/':
                factor_value /= next_factor_value
        
        return factor_value

    def parse_factor(tokens):
        """Parse a factor and return its value."""
        if not tokens:
            raise ValueError("Unexpected end of expression")

        token = tokens.pop(0)

        if token.isdigit():  # Number
            return float(token)

        elif token == '(':  # Parenthesized expression
            value = parse_expression(tokens)
            if not tokens or tokens.pop(0) != ')':
                raise ValueError("Mismatched parentheses")
            return value
        
        elif token in ('sin', 'cos'):  # Prefix operations
            factor_value = parse_factor(tokens)
            if token == 'sin':
                return math.sin(factor_value)
            elif token == 'cos':
                return math.cos(factor_value)

        raise ValueError(f"Unexpected token: {token}")

    # Tokenize the input expression
    tokens = re.findall(r'\d+|sin|cos|[()+\-*/]', expr.replace(" ", ""))
    
    # Parse and evaluate the expression
    result = parse_expression(tokens)
    
    if tokens:
        raise ValueError(f"Unexpected tokens remaining: {tokens}")

    return result

# Example usage:
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output: -0.240302
### Explanation: 1. **Tokenization**: The input expression is tokenized using a regular expression to split it into numbers, operators, and parentheses. 2. **Parsing**: - `parse_expression`: This function handles the addition and subtraction operations. - `parse_term`: This function deals with multiplication and division. - `parse_factor`: This function evaluates numbers, parenthesized expressions, and prefix operations (sin, cos). 3. **Error Handling**: The code raises exceptions for unmatched parentheses or unexpected tokens. This implementation respects the provided grammar and is capable of evaluating expressions using basic arithmetic operations and trigonometric functions.

Extract Code

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 re
import math

def evaluate(expr):
    def parse_expression(tokens):
        """Parse an expression and return its value."""
        term_value = parse_term(tokens)
        
        while tokens and tokens[0] in ('+', '-'):
            op = tokens.pop(0)
            next_term_value = parse_term(tokens)
            if op == '+':
                term_value += next_term_value
            elif op == '-':
                term_value -= next_term_value
        
        return term_value

    def parse_term(tokens):
        """Parse a term and return its value."""
        factor_value = parse_factor(tokens)
        
        while tokens and tokens[0] in ('*', '/'):
            op = tokens.pop(0)
            next_factor_value = parse_factor(tokens)
            if op == '*':
                factor_value *= next_factor_value
            elif op == '/':
                factor_value /= next_factor_value
        
        return factor_value

    def parse_factor(tokens):
        """Parse a factor and return its value."""
        if not tokens:
            raise ValueError("Unexpected end of expression")

        token = tokens.pop(0)

        if token.isdigit():  # Number
            return float(token)

        elif token == '(':  # Parenthesized expression
            value = parse_expression(tokens)
            if not tokens or tokens.pop(0) != ')':
                raise ValueError("Mismatched parentheses")
            return value
        
        elif token in ('sin', 'cos'):  # Prefix operations
            factor_value = parse_factor(tokens)
            if token == 'sin':
                return math.sin(factor_value)
            elif token == 'cos':
                return math.cos(factor_value)

        raise ValueError(f"Unexpected token: {token}")

    # Tokenize the input expression
    tokens = re.findall(r'\d+|sin|cos|[()+\-*/]', expr.replace(" ", ""))
    
    # Parse and evaluate the expression
    result = parse_expression(tokens)
    
    if tokens:
        raise ValueError(f"Unexpected tokens remaining: {tokens}")

    return result

# Example usage:
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output: -0.240302

Run Code Interpreter

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 re
import math

def evaluate(expr):
    def parse_expression(tokens):
        """Parse an expression and return its value."""
        term_value = parse_term(tokens)
        
        while tokens and tokens[0] in ('+', '-'):
            op = tokens.pop(0)
            next_term_value = parse_term(tokens)
            if op == '+':
                term_value += next_term_value
            elif op == '-':
                term_value -= next_term_value
        
        return term_value

    def parse_term(tokens):
        """Parse a term and return its value."""
        factor_value = parse_factor(tokens)
        
        while tokens and tokens[0] in ('*', '/'):
            op = tokens.pop(0)
            next_factor_value = parse_factor(tokens)
            if op == '*':
                factor_value *= next_factor_value
            elif op == '/':
                factor_value /= next_factor_value
        
        return factor_value

    def parse_factor(tokens):
        """Parse a factor and return its value."""
        if not tokens:
            raise ValueError("Unexpected end of expression")

        token = tokens.pop(0)

        if token.isdigit():  # Number
            return float(token)

        elif token == '(':  # Parenthesized expression
            value = parse_expression(tokens)
            if not tokens or tokens.pop(0) != ')':
                raise ValueError("Mismatched parentheses")
            return value
        
        elif token in ('sin', 'cos'):  # Prefix operations
            factor_value = parse_factor(tokens)
            if token == 'sin':
                return math.sin(factor_value)
            elif token == 'cos':
                return math.cos(factor_value)

        raise ValueError(f"Unexpected token: {token}")

    # Tokenize the input expression
    tokens = re.findall(r'\d+|sin|cos|[()+\-*/]', expr.replace(" ", ""))
    
    # Parse and evaluate the expression
    result = parse_expression(tokens)
    
    if tokens:
        raise ValueError(f"Unexpected tokens remaining: {tokens}")

    return result

# Example usage:
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output: -0.240302





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')
And got the output: -0.24030229369188216 All tests passed

Substring Evaluation

Testing if the previous output contains the string All tests passed: True

Initial Query

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

LLM Generation

Query

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

Output

To evaluate expressions defined by the given BNF-style grammar, we can define a Python function that uses recursion to parse the expression according to the specified rules. The evaluation will handle addition, subtraction, multiplication, division, and the trigonometric functions sine and cosine. We'll break down the implementation into several helper functions corresponding to the grammar rules (`expression`, `term`, `factor`, etc.). Here's how we can implement 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
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
import math

class Parser:
    def __init__(self, text):
        self.text = text
        self.pos = 0
        self.current_char = self.text[self.pos] if self.text else None

    def error(self):
        raise Exception('Invalid syntax')

    def advance(self):
        """Advance the 'pos' pointer and set 'current_char'."""
        self.pos += 1
        if self.pos > len(self.text) - 1:
            self.current_char = None
        else:
            self.current_char = self.text[self.pos]

    def skip_whitespace(self):
        """Skip whitespace characters."""
        while self.current_char is not None and self.current_char.isspace():
            self.advance()

    def parse_number(self):
        """Parse a number."""
        num_str = ''
        while self.current_char is not None and self.current_char.isdigit():
            num_str += self.current_char
            self.advance()
        return int(num_str)

    def parse_factor(self):
        """factor ::= <number> | '(' <expression> ')' | <prefix-op> <factor>"""
        if self.current_char == '(':
            self.advance()
            result = self.parse_expression()
            if self.current_char != ')':
                self.error()
            self.advance()  # Skip ')'
            return result
        elif self.current_char.isdigit():
            return self.parse_number()
        elif self.current_char in ['s', 'c']:
            prefix_op = self.parse_prefix_op()
            factor = self.parse_factor()
            if prefix_op == 'sin':
                return math.sin(factor)
            elif prefix_op == 'cos':
                return math.cos(factor)
        self.error()

    def parse_prefix_op(self):
        """prefix-op ::= 'sin' | 'cos'"""
        if self.text[self.pos:self.pos+3] == 'sin':
            self.pos += 3
            self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
            return 'sin'
        elif self.text[self.pos:self.pos+3] == 'cos':
            self.pos += 3
            self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
            return 'cos'
        self.error()

    def parse_term(self):
        """term ::= <factor> | <term> '*' <factor> | <term> '/' <factor>"""
        result = self.parse_factor()

        while self.current_char is not None and self.current_char in ('*', '/'):
            op = self.current_char
            self.advance()
            if op == '*':
                result *= self.parse_factor()
            elif op == '/':
                denominator = self.parse_factor()
                if denominator == 0:
                    self.error()  # Division by zero
                result /= denominator

        return result

    def parse_expression(self):
        """expression ::= <term> | <expression> '+' <term> | <expression> '-' <term>"""
        result = self.parse_term()

        while self.current_char is not None and self.current_char in ('+', '-'):
            op = self.current_char
            self.advance()
            if op == '+':
                result += self.parse_term()
            elif op == '-':
                result -= self.parse_term()

        return result

def evaluate(expression):
    parser = Parser(expression)
    parser.skip_whitespace()
    result = parser.parse_expression()
    if parser.current_char is not None:
        parser.error()  # If there's any remaining character, it's an error
    return result

# Example usage:
print(evaluate("sin(3 + 2 * 4) - cos(15)"))  # Should print a numerical result
### Explanation: 1. **Parsing Logic**: We define a `Parser` class that takes the input expression as a string and parses it according to the grammar. The parsing functions correspond to the grammar rules. 2. **Recursive Structure**: The parsing functions call each other recursively to handle the nested structure of expressions. 3. **Handling Operators**: The functions manage operators and precedence according to the grammar, ensuring that multiplication and division are processed before addition and subtraction. 4. **Trigonometric Functions**: The `parse_factor` method checks for `sin` or `cos` prefixes and evaluates them accordingly. 5. **Error Handling**: The parser includes error handling for invalid expressions and division by zero. You can test the function with different expressions following the grammar rules!

Extract Code

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
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
import math

class Parser:
    def __init__(self, text):
        self.text = text
        self.pos = 0
        self.current_char = self.text[self.pos] if self.text else None

    def error(self):
        raise Exception('Invalid syntax')

    def advance(self):
        """Advance the 'pos' pointer and set 'current_char'."""
        self.pos += 1
        if self.pos > len(self.text) - 1:
            self.current_char = None
        else:
            self.current_char = self.text[self.pos]

    def skip_whitespace(self):
        """Skip whitespace characters."""
        while self.current_char is not None and self.current_char.isspace():
            self.advance()

    def parse_number(self):
        """Parse a number."""
        num_str = ''
        while self.current_char is not None and self.current_char.isdigit():
            num_str += self.current_char
            self.advance()
        return int(num_str)

    def parse_factor(self):
        """factor ::= <number> | '(' <expression> ')' | <prefix-op> <factor>"""
        if self.current_char == '(':
            self.advance()
            result = self.parse_expression()
            if self.current_char != ')':
                self.error()
            self.advance()  # Skip ')'
            return result
        elif self.current_char.isdigit():
            return self.parse_number()
        elif self.current_char in ['s', 'c']:
            prefix_op = self.parse_prefix_op()
            factor = self.parse_factor()
            if prefix_op == 'sin':
                return math.sin(factor)
            elif prefix_op == 'cos':
                return math.cos(factor)
        self.error()

    def parse_prefix_op(self):
        """prefix-op ::= 'sin' | 'cos'"""
        if self.text[self.pos:self.pos+3] == 'sin':
            self.pos += 3
            self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
            return 'sin'
        elif self.text[self.pos:self.pos+3] == 'cos':
            self.pos += 3
            self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
            return 'cos'
        self.error()

    def parse_term(self):
        """term ::= <factor> | <term> '*' <factor> | <term> '/' <factor>"""
        result = self.parse_factor()

        while self.current_char is not None and self.current_char in ('*', '/'):
            op = self.current_char
            self.advance()
            if op == '*':
                result *= self.parse_factor()
            elif op == '/':
                denominator = self.parse_factor()
                if denominator == 0:
                    self.error()  # Division by zero
                result /= denominator

        return result

    def parse_expression(self):
        """expression ::= <term> | <expression> '+' <term> | <expression> '-' <term>"""
        result = self.parse_term()

        while self.current_char is not None and self.current_char in ('+', '-'):
            op = self.current_char
            self.advance()
            if op == '+':
                result += self.parse_term()
            elif op == '-':
                result -= self.parse_term()

        return result

def evaluate(expression):
    parser = Parser(expression)
    parser.skip_whitespace()
    result = parser.parse_expression()
    if parser.current_char is not None:
        parser.error()  # If there's any remaining character, it's an error
    return result

# Example usage:
print(evaluate("sin(3 + 2 * 4) - cos(15)"))  # Should print a numerical result

Run Code Interpreter

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
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import math

class Parser:
    def __init__(self, text):
        self.text = text
        self.pos = 0
        self.current_char = self.text[self.pos] if self.text else None

    def error(self):
        raise Exception('Invalid syntax')

    def advance(self):
        """Advance the 'pos' pointer and set 'current_char'."""
        self.pos += 1
        if self.pos > len(self.text) - 1:
            self.current_char = None
        else:
            self.current_char = self.text[self.pos]

    def skip_whitespace(self):
        """Skip whitespace characters."""
        while self.current_char is not None and self.current_char.isspace():
            self.advance()

    def parse_number(self):
        """Parse a number."""
        num_str = ''
        while self.current_char is not None and self.current_char.isdigit():
            num_str += self.current_char
            self.advance()
        return int(num_str)

    def parse_factor(self):
        """factor ::= <number> | '(' <expression> ')' | <prefix-op> <factor>"""
        if self.current_char == '(':
            self.advance()
            result = self.parse_expression()
            if self.current_char != ')':
                self.error()
            self.advance()  # Skip ')'
            return result
        elif self.current_char.isdigit():
            return self.parse_number()
        elif self.current_char in ['s', 'c']:
            prefix_op = self.parse_prefix_op()
            factor = self.parse_factor()
            if prefix_op == 'sin':
                return math.sin(factor)
            elif prefix_op == 'cos':
                return math.cos(factor)
        self.error()

    def parse_prefix_op(self):
        """prefix-op ::= 'sin' | 'cos'"""
        if self.text[self.pos:self.pos+3] == 'sin':
            self.pos += 3
            self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
            return 'sin'
        elif self.text[self.pos:self.pos+3] == 'cos':
            self.pos += 3
            self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
            return 'cos'
        self.error()

    def parse_term(self):
        """term ::= <factor> | <term> '*' <factor> | <term> '/' <factor>"""
        result = self.parse_factor()

        while self.current_char is not None and self.current_char in ('*', '/'):
            op = self.current_char
            self.advance()
            if op == '*':
                result *= self.parse_factor()
            elif op == '/':
                denominator = self.parse_factor()
                if denominator == 0:
                    self.error()  # Division by zero
                result /= denominator

        return result

    def parse_expression(self):
        """expression ::= <term> | <expression> '+' <term> | <expression> '-' <term>"""
        result = self.parse_term()

        while self.current_char is not None and self.current_char in ('+', '-'):
            op = self.current_char
            self.advance()
            if op == '+':
                result += self.parse_term()
            elif op == '-':
                result -= self.parse_term()

        return result

def evaluate(expression):
    parser = Parser(expression)
    parser.skip_whitespace()
    result = parser.parse_expression()
    if parser.current_char is not None:
        parser.error()  # If there's any remaining character, it's an error
    return result

# Example usage:
print(evaluate("sin(3 + 2 * 4) - cos(15)"))  # Should print a numerical 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')
And got the output: Traceback (most recent call last): File "/usr/src/app/main.py", line 106, in <module> print(evaluate("sin(3 + 2 * 4) - cos(15)")) # Should print a numerical result File "/usr/src/app/main.py", line 100, in evaluate result = parser.parse_expression() File "/usr/src/app/main.py", line 85, in parse_expression result = self.parse_term() File "/usr/src/app/main.py", line 68, in parse_term result = self.parse_factor() File "/usr/src/app/main.py", line 47, in parse_factor factor = self.parse_factor() File "/usr/src/app/main.py", line 40, in parse_factor self.error() File "/usr/src/app/main.py", line 11, in error raise Exception('Invalid syntax') Exception: Invalid syntax

Substring Evaluation

Testing if the previous output contains the string All tests passed: False

Initial Query

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

LLM Generation

Query

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

Output

To implement the evaluation of the specified BNF-style grammar in Python, we can use recursion to break down the expression into its components, following the rules defined in the grammar. We will also use the `math` library to handle the sine and cosine operations. Here's a step-by-step implementation of the `evaluate` function: 1. **Tokenization**: First, we need to break the input string into manageable tokens (numbers, operators, parentheses, and function names). 2. **Parsing**: We will recursively parse the tokens according to the grammar rules. 3. **Evaluation**: Finally, we will evaluate the parsed expression to produce a result. Here is the complete implementation:

 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
import math
import re

def tokenize(expression):
    # Regular expression to match numbers, operators, and parentheses
    token_pattern = r'\s*(?:(\d+)|([+\-*/()])|(\b(?:sin|cos)\b))'
    tokens = []
    for match in re.finditer(token_pattern, expression):
        if match.group(1):  # Number
            tokens.append(('NUMBER', float(match.group(1))))
        elif match.group(2):  # Operator or Parenthesis
            tokens.append((match.group(2),))
        elif match.group(3):  # Function (sin or cos)
            tokens.append((match.group(3),))
    return tokens

class Parser:
    def __init__(self, tokens):
        self.tokens = tokens
        self.pos = 0

    def current_token(self):
        if self.pos < len(self.tokens):
            return self.tokens[self.pos]
        return None

    def consume(self):
        token = self.current_token()
        self.pos += 1
        return token

    def parse_expression(self):
        left = self.parse_term()
        while True:
            token = self.current_token()
            if token and token[0] in ('+', '-'):
                op = self.consume()[0]
                right = self.parse_term()
                if op == '+':
                    left += right
                elif op == '-':
                    left -= right
            else:
                break
        return left

    def parse_term(self):
        left = self.parse_factor()
        while True:
            token = self.current_token()
            if token and token[0] in ('*', '/'):
                op = self.consume()[0]
                right = self.parse_factor()
                if op == '*':
                    left *= right
                elif op == '/':
                    left /= right
            else:
                break
        return left

    def parse_factor(self):
        token = self.current_token()
        if token is None:
            raise ValueError("Unexpected end of expression")
        
        if token[0] == 'NUMBER':
            self.consume()
            return token[1]
        elif token[0] == '(':
            self.consume()  # consume '('
            expr_value = self.parse_expression()
            if self.current_token() is None or self.current_token()[0] != ')':
                raise ValueError("Missing closing parenthesis")
            self.consume()  # consume ')'
            return expr_value
        elif token[0] in ('sin', 'cos'):
            func = self.consume()[0]
            factor_value = self.parse_factor()
            if func == 'sin':
                return math.sin(factor_value)
            elif func == 'cos':
                return math.cos(factor_value)
        else:
            raise ValueError(f"Unexpected token: {token}")

def evaluate(expression):
    tokens = tokenize(expression)
    parser = Parser(tokens)
    return parser.parse_expression()

# Example usage
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output: -0.240302
### Explanation: - **Tokenization**: The `tokenize` function uses a regular expression to identify numbers, operators, parentheses, and function names. It returns a list of tokens. - **Parser Class**: The `Parser` class is responsible for parsing the tokens according to the grammar rules. It has methods for parsing expressions, terms, factors, and handling functions. - **Evaluation**: The `evaluate` function orchestrates the tokenization and parsing, ultimately returning the evaluated result. You can test the function with other expressions following the defined grammar rules as well.

Extract Code

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
90
91
92
93
94
import math
import re

def tokenize(expression):
    # Regular expression to match numbers, operators, and parentheses
    token_pattern = r'\s*(?:(\d+)|([+\-*/()])|(\b(?:sin|cos)\b))'
    tokens = []
    for match in re.finditer(token_pattern, expression):
        if match.group(1):  # Number
            tokens.append(('NUMBER', float(match.group(1))))
        elif match.group(2):  # Operator or Parenthesis
            tokens.append((match.group(2),))
        elif match.group(3):  # Function (sin or cos)
            tokens.append((match.group(3),))
    return tokens

class Parser:
    def __init__(self, tokens):
        self.tokens = tokens
        self.pos = 0

    def current_token(self):
        if self.pos < len(self.tokens):
            return self.tokens[self.pos]
        return None

    def consume(self):
        token = self.current_token()
        self.pos += 1
        return token

    def parse_expression(self):
        left = self.parse_term()
        while True:
            token = self.current_token()
            if token and token[0] in ('+', '-'):
                op = self.consume()[0]
                right = self.parse_term()
                if op == '+':
                    left += right
                elif op == '-':
                    left -= right
            else:
                break
        return left

    def parse_term(self):
        left = self.parse_factor()
        while True:
            token = self.current_token()
            if token and token[0] in ('*', '/'):
                op = self.consume()[0]
                right = self.parse_factor()
                if op == '*':
                    left *= right
                elif op == '/':
                    left /= right
            else:
                break
        return left

    def parse_factor(self):
        token = self.current_token()
        if token is None:
            raise ValueError("Unexpected end of expression")
        
        if token[0] == 'NUMBER':
            self.consume()
            return token[1]
        elif token[0] == '(':
            self.consume()  # consume '('
            expr_value = self.parse_expression()
            if self.current_token() is None or self.current_token()[0] != ')':
                raise ValueError("Missing closing parenthesis")
            self.consume()  # consume ')'
            return expr_value
        elif token[0] in ('sin', 'cos'):
            func = self.consume()[0]
            factor_value = self.parse_factor()
            if func == 'sin':
                return math.sin(factor_value)
            elif func == 'cos':
                return math.cos(factor_value)
        else:
            raise ValueError(f"Unexpected token: {token}")

def evaluate(expression):
    tokens = tokenize(expression)
    parser = Parser(tokens)
    return parser.parse_expression()

# Example usage
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output: -0.240302

Run Code Interpreter

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
 99
100
101
102
103
import math
import re

def tokenize(expression):
    # Regular expression to match numbers, operators, and parentheses
    token_pattern = r'\s*(?:(\d+)|([+\-*/()])|(\b(?:sin|cos)\b))'
    tokens = []
    for match in re.finditer(token_pattern, expression):
        if match.group(1):  # Number
            tokens.append(('NUMBER', float(match.group(1))))
        elif match.group(2):  # Operator or Parenthesis
            tokens.append((match.group(2),))
        elif match.group(3):  # Function (sin or cos)
            tokens.append((match.group(3),))
    return tokens

class Parser:
    def __init__(self, tokens):
        self.tokens = tokens
        self.pos = 0

    def current_token(self):
        if self.pos < len(self.tokens):
            return self.tokens[self.pos]
        return None

    def consume(self):
        token = self.current_token()
        self.pos += 1
        return token

    def parse_expression(self):
        left = self.parse_term()
        while True:
            token = self.current_token()
            if token and token[0] in ('+', '-'):
                op = self.consume()[0]
                right = self.parse_term()
                if op == '+':
                    left += right
                elif op == '-':
                    left -= right
            else:
                break
        return left

    def parse_term(self):
        left = self.parse_factor()
        while True:
            token = self.current_token()
            if token and token[0] in ('*', '/'):
                op = self.consume()[0]
                right = self.parse_factor()
                if op == '*':
                    left *= right
                elif op == '/':
                    left /= right
            else:
                break
        return left

    def parse_factor(self):
        token = self.current_token()
        if token is None:
            raise ValueError("Unexpected end of expression")
        
        if token[0] == 'NUMBER':
            self.consume()
            return token[1]
        elif token[0] == '(':
            self.consume()  # consume '('
            expr_value = self.parse_expression()
            if self.current_token() is None or self.current_token()[0] != ')':
                raise ValueError("Missing closing parenthesis")
            self.consume()  # consume ')'
            return expr_value
        elif token[0] in ('sin', 'cos'):
            func = self.consume()[0]
            factor_value = self.parse_factor()
            if func == 'sin':
                return math.sin(factor_value)
            elif func == 'cos':
                return math.cos(factor_value)
        else:
            raise ValueError(f"Unexpected token: {token}")

def evaluate(expression):
    tokens = tokenize(expression)
    parser = Parser(tokens)
    return parser.parse_expression()

# Example usage
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output: -0.240302





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')
And got the output: -0.24030229369188216 All tests passed

Substring Evaluation

Testing if the previous output contains the string All tests passed: True

Initial Query

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

LLM Generation

Query

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

Output

To implement the evaluation of the given BNF-style grammar in Python, we can create a recursive parser that will handle the different components of the expression according to the specified rules. Here's a complete implementation of the `evaluate` function that processes the expression and computes its value:

 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
import math
import re

class Evaluator:
    def __init__(self, expression):
        self.tokens = re.findall(r'\d+|[()\-+*/]|sin|cos', expression)
        self.index = 0

    def parse_expression(self):
        result = self.parse_term()
        while self.index < len(self.tokens) and self.tokens[self.index] in ('+', '-'):
            op = self.tokens[self.index]
            self.index += 1  # consume operator
            right = self.parse_term()
            if op == '+':
                result += right
            elif op == '-':
                result -= right
        return result

    def parse_term(self):
        result = self.parse_factor()
        while self.index < len(self.tokens) and self.tokens[self.index] in ('*', '/'):
            op = self.tokens[self.index]
            self.index += 1  # consume operator
            right = self.parse_factor()
            if op == '*':
                result *= right
            elif op == '/':
                result /= right
        return result

    def parse_factor(self):
        token = self.tokens[self.index]
        if token.isdigit():  # if it's a number
            self.index += 1  # consume number
            return float(token)
        elif token == '(':  # if it's a sub-expression
            self.index += 1  # consume '('
            result = self.parse_expression()
            self.index += 1  # consume ')'
            return result
        elif token in ('sin', 'cos'):  # if it's a prefix operator
            self.index += 1  # consume operator
            self.index += 1  # consume '('
            inner_result = self.parse_expression()
            self.index += 1  # consume ')'
            if token == 'sin':
                return math.sin(inner_result)
            elif token == 'cos':
                return math.cos(inner_result)

def evaluate(expression):
    evaluator = Evaluator(expression)
    return evaluator.parse_expression()

# Example usage
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output: -0.240302
### Explanation: 1. **Tokenization**: We use a regular expression to split the input expression into tokens, which include digits, operators, and parentheses. 2. **Parsing and Evaluation**: - The `parse_expression` method handles addition and subtraction. - The `parse_term` method deals with multiplication and division. - The `parse_factor` method processes numbers, parentheses (for nested expressions), and prefix operators like `sin` and `cos`. 3. **Recursive Structure**: The parser uses recursion to evaluate nested expressions, ensuring that operations respect the order of precedence defined in the grammar. 4. **Math Functions**: The implementation uses Python's `math.sin` and `math.cos` to evaluate the trigonometric functions. ### Example: Running the provided example `evaluate("sin(3 + 2 * 4) - cos(15)")` will yield approximately `-0.240302`, as expected.

Extract Code

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
import math
import re

class Evaluator:
    def __init__(self, expression):
        self.tokens = re.findall(r'\d+|[()\-+*/]|sin|cos', expression)
        self.index = 0

    def parse_expression(self):
        result = self.parse_term()
        while self.index < len(self.tokens) and self.tokens[self.index] in ('+', '-'):
            op = self.tokens[self.index]
            self.index += 1  # consume operator
            right = self.parse_term()
            if op == '+':
                result += right
            elif op == '-':
                result -= right
        return result

    def parse_term(self):
        result = self.parse_factor()
        while self.index < len(self.tokens) and self.tokens[self.index] in ('*', '/'):
            op = self.tokens[self.index]
            self.index += 1  # consume operator
            right = self.parse_factor()
            if op == '*':
                result *= right
            elif op == '/':
                result /= right
        return result

    def parse_factor(self):
        token = self.tokens[self.index]
        if token.isdigit():  # if it's a number
            self.index += 1  # consume number
            return float(token)
        elif token == '(':  # if it's a sub-expression
            self.index += 1  # consume '('
            result = self.parse_expression()
            self.index += 1  # consume ')'
            return result
        elif token in ('sin', 'cos'):  # if it's a prefix operator
            self.index += 1  # consume operator
            self.index += 1  # consume '('
            inner_result = self.parse_expression()
            self.index += 1  # consume ')'
            if token == 'sin':
                return math.sin(inner_result)
            elif token == 'cos':
                return math.cos(inner_result)

def evaluate(expression):
    evaluator = Evaluator(expression)
    return evaluator.parse_expression()

# Example usage
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output: -0.240302

Run Code Interpreter

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
import math
import re

class Evaluator:
    def __init__(self, expression):
        self.tokens = re.findall(r'\d+|[()\-+*/]|sin|cos', expression)
        self.index = 0

    def parse_expression(self):
        result = self.parse_term()
        while self.index < len(self.tokens) and self.tokens[self.index] in ('+', '-'):
            op = self.tokens[self.index]
            self.index += 1  # consume operator
            right = self.parse_term()
            if op == '+':
                result += right
            elif op == '-':
                result -= right
        return result

    def parse_term(self):
        result = self.parse_factor()
        while self.index < len(self.tokens) and self.tokens[self.index] in ('*', '/'):
            op = self.tokens[self.index]
            self.index += 1  # consume operator
            right = self.parse_factor()
            if op == '*':
                result *= right
            elif op == '/':
                result /= right
        return result

    def parse_factor(self):
        token = self.tokens[self.index]
        if token.isdigit():  # if it's a number
            self.index += 1  # consume number
            return float(token)
        elif token == '(':  # if it's a sub-expression
            self.index += 1  # consume '('
            result = self.parse_expression()
            self.index += 1  # consume ')'
            return result
        elif token in ('sin', 'cos'):  # if it's a prefix operator
            self.index += 1  # consume operator
            self.index += 1  # consume '('
            inner_result = self.parse_expression()
            self.index += 1  # consume ')'
            if token == 'sin':
                return math.sin(inner_result)
            elif token == 'cos':
                return math.cos(inner_result)

def evaluate(expression):
    evaluator = Evaluator(expression)
    return evaluator.parse_expression()

# Example usage
result = evaluate("sin(3 + 2 * 4) - cos(15)")
print(result)  # Output: -0.240302





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')
And got the output: -0.24030229369188216 All tests passed

Substring Evaluation

Testing if the previous output contains the string All tests passed: True