From 8bac879ff9da95aaff1f61c0ffdf8e1b81a92710 Mon Sep 17 00:00:00 2001 From: yhirose Date: Wed, 8 Apr 2015 12:02:26 -0400 Subject: [PATCH] Added the predicate control feature. --- README.md | 27 +++++++++++++++++++++++++-- peglib.h | 38 ++++++++++++++++++++++++++------------ test/test.cc | 21 +++++++++++++++++++++ 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 9e220e9..ece7c9f 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ struct SemanticValue { const char* s; // Token start for the semantic value size_t n; // Token length for the semantic value - // Utility method + // Utility method template T& get(); template const T& get() const; std::string str() const; @@ -108,7 +108,7 @@ struct SemanticValues : protected std::vector using std::vector::end; // NOTE: There are more std::vector methods available... - // Transform the semantice values vector to another vector + // Transform the semantice values vector to another vector template auto map(size_t beg, size_t end, F f) const -> vector::type>; template auto map(F f) const -> vector::type>; template auto map(size_t beg = 0, size_t end = -1) const -> vector; @@ -258,6 +258,29 @@ The following are available operators: | cap | Capture character | | usr | User defiend parser | +Predicate control +----------------- + +```c++ +peg parser("NUMBER <- [0-9]+"); + +parser["NUMBER"] = [](const char* s, size_t n) { + return stol(string(s, n), nullptr, 10); +}; + +parser["NUMBER"].predicate = [](const char* s, size_t n, const any& val, const any& dt) { + return val.get() == 100; +}; + +long val; +auto ret = parser.parse("100", val); +assert(ret == true); +assert(val == 100); + +ret = parser.parse("200", val); +assert(ret == false); +``` + Adjust definitions ------------------ diff --git a/peglib.h b/peglib.h index 74d6cb7..1e509d6 100644 --- a/peglib.h +++ b/peglib.h @@ -284,6 +284,11 @@ any call(F fn, Args&&... args) { return any(fn(std::forward(args)...)); } +/* + * Predicate + */ +typedef std::function Predicate; + class Action { public: @@ -1159,14 +1164,14 @@ public: return parse_and_get_value(s, n, dt, val); } - Definition& operator=(Action ac) { + Definition& operator=(Action action) { assert(!actions.empty()); - actions[0] = ac; + actions[0] = action; return *this; } - Definition& operator=(std::initializer_list acs) { - actions = acs; + Definition& operator=(std::initializer_list ini) { + actions = ini; return *this; } @@ -1187,6 +1192,7 @@ public: std::string name; size_t id; + Predicate predicate; std::vector actions; std::function error_message; bool ignoreSemanticValue; @@ -1221,17 +1227,20 @@ inline int Holder::parse(const char* s, size_t n, SemanticValues& sv, Context& c throw std::logic_error("Uninitialized definition ope was used..."); } - int len; - any val; - const char* ancs = s; - size_t ancn = n; + int len; + any val; + const char* anchors = s; + size_t anchorn = n; c.packrat(s, outer_->id, len, val, [&](any& val) { auto& chldsv = c.push(); const auto& rule = *ope_; len = rule.parse(s, n, chldsv, c, dt); - ancn = len; + + anchorn = len; + + // Invoke action if (success(len) && !outer_->ignoreSemanticValue) { assert(!outer_->actions.empty()); @@ -1241,8 +1250,8 @@ inline int Holder::parse(const char* s, size_t n, SemanticValues& sv, Context& c : outer_->actions[0]; if (chldsv.s) { - ancs = chldsv.s; - ancn = chldsv.n; + anchors = chldsv.s; + anchorn = chldsv.n; } else { chldsv.s = s; chldsv.n = len; @@ -1251,11 +1260,16 @@ inline int Holder::parse(const char* s, size_t n, SemanticValues& sv, Context& c val = reduce(chldsv, dt, action); } + // Predicate check + if (success(len) && outer_->predicate && !outer_->predicate(anchors, anchorn, val, dt)) { + len = -1; + } + c.pop(); }); if (success(len) && !outer_->ignoreSemanticValue) { - sv.emplace_back(val, outer_->name.c_str(), ancs, ancn); + sv.emplace_back(val, outer_->name.c_str(), anchors, anchorn); } if (fail(len) && outer_->error_message && !c.message_pos) { diff --git a/test/test.cc b/test/test.cc index 8c31701..a244969 100644 --- a/test/test.cc +++ b/test/test.cc @@ -422,6 +422,27 @@ TEST_CASE("Calculator test3", "[general]") REQUIRE(val == -3); } +TEST_CASE("Predicate test", "[general]") +{ + peg parser("NUMBER <- [0-9]+"); + + parser["NUMBER"] = [](const char* s, size_t n) { + return stol(string(s, n), nullptr, 10); + }; + + parser["NUMBER"].predicate = [](const char* s, size_t n, const any& val, const any& dt) { + return val.get() == 100; + }; + + long val; + auto ret = parser.parse("100", val); + REQUIRE(ret == true); + REQUIRE(val == 100); + + ret = parser.parse("200", val); + REQUIRE(ret == false); +} + bool exact(Grammar& g, const char* d, const char* s) { auto n = strlen(s); auto r = g[d].parse(s, n);