Added the predicate control feature.

This commit is contained in:
yhirose 2015-04-08 12:02:26 -04:00
parent faa70f1f37
commit 8bac879ff9
3 changed files with 72 additions and 14 deletions

View File

@ -90,7 +90,7 @@ struct SemanticValue {
const char* s; // Token start for the semantic value const char* s; // Token start for the semantic value
size_t n; // Token length for the semantic value size_t n; // Token length for the semantic value
// Utility method // Utility method
template <typename T> T& get(); template <typename T> T& get();
template <typename T> const T& get() const; template <typename T> const T& get() const;
std::string str() const; std::string str() const;
@ -108,7 +108,7 @@ struct SemanticValues : protected std::vector<SemanticValue>
using std::vector<T>::end; using std::vector<T>::end;
// NOTE: There are more std::vector methods available... // 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 <typename F> auto map(size_t beg, size_t end, F f) const -> vector<typename std::remove_const<decltype(f(SemanticValue()))>::type>; template <typename F> auto map(size_t beg, size_t end, F f) const -> vector<typename std::remove_const<decltype(f(SemanticValue()))>::type>;
template <typename F> auto map(F f) const -> vector<typename std::remove_const<decltype(f(SemanticValue()))>::type>; template <typename F> auto map(F f) const -> vector<typename std::remove_const<decltype(f(SemanticValue()))>::type>;
template <typename T> auto map(size_t beg = 0, size_t end = -1) const -> vector<T>; template <typename T> auto map(size_t beg = 0, size_t end = -1) const -> vector<T>;
@ -258,6 +258,29 @@ The following are available operators:
| cap | Capture character | | cap | Capture character |
| usr | User defiend parser | | 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<long>() == 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 Adjust definitions
------------------ ------------------

View File

@ -284,6 +284,11 @@ any call(F fn, Args&&... args) {
return any(fn(std::forward<Args>(args)...)); return any(fn(std::forward<Args>(args)...));
} }
/*
* Predicate
*/
typedef std::function<bool(const char* s, size_t n, const any& val, const any& dt)> Predicate;
class Action class Action
{ {
public: public:
@ -1159,14 +1164,14 @@ public:
return parse_and_get_value(s, n, dt, val); return parse_and_get_value(s, n, dt, val);
} }
Definition& operator=(Action ac) { Definition& operator=(Action action) {
assert(!actions.empty()); assert(!actions.empty());
actions[0] = ac; actions[0] = action;
return *this; return *this;
} }
Definition& operator=(std::initializer_list<Action> acs) { Definition& operator=(std::initializer_list<Action> ini) {
actions = acs; actions = ini;
return *this; return *this;
} }
@ -1187,6 +1192,7 @@ public:
std::string name; std::string name;
size_t id; size_t id;
Predicate predicate;
std::vector<Action> actions; std::vector<Action> actions;
std::function<std::string ()> error_message; std::function<std::string ()> error_message;
bool ignoreSemanticValue; 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..."); throw std::logic_error("Uninitialized definition ope was used...");
} }
int len; int len;
any val; any val;
const char* ancs = s; const char* anchors = s;
size_t ancn = n; size_t anchorn = n;
c.packrat(s, outer_->id, len, val, [&](any& val) { c.packrat(s, outer_->id, len, val, [&](any& val) {
auto& chldsv = c.push(); auto& chldsv = c.push();
const auto& rule = *ope_; const auto& rule = *ope_;
len = rule.parse(s, n, chldsv, c, dt); len = rule.parse(s, n, chldsv, c, dt);
ancn = len;
anchorn = len;
// Invoke action
if (success(len) && !outer_->ignoreSemanticValue) { if (success(len) && !outer_->ignoreSemanticValue) {
assert(!outer_->actions.empty()); 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]; : outer_->actions[0];
if (chldsv.s) { if (chldsv.s) {
ancs = chldsv.s; anchors = chldsv.s;
ancn = chldsv.n; anchorn = chldsv.n;
} else { } else {
chldsv.s = s; chldsv.s = s;
chldsv.n = len; 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); val = reduce(chldsv, dt, action);
} }
// Predicate check
if (success(len) && outer_->predicate && !outer_->predicate(anchors, anchorn, val, dt)) {
len = -1;
}
c.pop(); c.pop();
}); });
if (success(len) && !outer_->ignoreSemanticValue) { 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) { if (fail(len) && outer_->error_message && !c.message_pos) {

View File

@ -422,6 +422,27 @@ TEST_CASE("Calculator test3", "[general]")
REQUIRE(val == -3); 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<long>() == 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) { bool exact(Grammar& g, const char* d, const char* s) {
auto n = strlen(s); auto n = strlen(s);
auto r = g[d].parse(s, n); auto r = g[d].parse(s, n);