C++로 만든 후위 표기식 계산기입니다.
    네이버나 구글에 C++ 후위 표기식으로 검색해보면 죄다 파일만 cpp지 C 스타일로 만들어놔서 "이게 뭐야?"싶은 마음에 만들었습니다.
    짧거나 긴 식들을 넣어서 계산 시켜본 결과 네이버 계산기와 결과가 똑같았기에 계산은 정확합니다.
    음수와 양수 표기, 제곱도 지원합니다. 식에 문제가 있을 때의 예외 처리도 돼있습니다.
    위의 모든 처리가 다 돼있다 보니 일반적으로 돌아다니는 후위 표기식 계산기보다는 코드가 조금 더 복잡합니다.
    다 만들고 보니 코드가 좀 어지 로운데다 좀 더 깔끔하고 효율적으로 수정할 여지가 있는 것 같네요.
    개인적으로 좀 마음에 안드네요. 시간이 나면 좀 더 다듬어서 수정본을 올려봐야겠습니다.
    코드에 대한 질문이나 의견은 댓글로 남겨주세요.


    Postfix.zip




    stdfx.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #pragma once
     
    #include "targetver.h"
     
    #include <iostream>
    #include <string>
    #include <tuple>
    #include <stack>
    #include <sstream>
    #include <cmath>
     
    #include "Calculator.h"
    cs


    Calculator.h

    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
    #pragma once
     
    template <class T>
    constexpr auto ToUType(T enumerator) noexcept
    {
        return static_cast<std::underlying_type_t<T>>(enumerator);
    }
     
    class Calculator
    {
    private :
        enum class Symbol : char
        { 
            None = 0,
            LeftParenthesis = '(', RightParenthesis = ')',
            Plus     = '+',  Minus = '-',
            Multiply = '*', Divide = '/',
            Square   = '^',
            Space    = ' ',
        };
     
        static const std::string kNumbers;
        static const std::string kSymbols;
        static const std::string kSpecialSymbol;
     
        static std::stack<char> m_stack;
     
    private :
        static const size_t GetPriority(char cipher);
     
    public :
        Calculator() = delete;
     
        static const std::tuple<boolstd::string> InfixToPostfix(const std::string& infix);
        static const std::tuple<booldoublestd::string> Calculate(const std::string& equation);
    };
    cs


    Calculator.cpp

    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
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    #include "stdafx.h"
     
    const std::string Calculator::kNumbers         = "1234567890.";
    const std::string Calculator::kSymbols         = "()+-*/^";
    const std::string Calculator::kSpecialSymbol = "+-";
     
    std::stack<char> Calculator::m_stack;
     
    const size_t Calculator::GetPriority(char cipher)
    {
        int priority = 0;
        const Symbol symbol = static_cast<const Symbol>(cipher);
        
        switch (symbol)
        {
        case Symbol::Square :
            priority = 0;
            break;
     
        case Symbol::Multiply :
        case Symbol::Divide :
            priority = 1;
            break;
     
        case Symbol::Plus :
        case Symbol::Minus:
            priority = 2;
            break;
     
        case Symbol::LeftParenthesis:
            priority = 3;
            break;
     
        default :
            break;
        }
     
        return priority;
    }
     
    const std::tuple<boolstd::string> Calculator::InfixToPostfix(const std::string& infix)
    {
        std::stack<char> stack;
        std::string         postfix;
        char chiper;
     
        for (int i = 0; i < infix.length(); i++)
        {
            chiper = infix[i];
     
            if (kNumbers.find(chiper) != std::string::npos)
            {
                postfix += chiper;
                continue;
            }
            else if (kSpecialSymbol.find(chiper) != std::string::npos)
            {
                if ((i == 0||
                    ((kSymbols.find(infix[i - 1]) != std::string::npos) &&
                    (kNumbers.find(infix[i + 1]) != std::string::npos)))
                {
                    postfix += chiper;
                    continue;
                }
            }
            else if (kSymbols.find(chiper) == std::string::npos)
                return std::make_tuple(falsestd::string("식이 잘못됐습니다."));
     
            if (chiper == ToUType(Symbol::LeftParenthesis))
                m_stack.emplace(chiper);
            else if (chiper == ToUType(Symbol::RightParenthesis))
            {
                while (!m_stack.empty() && (m_stack.top() != ToUType(Symbol::LeftParenthesis)))
                {
                    postfix += ToUType(Symbol::Space);
                    postfix += m_stack.top();
                    m_stack.pop();
                }
     
                if (m_stack.empty())
                    return std::make_tuple(falsestd::string("식이 잘못됐습니다."));
                else
                    m_stack.pop();
            }
            else
            {
                postfix += ToUType(Symbol::Space);
                while (!m_stack.empty() && (GetPriority(m_stack.top()) <= GetPriority(chiper)))
                {
                    postfix += m_stack.top();
                    postfix += ToUType(Symbol::Space);
                    m_stack.pop();
                }
                m_stack.emplace(chiper);
            }
        }
     
        while (!m_stack.empty())
        {
            if (m_stack.top() == ToUType(Symbol::LeftParenthesis))
                return std::make_tuple(false"식이 잘못됐습니다.");
            else
            {
                postfix += ToUType(Symbol::Space);
                postfix += m_stack.top();
                m_stack.pop();
            }
        }
     
        return std::make_tuple(true, postfix);
    }
     
    const std::tuple<booldoublestd::string> Calculator::Calculate(const std::string& equation)
    {
        auto inToPostResult = InfixToPostfix(equation);
        if (!std::get<0>(inToPostResult))
            return std::make_tuple(std::get<0>(inToPostResult), 0std::get<1>(inToPostResult));
     
        std::stack<double> stack;
        std::string chiper = "";
        std::stringstream equationStream(std::get<1>(inToPostResult));
        std::stringstream numberStream;
     
        double tempNum = 0;
        double rNum       = 0;
        double lNum    = 0;
     
        while (!equationStream.eof())
        {
            equationStream >> chiper;
            if (kSymbols.find(chiper) == std::string::npos)
            {
                numberStream.str(chiper);
                numberStream.clear();
                numberStream >> tempNum;
                stack.emplace(tempNum);
            }
            else
            {
                if (stack.size() < 2)
                    return std::make_tuple(false0std::string("식이 잘못됐습니다."));
     
                rNum = stack.top();
                stack.pop();
                lNum = stack.top();
                stack.pop();
     
                Symbol symbol = static_cast<const Symbol>(chiper[0]);
                switch (symbol)
                {
                case Symbol::Plus :
                    stack.emplace(lNum + rNum);
                    break;
     
                case Symbol::Minus :
                    stack.emplace(lNum - rNum);
                    break;
     
                case Symbol::Multiply :
                    stack.emplace(lNum * rNum);
                    break;
     
                case Symbol::Divide :
                    stack.emplace(lNum / rNum);
                    break;
     
                case Symbol::Square :
                    stack.emplace(pow(lNum, rNum));
                    break;
     
                default:
                    break;
                }
            }
        }
     
        return std::make_tuple(truestack.top(), std::string());
    }
    cs


    Main.cpp

    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
    #include "stdafx.h"
     
     
    int main()
    {
        while (true)
        {
            std::string infix = "";
     
            std::cout << "수식을 입력해주세요 : ";
            std::cin >> infix;
     
            auto resultTuple = Calculator::Calculate(infix);
            if (std::get<0>(resultTuple))
            {
                double        result = std::move(std::get<1>(resultTuple));
                std::string postfix = std::move(std::get<1>(Calculator::InfixToPostfix(infix)));
     
                std::cout << "Infix : " << infix << std::endl;
                std::cout << "Postfix : " << postfix << std::endl;
                std::cout << "Result : " << result << std::endl << std::endl;
            }
            else
                std::cout << std::get<2>(resultTuple) << std::endl << std::endl;
        }
        return 0;
    cs


    Posted by Muramasa