Domains
        CharList = Char *
        
        Operator = plus; minus; multiply; divide
        Bracket = left; right
        Token = identifier(Char); operator(Operator); bracket(Bracket)
        TokenList = Token *
        
        Operand = variable(Char); operation(Operation)
        OperationType = addition; subtraction; multiplication; division
        Operation = operation(OperationType, Operand, Operand)
Predicates
        StringToCharList(String, Charlist)
        SkipSpaces(CharList, CharList)
        IsLetter(Char)
        
        IdentifyToken(Char, Token)
        CharListToTokenList(CharList, TokenList)
        
        IsLowPriority(OperationType)
        TokenListToBracket(TokenList, Bracket, TokenList)
        TokenListToOperand(TokenList, Operand, TokenList)
        TokenListToOperationType(TokenList, OperationType, TokenList)
        TokenListToPrioritySequence(Operand, TokenList, Operand, TokenList)
        TokenListToPriority(TokenList, Operand, TokenList)
        TokenListToExpressionSequence(Operand, TokenList, Operand, TokenList)
        TokenListToExpression(TokenList, Operand, TokenList)
        
        OperandToString(Operand, String)
        OperationTypeToString(OperationType, String)
        OperationToString(Operation, String)
        Calculator()
Clauses
        StringToCharList("", []) :- !.
        StringToCharList(S, [H | T]) :-
                frontchar(S, H, ST),
                StringToCharList(ST, T).
        SkipSpaces([], []) :- !.
        SkipSpaces([C | T1], T2) :- C = ' ', SkipSpaces(T1, T2), !.
        SkipSpaces([C | T1], [C | T2]) :- SkipSpaces(T1, T2).
        
        IsLetter(C) :- C >= 'a', C <= 'z', !.
        IsLetter(C) :- C >= 'A', C <= 'Z'.
        
        IdentifyToken(C, identifier(C)) :- IsLetter(C), !.
        IdentifyToken('+', operator(plus)).
        IdentifyToken('-', operator(minus)).
        IdentifyToken('*', operator(multiply)).
        IdentifyToken('/', operator(divide)).
        IdentifyToken('(', bracket(left)).
        IdentifyToken(')', bracket(right)).
        
        CharListToTokenList([], []).
        CharListToTokenList([CLH | CLT], [TLH | TLT]) :- IdentifyToken(CLH, TLH), CharListToTokenList(CLT, TLT).
        
        IsLowPriority(addition).
        IsLowPriority(subtraction).
        
        TokenListToBracket([bracket(B) | TLT], B, TLT).
        
        TokenListToOperand([identifier(C) | TLT], variable(C), TLT) :- !.
        TokenListToOperand(TL1, O, TL) :-
                TokenListToBracket(TL1, left, TL2),
                TokenListToExpression(TL2, O, TL3),
                TokenListToBracket(TL3, right, TL).
        
        TokenListToOperationType([operator(plus) | TLT], addition, TLT).
        TokenListToOperationType([operator(minus) | TLT], subtraction, TLT).
        TokenListToOperationType([operator(multiply) | TLT], multiplication, TLT).
        TokenListToOperationType([operator(divide) | TLT], division, TLT).
        
        TokenListToPrioritySequence(O1, TL, O, TLT) :-
                TokenListToOperationType(TL, OT, TLT1),
                not(IsLowPriority(OT)),
                TokenListToOperand(TLT1, O2, TLT2),
                TokenListToPrioritySequence(operation(operation(OT, O1, O2)), TLT2, O, TLT), !.
        TokenListToPrioritySequence(O, TL, O, TL).
        
        TokenListToPriority(TL, O, TLT) :-
                TokenListToOperand(TL, O1, TLT1),
                TokenListToPrioritySequence(O1, TLT1, O, TLT), !.
        TokenListToPriority(TL, O, TLT) :- TokenListToOperand(TL, O, TLT).
        
        TokenListToExpressionSequence(O1, TL, O, TLT) :-
                TokenListToOperationType(TL, OT, TLT1),
                IsLowPriority(OT),
                TokenListToPriority(TLT1, O2, TLT2),
                TokenListToExpressionSequence(operation(operation(OT, O1, O2)), TLT2, O, TLT), !.
        TokenListToExpressionSequence(O, TL, O, TL).
                        
        TokenListToExpression(TL, O, TLT) :-
                TokenListToPriority(TL, O1, TLT1),
                TokenListToExpressionSequence(O1, TLT1, O, TLT), !.
        TokenListToExpression(TL, O, TLT) :-
                TokenListToPriority(TL, O, TLT).
        
        OperandToString(variable(C), S) :- str_char(S, C), !.
        OperandToString(operation(O), S) :- OperationToString(O, S).
        
        OperationTypeToString(addition, "ADD").
        OperationTypeToString(subtraction, "SUB").
        OperationTypeToString(multiplication, "MUL").
        OperationTypeToString(division, "DIV").
        
        OperationToString(operation(OT, O1, O2), S) :-
                OperationTypeToString(OT, SOT),
                OperandToString(O1, SO1),
                OperandToString(O2, SO2),
                format(S, "%(%,%)", SOT, SO1, SO2).
        Calculator() :-
                readln(IS),
                StringToCharList(IS, CL),
                SkipSpaces(CL, CL_WS),
                CharListToTokenList(Cl_WS, TL),
                TokenListToExpression(TL, O, []),
                OperandToString(O, OS),
                write(OS), nl,
                readchar(_).
Goal
        Calculator().