-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalculator.py
114 lines (102 loc) · 4.34 KB
/
calculator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
from collections import deque # Fiquei em duvida entre usar uma deque ou uma stack de um pacote externo e usei os 2
from pythonds.basic import Stack
class Calc:
items = deque()
variables = {}
precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3} # Ordem de prioridade das operações
@staticmethod
def calc(user_input):
identifier = user_input.split()[0]
if not identifier.isalpha() and not identifier.isnumeric(): # Checando se o identificador é valido (Para dar assign em uma variavel)
print('Invalid identifier')
return
try:
nums = ' '.join(Calc.variables.get(x) if x.isalpha() else x for x in user_input.split())
print(Calc.postfixToResult(Calc.toPostfix(nums))) # Chamando as funções de calculo geral ja no print()
except TypeError: # excessao para qualquer TypeError é por variavel invalida
print('Unknown variable')
except Exception: # Qualquer outra excessao é criado pelo input do usuario ou manipulação deste
print('Invalid Expression')
@staticmethod
def postfixToResult(postfixExpr): # Calculo da expressão convertida em postfix
operandStack = Stack()
tokenList = postfixExpr.split()
for token in tokenList:
if token.isdigit():
operandStack.push(int(token))
else:
operand2 = operandStack.pop()
operand1 = operandStack.pop()
result = eval(str(operand1) + str(token) + str(operand2))
operandStack.push(result)
return int(operandStack.pop())
@staticmethod
def declare_variable(user_input): # Metodo pra declaração de variavel do usuario
var, eq, val = user_input.partition('=')
var, val = var.strip(), val.strip()
if not var.isalpha():
print('Invalid identifier')
return
if not (val.isalpha() or val.isnumeric()) or\
val.isalpha() and not Calc.variables.get(val):
print('Invalid assignment')
return
Calc.variables[var] = val if val.isnumeric() else Calc.variables.get(val)
@staticmethod
def toPostfix(infixexpr): # Conversão da expressão entrada pelo usuario para PostFix
prec = {"^": 4, "*": 3, "/": 3, "+": 2, "-": 2, "(": 1}
opStack = Stack()
postfixList = []
temporary = infixexpr.split()
tokenList = []
for i in temporary: # O Split só separa por 1 argumento e sendo ele " " eu tive que filtrar melhor a lista
if "(" in i and i != "(":
tokenList.append("(")
tokenList.append(i.strip("("))
elif ")" in i and i != ")":
tokenList.append(i.strip(")"))
tokenList.append(")")
elif "*" in i and len(i) > 1:
tokenList.append(",.;")
elif "/" in i and len(i) > 1:
tokenList.append(",.;")
else:
tokenList.append(i)
for token in tokenList:
if token.isdigit():
postfixList.append(token)
elif token.isalpha():
postfixList.append(Calc.variables[token])
elif token == '(':
opStack.push(token)
elif token == ')':
topToken = opStack.pop()
while topToken != '(':
postfixList.append(topToken)
topToken = opStack.pop()
else:
while (not opStack.isEmpty()) and (prec[opStack.peek()] >= prec[token]):
postfixList.append(opStack.pop())
opStack.push(token)
while not opStack.isEmpty():
postfixList.append(opStack.pop())
return " ".join(postfixList)
def main(): # main que sustenta o programa e aceita os /comands
calc = Calc()
while True:
user_input = input()
if user_input == '/exit':
print('Bye!')
exit()
elif user_input == '/help':
print('A bit of a smart calculator')
continue
elif user_input.startswith('/'):
print('Unknown command')
continue
elif user_input.find('=') != -1:
calc.declare_variable(user_input)
elif user_input:
calc.calc(user_input)
if __name__ == '__main__':
main()