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