"""Calculator, worte in AST in python
"""
from ast import literal_eval
from math import inf
def ADD(x, y):
    return str(literal_eval(x) + literal_eval(y))
def SUB(x, y):
    return str(literal_eval(x) - literal_eval(y))
def POW(x, y):
    return str(literal_eval(x) ** literal_eval(y))
def MUL(x, y):
    return str(literal_eval(x) * literal_eval(y))
def DIV(x, y):
    return str(literal_eval(x) / literal_eval(y))
operations = {
    
    '+': [1, ADD],
    '-': [1, SUB],
    '*': [2, MUL],
    '/': [2, DIV],
    '^': [3, POW]
}
parens = {
    '(': 1,
    ')': -1
}
class TreeNode(object):
    __slots__ = ('val', 'left', 'right')
    def __init__(self, val=None, left=None, right=None):
        self.val, self.left, self.right = val, left, right
    def __repr__(self):
        left, right = ' ', ' '
        if self.left is not None:
            left = repr(self.left) + ' <- '
        if self.right is not None:
            right = ' -> ' + repr(self.right)
        return '(' + left + repr(self.val) + right + ')'
def lexer(string):
    
    result = list()
    if not string:
        return result
    head, tail = 0, 0  
    numeric = False  
    while tail < len(string):
        
        if string[tail] in {'+', '-'} and numeric:
            numeric = False
            result.append(('SYMB', string[tail]))
        
        elif (string[tail].isdecimal() or string[tail] == '.') or (string[tail] in {'+', '-'} and not numeric):
            numeric = True
            head = tail
            tail += 1
            while tail < len(string) and (string[tail].isdecimal() or string[tail] == '.'):
                tail += 1
            num = string[head:tail]
            if num in {'+', '-'}:
                num += '1'
            result.append(('NUM', num))
            tail -= 1
        
        elif string[tail] in {'*', '/', '^', '(', ')'}:
            symb = 'PAREN' if string[tail] in parens else 'SYMB'
            if numeric and string[tail] == '(':
                result.append(('SYMB', '*'))
            numeric = True if string[tail] == ')' else False
            result.append((symb, string[tail]))
        tail += 1
    return result
def parser(tokens):
    
    remove_enclosing_parans_flag = True
    while remove_enclosing_parans_flag:
        if len(tokens) == 0:
            return
        remove_enclosing_parans_flag = remove_enclosing_parans_flag and (tokens[0][1] == '(' and tokens[-1][1] == ')')
        depth = 0
        for TYPE, TOKEN in tokens[:-1]:
            depth += parens.get(TOKEN, 0)
            if depth == 0:
                remove_enclosing_parans_flag = remove_enclosing_parans_flag and (depth != 0)
                break
        if remove_enclosing_parans_flag:
            tokens = tokens[1:-1]
    depth = 0
    min_priority = inf
    min_priority_index = None
    
    for i, (TYPE, TOKEN) in enumerate(tokens):
        
        if TYPE == 'PAREN':
            depth += parens[TOKEN]
        elif TYPE == 'SYMB' and depth == 0:
            if operations[TOKEN][0] < min_priority:
                min_priority_index, min_priority = i, operations[TOKEN][0]
    if min_priority_index is None:
        if tokens[0][1] in parens or tokens[0][1] in operations:
            return
        else:
            return TreeNode(tokens[0][1])
    left = parser(tokens[:min_priority_index])
    right = parser(tokens[min_priority_index + 1:])
    return TreeNode(tokens[min_priority_index][1], left, right)
def solve(ast_root, DEBUG=False):
    """Traverse the AST and do calculation
    """
    if ast_root is None:
        raise ValueError('AST cannot be None')
    if ast_root.left is ast_root.right is None:
        return ast_root.val
    else:
        if DEBUG:
            left = solve(ast_root.left, DEBUG)
            right = solve(ast_root.right, DEBUG)
            result = operations[ast_root.val][1](left, right)
            print('Calculating:', ast_root.val, ast_root.left, '|', ast_root.right, '=>', left, ast_root.val, right, '=', result)
            return result
        else:
            return operations[ast_root.val][1](solve(ast_root.left), solve(ast_root.right))
def calculator(string):
    return solve(parser(lexer(string)))
def main():
    DEBUG = False
    prompt = ['Expression > ', 'DEBUG > ']
    try:
        while 1:
            string = input(prompt[DEBUG])
            if string.upper().strip() == 'DEBUG':
                DEBUG = not DEBUG
                continue
            if DEBUG:
                print('Atoms      :', list(zip(*lexer(string)))[1])
                print('Tree       :', repr(parser(lexer(string))))
                print('PyResult   :', eval(string.replace('^', '**')))
                print('MyResult   :', solve(parser(lexer(string)), DEBUG))
            else:
                print('Result:', calculator(string))
    except (EOFError, KeyboardInterrupt):
        exit()
if __name__ == '__main__':
    main()