逆ポーランド記法計算機書いてみた
結構前からちょくちょくいじってて、
昨日はこればっかやってた。
というわけで貼りつけたいんだけど、
どうやらGistは1つのGistに複数ファイルがあると
アルファベット順的に先頭のファイルしか貼りつけができないらしい。
これのために新しいGistを作るのもアレなので
直接はてダに貼りつける。
(っていってもGistは気軽に作れるのが良いところだと思ってるけど)
boost使ったりしてみた(というか途中使わざるを得なかったり・・・orz)
あとでパーサの部分をBoost.Spiritを使って書いてみるかも。
/* vim:ts=4:sw=4:sts=0:tw=0:set et: */ #include <iostream> #include <cstdlib> #include <string> #include <map> #include <stack> #include <cassert> #include <functional> #include <boost/function.hpp> #include <boost/lexical_cast.hpp> using namespace std; using namespace boost; template <class Digit> class RPN { typedef string::iterator InputIterator; typedef map< string, function<Digit (Digit, Digit)> > FuncMap; typedef stack<string> Stack; public: RPN() { funcmap["+"] = plus<Digit>(); funcmap["-"] = minus<Digit>(); funcmap["*"] = multiplies<Digit>(); funcmap["/"] = divides<Digit>(); } public: Digit eval(string& line) { while (! stk.empty()) stk.pop(); first = line.begin(); last = line.end(); return parse(); } Digit parse(); private: string get_word(); void call_stack() { string op, n, m; cerr << "* pop " << stk.top() << endl; op = stk.top(); stk.pop(); if (is_op(op)) { cerr << "* pop " << stk.top() << endl; m = stk.top(); stk.pop(); cerr << "* pop " << stk.top() << endl; n = stk.top(); stk.pop(); stk.push(lexical_cast<string>( funcmap[op]( lexical_cast<Digit>(n), lexical_cast<Digit>(m) ) )); } else { die(op + ": No such operator"); } } bool is_op(const char c) { string s(1, c); return is_op(s); } bool is_op(string& s) { return funcmap.find(s) != funcmap.end(); } void die(const string& errmsg) { cerr << "error:" << errmsg << endl; exit(EXIT_FAILURE); } private: InputIterator first; InputIterator last; FuncMap funcmap; Stack stk; }; /* parser * TODO Boost.Spirit */ template <class Digit> string RPN<Digit>::get_word() { string word; while (first != last) { if (isspace(*first)) { ++first; continue; } if (isdigit(*first)) { while (first != last && isdigit(*first)) { word += *first; ++first; } break; } if (isalpha(*first)) { while (first != last && isalpha(*first)) { word += *first; ++first; } break; } if (is_op(*first)) { while (first != last && is_op(*first)) { word += *first; ++first; } break; } ++first; } cerr << "get_word() returns: " << word << endl; return word; } template <class Digit> Digit RPN<Digit>::parse() { while (1) { string word = get_word(); if (word.empty()) { if (stk.empty()) { return 0.0; } else { return lexical_cast<Digit>(stk.top()); } } cerr << "* push " << word << endl; stk.push(word); if (is_op(word)) call_stack(); } die("never reach this block"); } int main(int argc, char *argv[]) { RPN<double> rpn; string buf; while (getline(cin, buf)) { try { cout << "result: " << rpn.eval(buf) << endl; } catch (const bad_lexical_cast& e) { cerr << e.what() << endl; } } return EXIT_SUCCESS; }