CODE-0006 · grok-build-0.1 (default)import re
def tokenize(s):
token_spec = [
('NUMBER', r'\d+\.?\d*|\.\d+'),
('OP', r'[+\-*/]'),
('LPAREN', r'\('),
('RPAREN', r'\)'),
('SKIP', r'\s+'),
]
tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_spec)
tokens = []
last_end = 0
for mo in re.finditer(tok_regex, s):
if mo.start() != last_end:
raise ValueError("Unknown token")
kind = mo.lastgroup
value = mo.group()
if kind == 'NUMBER':
tokens.append(value)
elif kind in ('OP', 'LPAREN', 'RPAREN'):
tokens.append(value)
last_end = mo.end()
if last_end != len(s):
raise ValueError("Unknown token")
return tokens
class Parser:
def __init__(self, tokens):
self.tokens = tokens
self.pos = 0
def parse(self):
if not self.tokens:
raise ValueError("Empty input")
val = self.expr()
if self.pos != len(self.tokens):
raise ValueError("Malformed expression")
return val
def expr(self):
val = self.term()
while self.pos < len(self.tokens) and self.tokens[self.pos] in ('+', '-'):
op = self.tokens[self.pos]
self.pos += 1
right = self.term()
if op == '+':
val = val + right
else:
val = val - right
return val
def term(self):
val = self.factor()
while self.pos < len(self.tokens) and self.tokens[self.pos] in ('*', '/'):
op = self.tokens[self.pos]
self.pos += 1
right = self.factor()
if op == '*':
val = val * right
else:
if right == 0:
raise ValueError("Division by zero")
val = val / right
return val
def factor(self):
if self.pos >= len(self.tokens):
raise ValueError("Malformed expression")
tok = self.tokens[self.pos]
if tok == '(':
self.pos += 1
val = self.expr()
if self.pos >= len(self.tokens) or self.tokens[self.pos] != ')':
raise ValueError("Mismatched parentheses")
self.pos += 1
return val
elif tok == '+':
self.pos += 1
return self.factor()
elif tok == '-':
self.pos += 1
return -self.factor()
else:
try:
num = float(tok)
self.pos += 1
return num
except (ValueError, TypeError):
raise ValueError("Malformed expression")
def eval_expr(s):
tokens = tokenize(s)
parser = Parser(tokens)
result = parser.parse()
if isinstance(result, float) and result.is_integer():
return int(result)
return result