Skip to content

Instantly share code, notes, and snippets.

@SealtielFreak
Last active April 6, 2024 00:17
Show Gist options
  • Save SealtielFreak/8a8afd9506c0aa72e0a2c52b881ea794 to your computer and use it in GitHub Desktop.
Save SealtielFreak/8a8afd9506c0aa72e0a2c52b881ea794 to your computer and use it in GitHub Desktop.
Scientific calculator
import collections
import enum
NUMBERS = "".join(map(str, range(10)))
FLOAT = ".,"
OPERATOR = "+-*/"
PARENTHESIS = "()"
class TokenType(enum.Enum):
UNKNOWN = 0
NUMBER = 1
OPERATOR = 2
PARENTHESIS = 3
def isint(_value: str) -> bool:
return _value.isnumeric()
def isfloat(_value: str) -> bool:
try:
float(_value)
except ValueError:
return False
return True
class Token:
def __init__(self, _str: str, type_token: TokenType):
self.__str = _str
self.__type_token = type_token
@property
def number(self) -> float | int:
if isint(self.value):
return int(self.value)
elif isfloat(self.value):
return float(self.value)
return 0
@property
def value(self):
return self.__str
@property
def type(self):
return self.__type_token
def __str__(self):
return str(self.value)
def __eq__(self, other):
if isinstance(other, TokenType):
return self.type == other
return False
@staticmethod
def create_from(token: str):
if isint(token) or isfloat(token):
return Token(token, TokenType.NUMBER)
elif token in OPERATOR:
return Token(token, TokenType.OPERATOR)
elif token in PARENTHESIS:
return Token(token, TokenType.PARENTHESIS)
class Tokens:
def __init__(self):
self.__deque = collections.deque()
def append(self, token: Token):
self.__deque.append(token)
def __iter__(self):
return iter(self.__deque)
def clean(self):
self.__deque.clear()
class Calculator:
def __init__(self):
self.__tokens = Tokens()
@property
def tokens(self):
return self.__tokens
def lex(self, _str: str):
def lex(deque: collections.deque[str], str_token=""):
if len(deque) == 0:
if len(str_token) != 0:
self.__tokens.append(Token.create_from(str_token))
return self.__tokens
token = deque.popleft()
while token == " ":
token = deque.popleft()
if token in NUMBERS + FLOAT:
self.__tokens = lex(deque, str_token + str(token))
else:
if len(str_token) != 0:
self.__tokens.append(Token.create_from(str_token))
if token in OPERATOR + PARENTHESIS:
self.__tokens.append(Token.create_from(token))
self.__tokens = lex(deque)
else:
self.__tokens.append(Token.create_from(str_token))
return self.__tokens
self.__tokens.clean()
self.__tokens = lex(
collections.deque(_str)
)
def eval(self):
def eval(tokens: collections.deque, value=0):
if len(tokens) == 0:
return value
token = tokens.popleft()
if token == TokenType.PARENTHESIS:
return eval(tokens, value)
elif token == TokenType.OPERATOR:
match token.value:
case '+':
value += eval(tokens, value)
case '-':
value -= eval(tokens, value)
case '*':
value *= eval(tokens, value)
case '/':
value /= eval(tokens, value)
elif token == TokenType.NUMBER:
value = eval(tokens, token.number)
return value
return eval(collections.deque(self.__tokens))
if __name__ == "__main__":
calc = Calculator()
calc.lex("1/3+3")
print(calc.eval())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment