CODE-0006 · deepseek-v4-flash (default)def tokenize(s):
"""Generate tokens from the expression string."""
i = 0
n = len(s)
while i < n:
c = s[i]
if c.isspace():
i += 1
continue
if c.isdigit() or c == '.':
start = i
has_dot = False
i += 1
while i < n and (s[i].isdigit() or (s[i] == '.' and not has_dot)):
if s[i] == '.':
has_dot = True
i += 1
num_str = s[start:i]
if has_dot:
yield ('num', float(num_str))
else:
yield ('num', int(num_str))
continue
if c in '+-*/':
yield ('op', c)
i += 1
continue
if c == '(':
yield ('(', None)
i += 1
continue
if c == ')':
yield (')', None)
i += 1
continue
raise ValueError(f"unknown token: {c!r}")
def parse_expr(tokens, idx):
left, idx = parse_term(tokens, idx)
while idx < len(tokens) and tokens[idx][0] == 'op' and tokens[idx][1] in '+-':
op = tokens[idx][1]
idx += 1
right, idx = parse_term(tokens, idx)
if op == '+':
left += right
else:
left -= right
return left, idx
def parse_term(tokens, idx):
left, idx = parse_factor(tokens, idx)
while idx < len(tokens) and tokens[idx][0] == 'op' and tokens[idx][1] in '*/':
op = tokens[idx][1]
idx += 1
right, idx = parse_factor(tokens, idx)
if op == '*':
left *= right
else:
if isinstance(right, (int, float)) and right == 0:
raise ValueError("division by zero")
left /= right
return left, idx
def parse_factor(tokens, idx):
if idx >= len(tokens):
raise ValueError("unexpected end of expression")
token = tokens[idx]
if token[0] == 'op' and token[1] in '+-':
op = token[1]
idx += 1
inner, idx = parse_factor(tokens, idx)
return -inner if op == '-' else inner, idx
return parse_atom(tokens, idx)
def parse_atom(tokens, idx):
if idx >= len(tokens):
raise ValueError("unexpected end of expression")
token = tokens[idx]
if token[0] == 'num':
return token[1], idx + 1
if token[0] == '(':
idx += 1
inner, idx = parse_expr(tokens, idx)
if idx >= len(tokens) or tokens[idx][0] != ')':
raise ValueError("missing closing parenthesis")
idx += 1
return inner, idx
raise ValueError("expected number or '('")
def eval_expr(s):
"""Evaluate an arithmetic expression string."""
tokens = list(tokenize(s))
if not tokens:
raise ValueError("empty expression")
result, idx = parse_expr(tokens, 0)
if idx != len(tokens):
raise ValueError("unexpected trailing tokens")
# Return exact integer when possible
if isinstance(result, float) and result.is_integer():
return int(result)
return result