Select Git revision
-
Wen Yao Jin authoredWen Yao Jin authored
calculator.py 2.27 KiB
"""
This Calculator holds the logic for the calculator.
"""
from calculator.operators import Operator, STANDARD_OPERATORS
from calculator.expression import Term, Expression, TermExpression, OperatorExpression
class Calculator:
"""
Calculator class is a simple calculator that can parse and evaluate expressions of the form:
expression ::= term | expression operator expression
operator ::= + | - | * | /
with the usual precedence rules.
"""
def __init__(self, operators=None):
if operators is None:
operators = STANDARD_OPERATORS
self.operators = operators
def tokenize(self, line: str):
"""
Tokenize an expression into a list of tokens.
"""
tokens = []
for token in line.split():
if token in self.operators:
tokens.append(self.operators[token])
else:
try:
if int(token) == float(token):
tokens.append(int(token))
except ValueError as exc:
raise ValueError(f"Invalid token {token}") from exc
return tokens
def parse(self, tokens) -> Expression:
"""
Parse a list of tokens into an ordered expression.
"""
if not tokens:
raise ValueError("Empty expression")
if len(tokens) == 1:
if isinstance(tokens[0], Term):
return TermExpression(tokens[0])
raise ValueError(f"Expected a term, got {tokens[0]}")
if len(tokens) == 2:
raise ValueError("Invalid expression")
# Find the rightest operator with the lowest precedence
operator = None
for i, token in enumerate(tokens):
if isinstance(token, Operator):
if operator is None or token.precedence <= operator.precedence:
operator = token
operator_index = i
# Split the expression into two parts
left = tokens[:operator_index]
right = tokens[operator_index + 1:]
# Parse the left and right parts recursively
return OperatorExpression(operator, self.parse(left), self.parse(right))
def __call__(self, expression: str) -> Term:
return self.parse(self.tokenize(expression))()