mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Updated public interface.
This commit is contained in:
parent
9fee7187fb
commit
1fc0a6819e
12
README.md
12
README.md
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
139
peglib.h
@ -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:
|
||||||
|
24
test/test.cc
24
test/test.cc
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user