mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Added error handling.
This commit is contained in:
parent
97641ed257
commit
45024d3aaa
126
peglib.h
126
peglib.h
@ -13,10 +13,10 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace peglib {
|
namespace peglib {
|
||||||
|
|
||||||
@ -352,18 +352,19 @@ private:
|
|||||||
*/
|
*/
|
||||||
struct Match
|
struct Match
|
||||||
{
|
{
|
||||||
Match(bool _ret, size_t _len, size_t _id) : ret(_ret), len(_len), id(_id) {}
|
|
||||||
bool ret;
|
bool ret;
|
||||||
size_t len;
|
size_t len;
|
||||||
size_t id;
|
size_t choice;
|
||||||
|
const char* ptr;
|
||||||
|
const std::string msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
Match success(size_t len, size_t id = 0) {
|
Match success(size_t len, size_t choice = 0) {
|
||||||
return Match(true, len, id);
|
return Match{ true, len, choice, nullptr, std::string() };
|
||||||
}
|
}
|
||||||
|
|
||||||
Match fail() {
|
Match fail(const char* ptr, std::string msg = std::string()) {
|
||||||
return Match(false, 0, -1);
|
return Match{ false, 0, (size_t)-1, ptr, msg };
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -411,7 +412,7 @@ public:
|
|||||||
for (const auto& ope : opes_) {
|
for (const auto& ope : opes_) {
|
||||||
auto m = ope->parse(s + i, l - i, v);
|
auto m = ope->parse(s + i, l - i, v);
|
||||||
if (!m.ret) {
|
if (!m.ret) {
|
||||||
return fail();
|
return fail(m.ptr, m.msg);
|
||||||
}
|
}
|
||||||
i += m.len;
|
i += m.len;
|
||||||
}
|
}
|
||||||
@ -462,7 +463,7 @@ public:
|
|||||||
}
|
}
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
return fail();
|
return fail(s, "no choice candidate was matched");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const { return opes_.size(); }
|
size_t size() const { return opes_.size(); }
|
||||||
@ -500,7 +501,7 @@ public:
|
|||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse_core(const char* s, size_t l, Values& v) const {
|
||||||
auto m = ope_->parse(s, l, v);
|
auto m = ope_->parse(s, l, v);
|
||||||
if (!m.ret) {
|
if (!m.ret) {
|
||||||
return fail();
|
return fail(m.ptr, m.msg);
|
||||||
}
|
}
|
||||||
auto i = m.len;
|
auto i = m.len;
|
||||||
while (l - i > 0) {
|
while (l - i > 0) {
|
||||||
@ -541,7 +542,7 @@ public:
|
|||||||
if (m.ret) {
|
if (m.ret) {
|
||||||
return success(0);
|
return success(0);
|
||||||
} else {
|
} else {
|
||||||
return fail();
|
return fail(m.ptr, m.msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,7 +558,7 @@ public:
|
|||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse_core(const char* s, size_t l, Values& v) const {
|
||||||
auto m = ope_->parse(s, l, v);
|
auto m = ope_->parse(s, l, v);
|
||||||
if (m.ret) {
|
if (m.ret) {
|
||||||
return fail();
|
return fail(s);
|
||||||
} else {
|
} else {
|
||||||
return success(0);
|
return success(0);
|
||||||
}
|
}
|
||||||
@ -576,7 +577,7 @@ public:
|
|||||||
auto i = 0u;
|
auto i = 0u;
|
||||||
for (; i < lit_.size(); i++) {
|
for (; i < lit_.size(); i++) {
|
||||||
if (i >= l || s[i] != lit_[i]) {
|
if (i >= l || s[i] != lit_[i]) {
|
||||||
return fail();
|
return fail(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return success(i);
|
return success(i);
|
||||||
@ -594,7 +595,7 @@ public:
|
|||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse_core(const char* s, size_t l, Values& v) const {
|
||||||
// TODO: UTF8 support
|
// TODO: UTF8 support
|
||||||
if (l < 1) {
|
if (l < 1) {
|
||||||
return fail();
|
return fail(s);
|
||||||
}
|
}
|
||||||
auto ch = s[0];
|
auto ch = s[0];
|
||||||
auto i = 0u;
|
auto i = 0u;
|
||||||
@ -611,7 +612,7 @@ public:
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fail();
|
return fail(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -626,7 +627,7 @@ public:
|
|||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse_core(const char* s, size_t l, Values& v) const {
|
||||||
// TODO: UTF8 support
|
// TODO: UTF8 support
|
||||||
if (l < 1 || s[0] != ch_) {
|
if (l < 1 || s[0] != ch_) {
|
||||||
return fail();
|
return fail(s);
|
||||||
}
|
}
|
||||||
return success(1);
|
return success(1);
|
||||||
}
|
}
|
||||||
@ -641,7 +642,7 @@ public:
|
|||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse_core(const char* s, size_t l, Values& v) const {
|
||||||
// TODO: UTF8 support
|
// TODO: UTF8 support
|
||||||
if (l < 1) {
|
if (l < 1) {
|
||||||
return fail();
|
return fail(s);
|
||||||
}
|
}
|
||||||
return success(1);
|
return success(1);
|
||||||
}
|
}
|
||||||
@ -730,6 +731,11 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Match parse_with_match(const char* s, size_t l) const {
|
||||||
|
Values v;
|
||||||
|
return holder_->parse(s, l, v);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool parse(const char* s, size_t l, T& val) const {
|
bool parse(const char* s, size_t l, T& val) const {
|
||||||
Values v;
|
Values v;
|
||||||
@ -800,7 +806,7 @@ private:
|
|||||||
|
|
||||||
assert(!outer_->actions.empty());
|
assert(!outer_->actions.empty());
|
||||||
|
|
||||||
auto id = m.id + 1;
|
auto id = m.choice + 1;
|
||||||
const auto& ac = (id < outer_->actions.size() && outer_->actions[id])
|
const auto& ac = (id < outer_->actions.size() && outer_->actions[id])
|
||||||
? outer_->actions[id]
|
? outer_->actions[id]
|
||||||
: outer_->actions[0];
|
: outer_->actions[0];
|
||||||
@ -979,7 +985,27 @@ inline Grammar make_peg_grammar()
|
|||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<Grammar> make_grammar(const char* syntax, std::string& start)
|
inline std::pair<size_t, size_t> find_line(const char* s, const char* ptr) {
|
||||||
|
auto p = s;
|
||||||
|
auto col_ptr = p;
|
||||||
|
auto no = 1;
|
||||||
|
|
||||||
|
while (p < ptr) {
|
||||||
|
if (*p == '\n') {
|
||||||
|
no++;
|
||||||
|
col_ptr = p + 1;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto col = p - col_ptr + 1;
|
||||||
|
|
||||||
|
return std::make_pair(no, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::shared_ptr<Grammar> make_grammar(
|
||||||
|
const char* syntax, size_t syntax_len, std::string& start,
|
||||||
|
std::function<void (size_t, size_t, const std::string)> log = nullptr)
|
||||||
{
|
{
|
||||||
Grammar peg = make_peg_grammar();
|
Grammar peg = make_peg_grammar();
|
||||||
|
|
||||||
@ -988,7 +1014,7 @@ inline std::shared_ptr<Grammar> make_grammar(const char* syntax, std::string& st
|
|||||||
start.clear();
|
start.clear();
|
||||||
|
|
||||||
// Setup actions
|
// Setup actions
|
||||||
std::set<std::string> refs;
|
std::map<std::string, const char*> refs;
|
||||||
|
|
||||||
peg["Definition"] = [&](const std::vector<Any>& v) {
|
peg["Definition"] = [&](const std::vector<Any>& v) {
|
||||||
const auto& name = v[0].get<std::string>();
|
const auto& name = v[0].get<std::string>();
|
||||||
@ -1051,9 +1077,16 @@ inline std::shared_ptr<Grammar> make_grammar(const char* syntax, std::string& st
|
|||||||
};
|
};
|
||||||
|
|
||||||
peg["Primary"].actions = {
|
peg["Primary"].actions = {
|
||||||
[&](const std::vector<Any>& v) { return v[0]; },
|
[&](const std::vector<Any>& v) {
|
||||||
[&](const std::vector<Any>& v) { refs.insert(v[0]); return ref(*grammar, v[0]); },
|
return v[0];
|
||||||
[&](const std::vector<Any>& v) { return v[1]; }
|
},
|
||||||
|
[&](const char* s, size_t l, const std::vector<Any>& v) {
|
||||||
|
refs[v[0]] = s;
|
||||||
|
return ref(*grammar, v[0]);
|
||||||
|
},
|
||||||
|
[&](const std::vector<Any>& v) {
|
||||||
|
return v[1];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["IdentCont"] = [](const char*s, size_t l) {
|
peg["IdentCont"] = [](const char*s, size_t l) {
|
||||||
@ -1081,16 +1114,35 @@ inline std::shared_ptr<Grammar> make_grammar(const char* syntax, std::string& st
|
|||||||
return any();
|
return any();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (peg["Grammar"].parse(syntax)) {
|
auto m = peg["Grammar"].parse_with_match(syntax, syntax_len);
|
||||||
for (const auto& name : refs) {
|
if (!m.ret) {
|
||||||
if (grammar->find(name) == grammar->end()) {
|
if (log) {
|
||||||
|
auto line = find_line(syntax, m.ptr);
|
||||||
|
log(line.first, line.second, m.msg.empty() ? "syntax error" : m.msg);
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return grammar;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (const auto& x : refs) {
|
||||||
|
const auto& name = x.first;
|
||||||
|
auto ptr = x.second;
|
||||||
|
if (grammar->find(name) == grammar->end()) {
|
||||||
|
if (log) {
|
||||||
|
auto line = find_line(syntax, ptr);
|
||||||
|
log(line.first, line.second, "'" + name + "' is not defined.");
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grammar;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::shared_ptr<Grammar> make_grammar(
|
||||||
|
const char* syntax, std::string& start,
|
||||||
|
std::function<void (size_t, size_t, const std::string)> log = nullptr)
|
||||||
|
{
|
||||||
|
return make_grammar(syntax, strlen(syntax), start, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
@ -1104,8 +1156,8 @@ public:
|
|||||||
return grammar_ != nullptr;
|
return grammar_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_syntax(const char* syntax) {
|
bool load_syntax(const char* s, size_t l, std::function<void (size_t, size_t, const std::string&)> log) {
|
||||||
grammar_ = make_grammar(syntax, start_);
|
grammar_ = make_grammar(s, l, start_, log);
|
||||||
return grammar_ != nullptr;
|
return grammar_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1145,11 +1197,15 @@ private:
|
|||||||
std::string start_;
|
std::string start_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Parser make_parser(const char* syntax) {
|
inline Parser make_parser(const char* s, size_t l, std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
||||||
Parser parser;
|
Parser parser;
|
||||||
if (!parser.load_syntax(syntax)) {
|
parser.load_syntax(s, l, log);
|
||||||
throw std::logic_error("PEG syntax error.");
|
return parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Parser make_parser(const char* s, std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
||||||
|
Parser parser;
|
||||||
|
parser.load_syntax(s, strlen(s), log);
|
||||||
return parser;
|
return parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user