CODE-0006 · claude-fable-5 (high)
import re

_TOKEN_RE = re.compile(r'\s*(?:(\d+\.\d*|\.\d+|\d+)|([+\-*/()])|(\S))')


def _tokenize(s):
    tokens = []
    pos = 0
    while pos < len(s):
        m = _TOKEN_RE.match(s, pos)
        if not m:
            break
        num, op, bad = m.group(1), m.group(2), m.group(3)
        if bad is not None:
            raise ValueError("unknown token: %r" % bad)
        if num is not None:
            if '.' in num:
                tokens.append(('num', float(num)))
            else:
                tokens.append(('num', int(num)))
        else:
            tokens.append(('op', op))
        pos = m.end()
    return tokens


class _Parser:
    def __init__(self, tokens):
        self.tokens = tokens
        self.i = 0

    def peek(self):
        if self.i < len(self.tokens):
            return self.tokens[self.i]
        return (None, None)

    def next(self):
        tok = self.peek()
        self.i += 1
        return tok

    def parse_expr(self):
        value = self.parse_term()
        while True:
            kind, val = self.peek()
            if kind == 'op' and val in ('+', '-'):
                self.next()
                rhs = self.parse_term()
                if val == '+':
                    value = value + rhs
                else:
                    value = value - rhs
            else:
                return value

    def parse_term(self):
        value = self.parse_factor()
        while True:
            kind, val = self.peek()
            if kind == 'op' and val in ('*', '/'):
                self.next()
                rhs = self.parse_factor()
                if val == '*':
                    value = value * rhs
                else:
                    if rhs == 0:
                        raise ValueError("division by zero")
                    value = value / rhs
            else:
                return value

    def parse_factor(self):
        kind, val = self.peek()
        if kind == 'op' and val in ('+', '-'):
            self.next()
            operand = self.parse_factor()
            return operand if val == '+' else -operand
        return self.parse_primary()

    def parse_primary(self):
        kind, val = self.next()
        if kind == 'num':
            return val
        if kind == 'op' and val == '(':
            value = self.parse_expr()
            k2, v2 = self.next()
            if k2 != 'op' or v2 != ')':
                raise ValueError("mismatched parentheses")
            return value
        raise ValueError("malformed expression")


def eval_expr(s):
    tokens = _tokenize(s)
    if not tokens:
        raise ValueError("empty expression")
    parser = _Parser(tokens)
    result = parser.parse_expr()
    if parser.i != len(tokens):
        raise ValueError("unexpected token")
    if isinstance(result, float) and result.is_integer():
        return int(result)
    return result