CODE-0006 · gpt-5.4-mini (high)from fractions import Fraction
def eval_expr(s):
def parse_number(num_str):
if num_str.count(".") > 1:
raise ValueError
if "." not in num_str:
return Fraction(int(num_str))
left, right = num_str.split(".", 1)
if left == "" and right == "":
raise ValueError
if left == "":
left = "0"
if right == "":
return Fraction(int(left))
return Fraction(int(left + right), 10 ** len(right))
def tokenize(text):
tokens = []
i = 0
n = len(text)
while i < n:
ch = text[i]
if ch.isspace():
i += 1
continue
if ch in "+-*/()":
tokens.append((ch, None))
i += 1
continue
if ch.isdigit() or ch == ".":
start = i
if ch == ".":
i += 1
if i >= n or not text[i].isdigit():
raise ValueError
saw_dot = ch == "."
while i < n:
ch = text[i]
if ch.isdigit():
i += 1
elif ch == ".":
if saw_dot:
break
saw_dot = True
i += 1
else:
break
tokens.append(("NUMBER", parse_number(text[start:i])))
continue
raise ValueError
return tokens
values = []
ops = []
def precedence(op):
if op in ("u+", "u-"):
return 3
if op in ("*", "/"):
return 2
if op in ("+", "-"):
return 1
return -1
def is_left_assoc(op):
return op in ("+", "-", "*", "/")
def should_pop(top, current):
if top == "(":
return False
pt = precedence(top)
pc = precedence(current)
if pt > pc:
return True
if pt < pc:
return False
return is_left_assoc(current)
def apply_op(op):
if op == "u+" or op == "u-":
if not values:
raise ValueError
a = values.pop()
values.append(a if op == "u+" else -a)
return
if len(values) < 2:
raise ValueError
b = values.pop()
a = values.pop()
if op == "+":
values.append(a + b)
elif op == "-":
values.append(a - b)
elif op == "*":
values.append(a * b)
elif op == "/":
if b == 0:
raise ValueError
values.append(a / b)
else:
raise ValueError
tokens = tokenize(s)
expect_operand = True
for kind, val in tokens:
if kind == "NUMBER":
if not expect_operand:
raise ValueError
values.append(val)
expect_operand = False
elif kind == "(":
if not expect_operand:
raise ValueError
ops.append(kind)
expect_operand = True
elif kind == ")":
if expect_operand:
raise ValueError
while ops and ops[-1] != "(":
apply_op(ops.pop())
if not ops:
raise ValueError
ops.pop()
expect_operand = False
else:
op = kind
if op not in "+-*/":
raise ValueError
if op in "+-" and expect_operand:
op = "u" + op
elif expect_operand:
raise ValueError
while ops and ops[-1] != "(" and should_pop(ops[-1], op):
apply_op(ops.pop())
ops.append(op)
expect_operand = True
if expect_operand:
raise ValueError
while ops:
op = ops.pop()
if op == "(":
raise ValueError
apply_op(op)
if len(values) != 1:
raise ValueError
result = values[0]
return int(result) if result.denominator == 1 else float(result)