Updated public interface.

This commit is contained in:
yhirose 2015-03-02 21:52:09 -05:00
parent 9fee7187fb
commit 1fc0a6819e
5 changed files with 104 additions and 77 deletions

View File

@ -12,7 +12,7 @@ The PEG syntax is well described on page 2 in the [document](http://pdos.csail.m
* `~` (Ignore operator) * `~` (Ignore operator)
* `\x??` (Hex number char) * `\x??` (Hex number char)
This library is a [*Packrat*](http://pdos.csail.mit.edu/~baford/packrat/thesis/thesis.pdf) parser which supports the linear-time parsing. This library also supports the linear-time parsing known as the [*Packrat*](http://pdos.csail.mit.edu/~baford/packrat/thesis/thesis.pdf) parsing.
How to use How to use
---------- ----------
@ -41,6 +41,8 @@ int main(void) {
peg parser(syntax); peg parser(syntax);
parser.packrat_parsing(true); // Enable packrat parsing
// (3) Setup an action // (3) Setup an action
parser["Additive"] = { parser["Additive"] = {
nullptr, // Default action nullptr, // Default action
@ -59,19 +61,13 @@ int main(void) {
} }
}; };
/* This action is not necessary.
parser["Primary"] = [](const SemanticValues& sv) {
return sv[0];
};
*/
parser["Number"] = [](const char* s, size_t l) { parser["Number"] = [](const char* s, size_t l) {
return stoi(string(s, l), nullptr, 10); return stoi(string(s, l), nullptr, 10);
}; };
// (4) Parse // (4) Parse
int val; int val;
parser.parse("(1+2)*3", val); parser.parse_with_value("(1+2)*3", val);
assert(val == 9); assert(val == 9);
} }

View File

@ -108,7 +108,7 @@ int main(int argc, const char** argv)
parser["NUMBER"] = ast_num::create; parser["NUMBER"] = ast_num::create;
shared_ptr<ast_node> ast; shared_ptr<ast_node> ast;
if (parser.parse(s, ast)) { if (parser.parse_with_value(s, ast)) {
cout << s << " = " << ast->eval() << endl; cout << s << " = " << ast->eval() << endl;
return 0; return 0;
} }

View File

@ -61,9 +61,7 @@ int main(int argc, const char** argv)
return -1; return -1;
} }
peglib::any dt; auto ret = peg.lint(source.data(), source.size(), [&](size_t ln, size_t col, const string& msg) {
auto ret = peg.lint(source.data(), source.size(), true, false, dt,
[&](size_t ln, size_t col, const string& msg) {
cerr << source_path << ":" << ln << ":" << col << ": " << msg << endl; cerr << source_path << ":" << ln << ":" << col << ": " << msg << endl;
}); });

139
peglib.h
View File

@ -1034,14 +1034,16 @@ public:
}; };
Definition() Definition()
: actions(1) : actions(1)
, ignore(false) , ignore(false)
, holder_(std::make_shared<Holder>(this)) {} , packrat(false)
, holder_(std::make_shared<Holder>(this)) {}
Definition(const Definition& rhs) Definition(const Definition& rhs)
: name(rhs.name) : name(rhs.name)
, actions(1) , actions(1)
, ignore(false) , ignore(false)
, packrat(false)
, holder_(rhs.holder_) , holder_(rhs.holder_)
{ {
holder_->outer_ = this; holder_->outer_ = this;
@ -1051,6 +1053,7 @@ public:
: name(std::move(rhs.name)) : name(std::move(rhs.name))
, actions(1) , actions(1)
, ignore(rhs.ignore) , ignore(rhs.ignore)
, packrat(rhs.packrat)
, holder_(std::move(rhs.holder_)) , holder_(std::move(rhs.holder_))
{ {
holder_->outer_ = this; holder_->outer_ = this;
@ -1059,6 +1062,7 @@ public:
Definition(const std::shared_ptr<Ope>& ope) Definition(const std::shared_ptr<Ope>& ope)
: actions(1) : actions(1)
, ignore(false) , ignore(false)
, packrat(false)
, holder_(std::make_shared<Holder>(this)) , holder_(std::make_shared<Holder>(this))
{ {
holder_->ope_ = ope; holder_->ope_ = ope;
@ -1073,36 +1077,32 @@ public:
return *this; return *this;
} }
Result parse_core(const char* s, size_t l, SemanticValues& sv, any& dt, bool packrat) const { Result parse(const char* s, size_t l) const {
DefinitionIDs defIds;
holder_->accept(defIds);
Context c(s, l, defIds.ids.size(), packrat);
auto len = holder_->parse(s, l, sv, c, dt);
return Result { success(len), len, c.error_ptr, c.msg };
}
Result parse(const char* s, size_t l, any& dt, bool packrat = false) const {
SemanticValues sv;
return parse_core(s, l, sv, dt, packrat);
}
Result parse(const char* s, size_t l, bool packrat = false) const {
SemanticValues sv; SemanticValues sv;
any dt; any dt;
return parse_core(s, l, sv, dt, packrat); return parse_core(s, l, sv, dt);
} }
Result parse(const char* s, bool packrat = false) const { Result parse(const char* s) const {
auto l = strlen(s); auto l = strlen(s);
return parse(s, l, packrat); return parse(s, l);
}
Result parse_with_data(const char* s, size_t l, any& dt) const {
SemanticValues sv;
return parse_core(s, l, sv, dt);
}
Result parse_with_data(const char* s, any& dt) const {
auto l = strlen(s);
return parse_with_data(s, l, dt);
} }
template <typename T> template <typename T>
Result parse_with_value(const char* s, size_t l, T& val, bool packrat = false) const { Result parse_with_value(const char* s, size_t l, T& val) const {
SemanticValues sv; SemanticValues sv;
any dt; any dt;
auto r = parse_core(s, l, sv, dt, packrat); auto r = parse_core(s, l, sv, dt);
if (r.ret && !sv.empty() && !sv.front().val.is_undefined()) { if (r.ret && !sv.empty() && !sv.front().val.is_undefined()) {
val = sv[0].val.get<T>(); val = sv[0].val.get<T>();
} }
@ -1110,9 +1110,9 @@ public:
} }
template <typename T> template <typename T>
Result parse_with_value(const char* s, T& val, bool packrat = false) const { Result parse_with_value(const char* s, T& val) const {
auto l = strlen(s); auto l = strlen(s);
return parse_with_value(s, l, val, packrat); return parse_with_value(s, l, val);
} }
Definition& operator=(Action ac) { Definition& operator=(Action ac) {
@ -1145,6 +1145,7 @@ public:
size_t id; size_t id;
std::vector<Action> actions; std::vector<Action> actions;
bool ignore; bool ignore;
bool packrat;
private: private:
friend class DefinitionReference; friend class DefinitionReference;
@ -1152,6 +1153,15 @@ private:
Definition& operator=(const Definition& rhs); Definition& operator=(const Definition& rhs);
Definition& operator=(Definition&& rhs); Definition& operator=(Definition&& rhs);
Result parse_core(const char* s, size_t l, SemanticValues& sv, any& dt) const {
DefinitionIDs defIds;
holder_->accept(defIds);
Context c(s, l, defIds.ids.size(), packrat);
auto len = holder_->parse(s, l, sv, c, dt);
return Result { success(len), len, c.error_ptr, c.msg };
}
std::shared_ptr<Holder> holder_; std::shared_ptr<Holder> holder_;
}; };
@ -1602,7 +1612,7 @@ private:
data.match_action = ma; data.match_action = ma;
any dt = &data; any dt = &data;
auto r = g["Grammar"].parse(s, l, dt, false); auto r = g["Grammar"].parse_with_data(s, l, dt);
if (!r.ret) { if (!r.ret) {
if (log) { if (log) {
@ -1771,62 +1781,76 @@ public:
return grammar_ != nullptr; return grammar_ != nullptr;
} }
template <typename T> bool parse(const char* s, size_t l) const {
bool parse(const char* s, size_t l, T& out, bool exact = true, bool packrat = false) const {
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_]; const auto& rule = (*grammar_)[start_];
auto r = rule.parse_with_value(s, l, out, packrat); auto r = rule.parse(s, l);
return r.ret && (!exact || r.len == l); return r.ret && r.len == l;
}
return false;
}
bool parse(const char* s) const {
auto l = strlen(s);
return parse(s, l);
}
bool parse_with_data(const char* s, size_t l, any& dt) const {
if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse_with_data(s, l, dt);
return r.ret && r.len == l;
}
return false;
}
bool parse_with_data(const char* s, any& dt) const {
auto l = strlen(s);
return parse_with_data(s, l, dt);
}
template <typename T>
bool parse_with_value(const char* s, size_t l, T& out) const {
if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse_with_value(s, l, out);
return r.ret && r.len == l;
} }
return false; return false;
} }
template <typename T> template <typename T>
bool parse(const char* s, T& out, bool exact = true, bool packrat = false) const { bool parse_with_value(const char* s, T& out) const {
auto l = strlen(s); auto l = strlen(s);
return parse(s, l, out, exact, packrat); return parse_with_value(s, l, out);
} }
bool parse(const char* s, size_t l, bool exact = true, bool packrat = false) const { bool lint(const char* s, size_t l, Log log) {
if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, l, packrat);
return r.ret && (!exact || r.len == l);
}
return false;
}
bool parse(const char* s, bool exact = true, bool packrat = false) const {
auto l = strlen(s);
return parse(s, l, exact, packrat);
}
bool lint(const char* s, size_t l, bool exact, bool packrat, any& dt, Log log) {
assert(grammar_); assert(grammar_);
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_]; const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, l, dt, packrat); auto r = rule.parse(s, l);
if (!r.ret) { if (!r.ret) {
if (log) { if (log) {
auto line = line_info(s, r.error_ptr); auto line = line_info(s, r.error_ptr);
log(line.first, line.second, r.msg ? "syntax error" : r.msg); log(line.first, line.second, r.msg ? "syntax error" : r.msg);
} }
} else if (exact && r.len != l) { } else if (r.len != l) {
auto line = line_info(s, s + r.len); auto line = line_info(s, s + r.len);
log(line.first, line.second, "syntax error"); log(line.first, line.second, "syntax error");
} }
return r.ret && (!exact || r.len == l); return r.ret;
} }
return false; return false;
} }
bool search(const char* s, size_t l, size_t& mpos, size_t& mlen, bool packrat = false) const { bool search(const char* s, size_t l, size_t& mpos, size_t& mlen) const {
const auto& rule = (*grammar_)[start_]; const auto& rule = (*grammar_)[start_];
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
size_t pos = 0; size_t pos = 0;
while (pos < l) { while (pos < l) {
size_t len = l - pos; size_t len = l - pos;
auto r = rule.parse(s + pos, len, packrat); auto r = rule.parse(s + pos, len);
if (r.ret) { if (r.ret) {
mpos = pos; mpos = pos;
mlen = len; mlen = len;
@ -1840,15 +1864,22 @@ public:
return false; return false;
} }
bool search(const char* s, size_t& mpos, size_t& mlen, bool packrat) const { bool search(const char* s, size_t& mpos, size_t& mlen) const {
auto l = strlen(s); auto l = strlen(s);
return search(s, l, mpos, mlen, packrat); return search(s, l, mpos, mlen);
} }
Definition& operator[](const char* s) { Definition& operator[](const char* s) {
return (*grammar_)[s]; return (*grammar_)[s];
} }
void packrat_parsing(bool sw) {
if (grammar_ != nullptr) {
auto& rule = (*grammar_)[start_];
rule.packrat = sw;
}
}
MatchAction match_action; MatchAction match_action;
private: private:

View File

@ -76,9 +76,9 @@ TEST_CASE("String capture test2", "[general]")
TAG_NAME <= oom(seq(npd(chr(']')), dot())), [&](const char* s, size_t l) { tags.push_back(string(s, l)); }; TAG_NAME <= oom(seq(npd(chr(']')), dot())), [&](const char* s, size_t l) { tags.push_back(string(s, l)); };
WS <= zom(cls(" \t")); WS <= zom(cls(" \t"));
auto m = ROOT.parse(" [tag1] [tag:2] [tag-3] "); auto r = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
REQUIRE(m.ret == true); REQUIRE(r.ret == true);
REQUIRE(tags.size() == 3); REQUIRE(tags.size() == 3);
REQUIRE(tags[0] == "tag1"); REQUIRE(tags[0] == "tag1");
REQUIRE(tags[1] == "tag:2"); REQUIRE(tags[1] == "tag:2");
@ -124,9 +124,9 @@ TEST_CASE("String capture test with embedded match action", "[general]")
TAG_NAME <= oom(seq(npd(chr(']')), dot())); TAG_NAME <= oom(seq(npd(chr(']')), dot()));
WS <= zom(cls(" \t")); WS <= zom(cls(" \t"));
auto m = ROOT.parse(" [tag1] [tag:2] [tag-3] "); auto r = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
REQUIRE(m.ret == true); REQUIRE(r.ret == true);
REQUIRE(tags.size() == 3); REQUIRE(tags.size() == 3);
REQUIRE(tags[0] == "tag1"); REQUIRE(tags[0] == "tag1");
REQUIRE(tags[1] == "tag:2"); REQUIRE(tags[1] == "tag:2");
@ -204,7 +204,9 @@ TEST_CASE("Backtracking test", "[general]")
count++; count++;
}; };
bool ret = parser.parse("Hello Two", true, true); parser.packrat_parsing(true);
bool ret = parser.parse("Hello Two");
REQUIRE(ret == true); REQUIRE(ret == true);
REQUIRE(count == 1); // Skip second time REQUIRE(count == 1); // Skip second time
} }
@ -265,7 +267,7 @@ TEST_CASE("Simple calculator test", "[general]")
}; };
int val; int val;
parser.parse("(1+2)*3", val); parser.parse_with_value("(1+2)*3", val);
REQUIRE(val == 9); REQUIRE(val == 9);
} }
@ -305,9 +307,9 @@ TEST_CASE("Calculator test", "[general]")
// Parse // Parse
long val; long val;
auto m = EXPRESSION.parse_with_value("1+2*3*(4-5+6)/7-8", val); auto r = EXPRESSION.parse_with_value("1+2*3*(4-5+6)/7-8", val);
REQUIRE(m.ret == true); REQUIRE(r.ret == true);
REQUIRE(val == -3); REQUIRE(val == -3);
} }
@ -351,9 +353,9 @@ TEST_CASE("Calculator test2", "[general]")
// Parse // Parse
long val; long val;
auto m = g[start].parse_with_value("1+2*3*(4-5+6)/7-8", val); auto r = g[start].parse_with_value("1+2*3*(4-5+6)/7-8", val);
REQUIRE(m.ret == true); REQUIRE(r.ret == true);
REQUIRE(val == -3); REQUIRE(val == -3);
} }
@ -393,7 +395,7 @@ TEST_CASE("Calculator test3", "[general]")
// Parse // Parse
long val; long val;
auto ret = parser.parse("1+2*3*(4-5+6)/7-8", val); auto ret = parser.parse_with_value("1+2*3*(4-5+6)/7-8", val);
REQUIRE(ret == true); REQUIRE(ret == true);
REQUIRE(val == -3); REQUIRE(val == -3);