予鈴

アウトプットとメモ書きの中間みたいな記事がたくさん出ます。

数式(?)を逆ポーランド記法に変換して計算する。

面白そうだな〜と思っていたので、実装しました。
要するに電卓です。
10+4*(10/2+7)/2+2+(3+(2+2)) ←こういうのを計算してくれます。負数と小数点には対応してません。
楽しかったので自己満足記事です。verifyはしてないので、使用は自己責任でお願いします。
バグがあれば教えてください。


#include <iostream>
#include <string>
#include <vector>
#include <stack>

using namespace std;

bool isOp(string c){return c == "+" or c == "*" or c == "-" or c == "/" or c == ")" or c == "("; }
bool isOp(char c){return c == '+' or c == '*' or c == '-' or c == '/';}
bool isNum(char c){return '0' <= c and c <= '9';}
bool isNum(string s){return !(isOp(s));}

auto  parser(string s){
    string num = "";
    vector<string>token;
    for(auto c : s){
        if(isNum(c)){
            num.push_back(c);
        } else {
            if(not num.empty()){
                token.push_back(num);
                num.clear();
            }
            token.push_back(string() + c);
        }
    }
    if(not num.empty()) token.push_back(num);
    return token;
}
auto OperandPriority(string lower,string higher){
    return ((lower == "+" or lower == "-") and (higher == "*" or higher == "/")) ;
}
auto constructRPN(vector<string>token){
    //逆ポーランド記法の文字列配列を生成。
    stack<string>st;
    vector<string> buffer;
    for(auto str : token){
        if(isNum(str)){
            buffer.push_back(str);
        } else {
            if(str  == ")"){
                while(st.top() != "("){
                    buffer.push_back (st.top());
                    st.pop();
                }
                assert(st.top() == "(");
                st.pop();
            } else if(str == "(" or st.empty()){
                st.push(str);
            } else if(OperandPriority(st.top(),str)){
                st.push(str);
            } else {
                while(not st.empty() and st.top() != "(" and !OperandPriority(st.top(),str)){
                    buffer.push_back(st.top());
                    st.pop();
                }
                st.push(str);
            }
        }
    }
    while(not st.empty())buffer.push_back(st.top()),st.pop();
    return buffer;
}
int execute(vector<string> l){
    stack<int>num;
    for(auto s: l){
        if(isNum(s)){
            num.push(stoi(s));
        } else {
            int res = 0;
            int val1 = num.top();num.pop();
            int val2 = num.top();num.pop();
            char c = s.front();
            switch (c) {
                case '+':
                    res =  val1 + val2;
                    break;
                case '*':
                    res =  val2 * val1;
                    break;
                case '-':
                    res =  val2 - val1;
                    break;
                default:
                    res =  val2 / val1;
                    break;
            }
            num.push(res);
        }
    }
    return num.top();
}
int main() {
    string s; cin >> s;
    auto token = parser(s);
    auto Literal =  constructRPN(token);
    for(auto s: Literal)cout << s; cout << endl;
    cout << execute(Literal) << endl;
}