// // calc3.cc // // Copyright (c) 2015 Yuji Hirose. All rights reserved. // MIT License // #include #include #include using namespace peglib; using namespace std; template static U reduce(T i, T end, U val, F f) { if (i == end) { return val; } tie(val, i) = f(val, i); return reduce(i, end, val, f); }; struct ast_node { virtual ~ast_node() = default; virtual long eval() = 0; }; struct ast_ope : public ast_node { ast_ope(char ope, shared_ptr left, shared_ptr right) : ope_(ope), left_(left), right_(right) {} long eval() override { switch (ope_) { case '+': return left_->eval() + right_->eval(); case '-': return left_->eval() - right_->eval(); case '*': return left_->eval() * right_->eval(); case '/': return left_->eval() / right_->eval(); } assert(false); return 0; }; static shared_ptr create(const SemanticValues& sv) { assert(!sv.empty()); return reduce( sv.begin() + 1, sv.end(), sv[0].get>(), [](shared_ptr r, SemanticValues::const_iterator i) { auto ope = (i++)->val.get(); auto nd = (i++)->val.get>(); r = make_shared(ope, r, nd); return make_tuple(r, i); }); } private: char ope_; shared_ptr left_; shared_ptr right_; }; struct ast_num : public ast_node { ast_num(long num) : num_(num) {} long eval() override { return num_; }; static shared_ptr create(const char* s, size_t n) { return make_shared(atol(s)); } private: long num_; }; int main(int argc, const char** argv) { if (argc < 2 || string("--help") == argv[1]) { cout << "usage: calc3 [formula]" << endl; return 1; } peg parser( " EXPRESSION <- _ TERM (TERM_OPERATOR TERM)* " " TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* " " FACTOR <- NUMBER / '(' _ EXPRESSION ')' _ " " TERM_OPERATOR <- < [-+] > _ " " FACTOR_OPERATOR <- < [/*] > _ " " NUMBER <- < [0-9]+ > _ " " ~_ <- [ \t\r\n]* " ); parser["EXPRESSION"] = ast_ope::create; parser["TERM"] = ast_ope::create; parser["TERM_OPERATOR"] = [](const char* s, size_t n) { return *s; }; parser["FACTOR_OPERATOR"] = [](const char* s, size_t n) { return *s; }; parser["NUMBER"] = ast_num::create; auto expr = argv[1]; shared_ptr ast; if (parser.parse(expr, ast)) { cout << expr << " = " << ast->eval() << endl; return 0; } cout << "syntax error..." << endl; return -1; } // vim: et ts=4 sw=4 cin cino={1s ff=unix