CODE-0006 · grok-4.3 (default)import re
class Parser:
def __init__(self, s):
self.tokens = self.tokenize(s)
self.pos = 0
def tokenize(self, s):
if not s or not s.strip():
raise ValueError("empty")
pattern = r'\s*((\d+\.?\d*|\.\d+)|[+\-*/()])\s*'
tokens = []
last_end = 0
for m in re.finditer(pattern, s):
if m.start() != last_end:
raise ValueError("invalid")
last_end = m.end()
token = m.group(1)
tokens.append(token)
if last_end != len(s):
raise ValueError("invalid")
if not tokens:
raise ValueError("empty")
return tokens
def peek(self):
if self.pos < len(self.tokens):
return self.tokens[self.pos]
return None
def consume(self):
tok = self.peek()
self.pos += 1
return tok
def parse(self):
val = self.expr()
if self.pos != len(self.tokens):
raise ValueError("extra")
if isinstance(val, float) and val.is_integer():
return int(val)
return val
def expr(self):
val = self.term()
while self.peek() in ('+', '-'):
op = self.consume()
right = self.term()
if op == '+':
val = val + right
else:
val = val - right
return val
def term(self):
val = self.factor()
while self.peek() in ('*', '/'):
op = self.consume()
right = self.factor()
if op == '*':
val = val * right
else:
if right == 0:
raise ValueError("div0")
val = val / right
return val
def factor(self):
tok = self.peek()
if tok is None:
raise ValueError("dangling")
if tok == '(':
self.consume()
val = self.expr()
if self.consume() != ')':
raise ValueError("mismatch")
return val
elif tok in ('+', '-'):
self.consume()
val = self.factor()
return val if tok == '+' else -val
elif re.match(r'^[\d.]', tok):
self.consume()
try:
return float(tok)
except ValueError:
raise ValueError("badnum")
else:
raise ValueError("unknown")
def eval_expr(s):
try:
p = Parser(s)
return p.parse()
except Exception:
raise ValueError