diff --git a/example/Makefile b/example/Makefile index 3c0fc71..10237a9 100644 --- a/example/Makefile +++ b/example/Makefile @@ -9,10 +9,13 @@ CC = g++ CFLAGS = -std=c++1y -g endif -all: calc calc2 +all: calc calc2 calc3 calc : calc.cc ../peglib.h $(CC) -o calc $(CFLAGS) -I.. calc.cc calc2 : calc2.cc ../peglib.h $(CC) -o calc2 $(CFLAGS) -I.. calc2.cc + +calc3 : calc3.cc ../peglib.h + $(CC) -o calc3 $(CFLAGS) -I.. calc3.cc diff --git a/example/calc3.cc b/example/calc3.cc new file mode 100644 index 0000000..4f19099 --- /dev/null +++ b/example/calc3.cc @@ -0,0 +1,123 @@ +// +// calc3.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]+ > _ +// ~_ <- [ \t\r\n]* +// + +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) { + if (sv.empty()) { + return nullptr; + } + return SemanticValues::reduce( + sv.begin() + 1, + sv.end(), + sv[0].val.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 l) { + 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; + } + + const char* s = argv[1]; + + const char* syntax = + " EXPRESSION <- _ TERM (TERM_OPERATOR TERM)* " + " TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* " + " FACTOR <- NUMBER / '(' _ EXPRESSION ')' _ " + " TERM_OPERATOR <- < [-+] > _ " + " FACTOR_OPERATOR <- < [/*] > _ " + " NUMBER <- < [0-9]+ > _ " + " ~_ <- [ \t\r\n]* " + ; + + peg parser(syntax); + + parser["EXPRESSION"] = ast_ope::create; + parser["TERM"] = ast_ope::create; + parser["TERM_OPERATOR"] = [](const char* s, size_t l) { return *s; }; + parser["FACTOR_OPERATOR"] = [](const char* s, size_t l) { return *s; }; + parser["NUMBER"] = ast_num::create; + + shared_ptr ast; + if (parser.parse(s, ast)) { + cout << s << " = " << ast->eval() << endl; + return 0; + } + + cout << "syntax error..." << endl; + + return -1; +} + +// vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/peglib.h b/peglib.h index 9a25e47..56bf2d6 100644 --- a/peglib.h +++ b/peglib.h @@ -167,6 +167,8 @@ struct SemanticValues : protected std::vector SemanticValues() : s(nullptr), l(0) {} typedef SemanticValue T; + using std::vector::iterator; + using std::vector::const_iterator; using std::vector::size; using std::vector::empty; using std::vector::assign; @@ -185,6 +187,15 @@ struct SemanticValues : protected std::vector using std::vector::erase; using std::vector::clear; using std::vector::swap; + + template + static U reduce(T i, T end, U val, V f){ + if (i == end) { + return val; + } + std::tie(val, i) = f(val, i); + return reduce(i, end, val, f); + }; }; /*