NUMBER, OPER, NONE = "NUMBER", "OPER", "NONE" VALID_OPERS = ["+", "-", "*", "/", "^"] class Token(object): def __init__(self, type, value): self.type = type self.value = value def __str__(self): return "{} {}".format(self.type, self.value) # try to build a Token infering the type of the input def build_token(tok): type = NUMBER try: value = float(tok) except ValueError: try: value = int(tok) except ValueError: if tok not in VALID_OPERS: raise Exception("UNRECOGNIZED TOKEN '{}'".format(tok)) value = tok type = OPER return Token(type, value) # Lexer def get_tokens(stream): string = stream tok = "" for c in string: if c in VALID_OPERS: yield build_token(tok.strip()) yield build_token(c) tok = "" else: tok += c if tok.strip(): yield build_token(tok.strip()) return Token(NONE,None) from math import pow oper = { '+' : lambda x,y: x+y, '-' : lambda x,y: x-y, '*' : lambda x,y: x*y, '/' : lambda x,y: x/y, '^' : lambda x,y: pow(x,y) } # Parser class Parser(object): def __init__(self, string): self.string = string def parse(self): gen = get_tokens(self.string) first_term = next(gen) result = first_term.value try: while True: operator = next(gen) next_term = next(gen) result = oper[operator.value](first_term.value, next_term.value) first_term = build_token(str(result)) except StopIteration: return result return None def main(): while True: try: text = input('calc> ') except IOError: break if not text: continue parser = Parser(text) result = parser.parse() print(result) if __name__ == "__main__": main()