// // calc2.cc // // Copyright (c) 2015 Yuji Hirose. All rights reserved. // MIT License // #include #include #include using namespace peglib; using namespace std; // // PEG syntax: // // EXPRESSION <- TERM (TERM_OPERATOR TERM)* // TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* // FACTOR <- NUMBER / '(' EXPRESSION ')' // TERM_OPERATOR <- [-+] // FACTOR_OPERATOR <- [/*] // NUMBER <- [0-9]+ // class Calculator { public: Calculator() { EXPRESSION <= seq(TERM, zom(seq(TERM_OPERATOR, TERM))), reduce; TERM <= seq(FACTOR, zom(seq(FACTOR_OPERATOR, FACTOR))), reduce; FACTOR <= cho(NUMBER, seq(chr('('), EXPRESSION, chr(')'))); TERM_OPERATOR <= cls("+-"), [](const char* s, size_t l) { return (char)*s; }; FACTOR_OPERATOR <= cls("*/"), [](const char* s, size_t l) { return (char)*s; }; NUMBER <= oom(cls("0-9")), [](const char* s, size_t l) { return stol(string(s, l), nullptr, 10); }; } bool execute(const char* s, long& v) const { Any val; auto ret = EXPRESSION.parse(s, actions, val); if (ret) { v = val.get(); } return ret; } private: Definition EXPRESSION, TERM, FACTOR, TERM_OPERATOR, FACTOR_OPERATOR, NUMBER; SemanticActions actions; static long reduce(const vector& v) { auto result = v[0].get(); for (auto i = 1u; i < v.size(); i += 2) { auto num = v[i + 1].get(); auto ope = v[i].get(); switch (ope) { case '+': result += num; break; case '-': result -= num; break; case '*': result *= num; break; case '/': result /= num; break; } } return result; } }; int main(int argc, const char** argv) { if (argc < 2 || string("--help") == argv[1]) { cout << "usage: calc [formula]" << endl; return 1; } const char* s = argv[1]; Calculator calc; long val = 0; if (calc.execute(s, val)) { cout << s << " = " << val << endl; return 0; } cout << "syntax error..." << endl; return -1; } // vim: et ts=4 sw=4 cin cino={1s ff=unix