mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Added simple error handling code.
This commit is contained in:
parent
45024d3aaa
commit
f9c6a67ea6
243
peglib.h
243
peglib.h
@ -112,12 +112,9 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add more implecit cast operators
|
|
||||||
operator bool() const { return get<bool>(); }
|
operator bool() const { return get<bool>(); }
|
||||||
operator char() const { return get<char>(); }
|
operator char() const { return get<char>(); }
|
||||||
operator wchar_t() const { return get<wchar_t>(); }
|
operator wchar_t() const { return get<wchar_t>(); }
|
||||||
operator char16_t() const { return get<char16_t>(); }
|
|
||||||
operator char32_t() const { return get<char32_t>(); }
|
|
||||||
operator unsigned char() const { return get<unsigned char>(); }
|
operator unsigned char() const { return get<unsigned char>(); }
|
||||||
operator int() const { return get<int>(); }
|
operator int() const { return get<int>(); }
|
||||||
operator unsigned int() const { return get<unsigned int>(); }
|
operator unsigned int() const { return get<unsigned int>(); }
|
||||||
@ -131,6 +128,12 @@ public:
|
|||||||
operator double() const { return get<double>(); }
|
operator double() const { return get<double>(); }
|
||||||
operator const std::string&() const { return get<std::string>(); }
|
operator const std::string&() const { return get<std::string>(); }
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015
|
||||||
|
#else
|
||||||
|
operator char16_t() const { return get<char16_t>(); }
|
||||||
|
operator char32_t() const { return get<char32_t>(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct placeholder {
|
struct placeholder {
|
||||||
virtual ~placeholder() {};
|
virtual ~placeholder() {};
|
||||||
@ -195,16 +198,16 @@ public:
|
|||||||
|
|
||||||
//Action(Action&& rhs) : fn_(std::move(rhs.fn_)) {}
|
//Action(Action&& rhs) : fn_(std::move(rhs.fn_)) {}
|
||||||
|
|
||||||
template <typename F, typename std::enable_if<!std::is_pointer<F>::value && !std::is_null_pointer<F>::value>::type*& = enabler>
|
template <typename F, typename std::enable_if<!std::is_pointer<F>::value && !std::is_same<F, std::nullptr_t>::value>::type*& = enabler>
|
||||||
Action(F fn) : fn_(make_adaptor(fn, &F::operator())) {}
|
Action(F fn) : fn_(make_adaptor(fn, &F::operator())) {}
|
||||||
|
|
||||||
template <typename F, typename std::enable_if<std::is_pointer<F>::value>::type*& = enabler>
|
template <typename F, typename std::enable_if<std::is_pointer<F>::value>::type*& = enabler>
|
||||||
Action(F fn) : fn_(make_adaptor(fn, fn)) {}
|
Action(F fn) : fn_(make_adaptor(fn, fn)) {}
|
||||||
|
|
||||||
template <typename F, typename std::enable_if<std::is_null_pointer<F>::value>::type*& = enabler>
|
template <typename F, typename std::enable_if<std::is_same<F, std::nullptr_t>::value>::type*& = enabler>
|
||||||
Action(F fn) {}
|
Action(F fn) {}
|
||||||
|
|
||||||
template <typename F, typename std::enable_if<!std::is_pointer<F>::value && !std::is_null_pointer<F>::value>::type*& = enabler>
|
template <typename F, typename std::enable_if<!std::is_pointer<F>::value && !std::is_same<F, std::nullptr_t>::value>::type*& = enabler>
|
||||||
void operator=(F fn) {
|
void operator=(F fn) {
|
||||||
fn_ = make_adaptor(fn, &F::operator());
|
fn_ = make_adaptor(fn, &F::operator());
|
||||||
}
|
}
|
||||||
@ -214,7 +217,7 @@ public:
|
|||||||
fn_ = make_adaptor(fn, fn);
|
fn_ = make_adaptor(fn, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F, typename std::enable_if<std::is_null_pointer<F>::value>::type*& = enabler>
|
template <typename F, typename std::enable_if<std::is_same<F, std::nullptr_t>::value>::type*& = enabler>
|
||||||
void operator=(F fn) {}
|
void operator=(F fn) {}
|
||||||
|
|
||||||
operator bool() const {
|
operator bool() const {
|
||||||
@ -363,7 +366,7 @@ Match success(size_t len, size_t choice = 0) {
|
|||||||
return Match{ true, len, choice, nullptr, std::string() };
|
return Match{ true, len, choice, nullptr, std::string() };
|
||||||
}
|
}
|
||||||
|
|
||||||
Match fail(const char* ptr, std::string msg = std::string()) {
|
Match fail(const char* ptr, std::string msg = std::string(), std::string name = std::string()) {
|
||||||
return Match{ false, 0, (size_t)-1, ptr, msg };
|
return Match{ false, 0, (size_t)-1, ptr, msg };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,13 +377,7 @@ class Ope
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Ope() {};
|
virtual ~Ope() {};
|
||||||
|
virtual Match parse(const char* s, size_t l, Values& v) const = 0;
|
||||||
virtual Match parse_core(const char* s, size_t l, Values& v) const = 0;
|
|
||||||
|
|
||||||
virtual Match parse(const char* s, size_t l, Values& v) const {
|
|
||||||
// NOTE: This is a good place to set a break point for debugging...
|
|
||||||
return parse_core(s, l, v);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Sequence : public Ope
|
class Sequence : public Ope
|
||||||
@ -407,12 +404,17 @@ public:
|
|||||||
Sequence(const std::vector<std::shared_ptr<Ope>>& opes) : opes_(opes) {}
|
Sequence(const std::vector<std::shared_ptr<Ope>>& opes) : opes_(opes) {}
|
||||||
Sequence(std::vector<std::shared_ptr<Ope>>&& opes) : opes_(std::move(opes)) {}
|
Sequence(std::vector<std::shared_ptr<Ope>>&& opes) : opes_(std::move(opes)) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (const auto& ope : opes_) {
|
for (const auto& ope : opes_) {
|
||||||
auto m = ope->parse(s + i, l - i, v);
|
const auto& rule = *ope;
|
||||||
|
auto m = rule.parse(s + i, l - i, v);
|
||||||
if (!m.ret) {
|
if (!m.ret) {
|
||||||
return fail(m.ptr, m.msg);
|
auto msg = m.msg;
|
||||||
|
if (msg.empty()) {
|
||||||
|
msg = "missing an element in the 'sequence'";
|
||||||
|
}
|
||||||
|
return fail(m.ptr, msg);
|
||||||
}
|
}
|
||||||
i += m.len;
|
i += m.len;
|
||||||
}
|
}
|
||||||
@ -445,11 +447,12 @@ public:
|
|||||||
PrioritizedChoice(const std::vector<std::shared_ptr<Ope>>& opes) : opes_(opes) {}
|
PrioritizedChoice(const std::vector<std::shared_ptr<Ope>>& opes) : opes_(opes) {}
|
||||||
PrioritizedChoice(std::vector<std::shared_ptr<Ope>>&& opes) : opes_(std::move(opes)) {}
|
PrioritizedChoice(std::vector<std::shared_ptr<Ope>>&& opes) : opes_(std::move(opes)) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
size_t id = 0;
|
size_t id = 0;
|
||||||
for (const auto& ope : opes_) {
|
for (const auto& ope : opes_) {
|
||||||
|
const auto& rule = *ope;
|
||||||
Values chldsv;
|
Values chldsv;
|
||||||
auto m = ope->parse(s, l, chldsv);
|
auto m = rule.parse(s, l, chldsv);
|
||||||
if (m.ret) {
|
if (m.ret) {
|
||||||
if (!chldsv.values.empty()) {
|
if (!chldsv.values.empty()) {
|
||||||
for (const auto& x: chldsv.values) {
|
for (const auto& x: chldsv.values) {
|
||||||
@ -463,7 +466,7 @@ public:
|
|||||||
}
|
}
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
return fail(s, "no choice candidate was matched");
|
return fail(s, "nothing was matched in the 'prioritized choice'");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const { return opes_.size(); }
|
size_t size() const { return opes_.size(); }
|
||||||
@ -477,10 +480,11 @@ class ZeroOrMore : public Ope
|
|||||||
public:
|
public:
|
||||||
ZeroOrMore(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
ZeroOrMore(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
auto i = 0;
|
auto i = 0;
|
||||||
while (l - i > 0) {
|
while (l - i > 0) {
|
||||||
auto m = ope_->parse(s + i, l - i, v);
|
const auto& rule = *ope_;
|
||||||
|
auto m = rule.parse(s + i, l - i, v);
|
||||||
if (!m.ret) {
|
if (!m.ret) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -498,14 +502,19 @@ class OneOrMore : public Ope
|
|||||||
public:
|
public:
|
||||||
OneOrMore(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
OneOrMore(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(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) {
|
||||||
|
auto msg = m.msg;
|
||||||
|
if (msg.empty()) {
|
||||||
|
msg = "nothing occurred in the 'one-or-more'";
|
||||||
|
}
|
||||||
return fail(m.ptr, m.msg);
|
return fail(m.ptr, m.msg);
|
||||||
}
|
}
|
||||||
auto i = m.len;
|
auto i = m.len;
|
||||||
while (l - i > 0) {
|
while (l - i > 0) {
|
||||||
auto m = ope_->parse(s + i, l - i, v);
|
const auto& rule = *ope_;
|
||||||
|
auto m = rule.parse(s + i, l - i, v);
|
||||||
if (!m.ret) {
|
if (!m.ret) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -523,8 +532,9 @@ class Option : public Ope
|
|||||||
public:
|
public:
|
||||||
Option(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
Option(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
auto m = ope_->parse(s, l, v);
|
const auto& rule = *ope_;
|
||||||
|
auto m = rule.parse(s, l, v);
|
||||||
return success(m.ret ? m.len : 0);
|
return success(m.ret ? m.len : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,8 +547,9 @@ class AndPredicate : public Ope
|
|||||||
public:
|
public:
|
||||||
AndPredicate(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
AndPredicate(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
auto m = ope_->parse(s, l, v);
|
const auto& rule = *ope_;
|
||||||
|
auto m = rule.parse(s, l, v);
|
||||||
if (m.ret) {
|
if (m.ret) {
|
||||||
return success(0);
|
return success(0);
|
||||||
} else {
|
} else {
|
||||||
@ -555,8 +566,9 @@ class NotPredicate : public Ope
|
|||||||
public:
|
public:
|
||||||
NotPredicate(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
NotPredicate(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
auto m = ope_->parse(s, l, v);
|
const auto& rule = *ope_;
|
||||||
|
auto m = rule.parse(s, l, v);
|
||||||
if (m.ret) {
|
if (m.ret) {
|
||||||
return fail(s);
|
return fail(s);
|
||||||
} else {
|
} else {
|
||||||
@ -571,9 +583,9 @@ private:
|
|||||||
class LiteralString : public Ope
|
class LiteralString : public Ope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LiteralString(const char* s) : lit_(s) {}
|
LiteralString(const std::string& s) : lit_(s) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
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]) {
|
||||||
@ -590,9 +602,9 @@ private:
|
|||||||
class CharacterClass : public Ope
|
class CharacterClass : public Ope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CharacterClass(const char* chars) : chars_(chars) {}
|
CharacterClass(const std::string& chars) : chars_(chars) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
// TODO: UTF8 support
|
// TODO: UTF8 support
|
||||||
if (l < 1) {
|
if (l < 1) {
|
||||||
return fail(s);
|
return fail(s);
|
||||||
@ -624,7 +636,7 @@ class Character : public Ope
|
|||||||
public:
|
public:
|
||||||
Character(char ch) : ch_(ch) {}
|
Character(char ch) : ch_(ch) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(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(s);
|
return fail(s);
|
||||||
@ -639,7 +651,7 @@ private:
|
|||||||
class AnyCharacter : public Ope
|
class AnyCharacter : public Ope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
// TODO: UTF8 support
|
// TODO: UTF8 support
|
||||||
if (l < 1) {
|
if (l < 1) {
|
||||||
return fail(s);
|
return fail(s);
|
||||||
@ -655,9 +667,10 @@ public:
|
|||||||
Grouping(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
Grouping(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
||||||
Grouping(const std::shared_ptr<Ope>& ope, std::function<void(const char* s, size_t l)> match) : ope_(ope), match_(match) {}
|
Grouping(const std::shared_ptr<Ope>& ope, std::function<void(const char* s, size_t l)> match) : ope_(ope), match_(match) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
assert(ope_);
|
assert(ope_);
|
||||||
auto m = ope_->parse(s, l, v);
|
const auto& rule = *ope_;
|
||||||
|
auto m = rule.parse(s, l, v);
|
||||||
if (m.ret && match_) {
|
if (m.ret && match_) {
|
||||||
match_(s, m.len);
|
match_(s, m.len);
|
||||||
}
|
}
|
||||||
@ -674,10 +687,11 @@ class WeakHolder : public Ope
|
|||||||
public:
|
public:
|
||||||
WeakHolder(const std::shared_ptr<Ope>& ope) : weak_(ope) {}
|
WeakHolder(const std::shared_ptr<Ope>& ope) : weak_(ope) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
auto ope = weak_.lock();
|
auto ope = weak_.lock();
|
||||||
assert(ope);
|
assert(ope);
|
||||||
return ope->parse(s, l, v);
|
const auto& rule = *ope;
|
||||||
|
return rule.parse(s, l, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -740,7 +754,8 @@ public:
|
|||||||
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;
|
||||||
|
|
||||||
auto m = holder_->parse(s, l, v);
|
const auto& rule = *holder_;
|
||||||
|
auto m = rule.parse(s, l, v);
|
||||||
auto ret = m.ret && m.len == l;
|
auto ret = m.ret && m.len == l;
|
||||||
|
|
||||||
if (ret && !v.values.empty() && !v.values.front().is_undefined()) {
|
if (ret && !v.values.empty() && !v.values.front().is_undefined()) {
|
||||||
@ -794,13 +809,14 @@ private:
|
|||||||
Holder(Definition* outer)
|
Holder(Definition* outer)
|
||||||
: outer_(outer) {}
|
: outer_(outer) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
if (!ope_) {
|
if (!ope_) {
|
||||||
throw std::logic_error("Uninitialized definition ope was used...");
|
throw std::logic_error("Uninitialized definition ope was used...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& rule = *ope_;
|
||||||
Values chldsv;
|
Values chldsv;
|
||||||
auto m = ope_->parse(s, l, chldsv);
|
auto m = rule.parse(s, l, chldsv);
|
||||||
if (m.ret) {
|
if (m.ret) {
|
||||||
v.names.push_back(outer_->name);
|
v.names.push_back(outer_->name);
|
||||||
|
|
||||||
@ -847,8 +863,9 @@ public:
|
|||||||
: grammar_(grammar)
|
: grammar_(grammar)
|
||||||
, name_(name) {}
|
, name_(name) {}
|
||||||
|
|
||||||
Match parse_core(const char* s, size_t l, Values& v) const {
|
Match parse(const char* s, size_t l, Values& v) const {
|
||||||
return grammar_.at(name_).holder_->parse(s, l, v);
|
const auto& rule = *grammar_.at(name_).holder_;
|
||||||
|
return rule.parse(s, l, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -891,11 +908,11 @@ inline std::shared_ptr<Ope> npd(const std::shared_ptr<Ope>& ope) {
|
|||||||
return std::make_shared<NotPredicate>(ope);
|
return std::make_shared<NotPredicate>(ope);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<Ope> lit(const char* lit) {
|
inline std::shared_ptr<Ope> lit(const std::string& lit) {
|
||||||
return std::make_shared<LiteralString>(lit);
|
return std::make_shared<LiteralString>(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<Ope> cls(const char* chars) {
|
inline std::shared_ptr<Ope> cls(const std::string& chars) {
|
||||||
return std::make_shared<CharacterClass>(chars);
|
return std::make_shared<CharacterClass>(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,7 +973,7 @@ inline Grammar make_peg_grammar()
|
|||||||
|
|
||||||
g["Range"] <= cho(seq(g["Char"], chr('-'), g["Char"]), g["Char"]);
|
g["Range"] <= cho(seq(g["Char"], chr('-'), g["Char"]), g["Char"]);
|
||||||
g["Char"] <= cho(seq(chr('\\'), cls("nrt'\"[]\\")),
|
g["Char"] <= cho(seq(chr('\\'), cls("nrt'\"[]\\")),
|
||||||
seq(chr('\\'), cls("0-2"), cls("0-7"), cls("0-7")),
|
seq(chr('\\'), cls("0-2"), cls("0-7"), cls("0-7")), // TODO: 0-2 should be 0-3. bug in the spec...
|
||||||
seq(chr('\\'), cls("0-7"), opt(cls("0-7"))),
|
seq(chr('\\'), cls("0-7"), opt(cls("0-7"))),
|
||||||
seq(npd(chr('\\')), any()));
|
seq(npd(chr('\\')), any()));
|
||||||
|
|
||||||
@ -985,7 +1002,7 @@ inline Grammar make_peg_grammar()
|
|||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::pair<size_t, size_t> find_line(const char* s, const char* ptr) {
|
inline std::pair<size_t, size_t> line_info(const char* s, const char* ptr) {
|
||||||
auto p = s;
|
auto p = s;
|
||||||
auto col_ptr = p;
|
auto col_ptr = p;
|
||||||
auto no = 1;
|
auto no = 1;
|
||||||
@ -1003,9 +1020,38 @@ inline std::pair<size_t, size_t> find_line(const char* s, const char* ptr) {
|
|||||||
return std::make_pair(no, col);
|
return std::make_pair(no, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::string resolve_escape_sequence(const char*s, size_t l) {
|
||||||
|
std::string r;
|
||||||
|
r.reserve(l);
|
||||||
|
for (auto i = 0u; i < l; i++) {
|
||||||
|
auto ch = s[i];
|
||||||
|
if (ch == '\\') {
|
||||||
|
i++;
|
||||||
|
switch (s[i]) {
|
||||||
|
case 'n': r += '\n'; break;
|
||||||
|
case 'r': r += '\r'; break;
|
||||||
|
case 't': r += '\t'; break;
|
||||||
|
case '\'': r += '\''; break;
|
||||||
|
case '"': r += '"'; break;
|
||||||
|
case '[': r += '['; break;
|
||||||
|
case ']': r += ']'; break;
|
||||||
|
case '\\': r += '\\'; break;
|
||||||
|
default: {
|
||||||
|
// TODO: Octal number support
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<Grammar> make_grammar(
|
inline std::shared_ptr<Grammar> make_grammar(
|
||||||
const char* syntax, size_t syntax_len, std::string& start,
|
const char* syntax, size_t syntax_len, std::string& start,
|
||||||
std::function<void (size_t, size_t, const std::string)> log = nullptr)
|
std::function<void (size_t, size_t, const std::string&)> log = nullptr)
|
||||||
{
|
{
|
||||||
Grammar peg = make_peg_grammar();
|
Grammar peg = make_peg_grammar();
|
||||||
|
|
||||||
@ -1027,21 +1073,31 @@ inline std::shared_ptr<Grammar> make_grammar(
|
|||||||
};
|
};
|
||||||
|
|
||||||
peg["Expression"] = [&](const std::vector<Any>& v) {
|
peg["Expression"] = [&](const std::vector<Any>& v) {
|
||||||
std::vector<std::shared_ptr<Ope>> opes;
|
if (v.size() == 1) {
|
||||||
for (auto i = 0u; i < v.size(); i++) {
|
return v[0].get<std::shared_ptr<Ope>>();
|
||||||
if (!(i % 2)) {
|
} else {
|
||||||
opes.push_back(v[i].get<std::shared_ptr<Ope>>());
|
std::vector<std::shared_ptr<Ope>> opes;
|
||||||
|
for (auto i = 0u; i < v.size(); i++) {
|
||||||
|
if (!(i % 2)) {
|
||||||
|
opes.push_back(v[i].get<std::shared_ptr<Ope>>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
const std::shared_ptr<Ope> ope = std::make_shared<PrioritizedChoice>(opes);
|
||||||
|
return ope;
|
||||||
}
|
}
|
||||||
return static_cast<std::shared_ptr<Ope>>(std::make_shared<PrioritizedChoice>(opes));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["Sequence"] = [&](const std::vector<Any>& v) {
|
peg["Sequence"] = [&](const std::vector<Any>& v) {
|
||||||
std::vector<std::shared_ptr<Ope>> opes;
|
if (v.size() == 1) {
|
||||||
for (const auto& x: v) {
|
return v[0].get<std::shared_ptr<Ope>>();
|
||||||
opes.push_back(x.get<std::shared_ptr<Ope>>());
|
} else {
|
||||||
|
std::vector<std::shared_ptr<Ope>> opes;
|
||||||
|
for (const auto& x: v) {
|
||||||
|
opes.push_back(x.get<std::shared_ptr<Ope>>());
|
||||||
|
}
|
||||||
|
const std::shared_ptr<Ope> ope = std::make_shared<Sequence>(opes);
|
||||||
|
return ope;
|
||||||
}
|
}
|
||||||
return static_cast<std::shared_ptr<Ope>>(std::make_shared<Sequence>(opes));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["Prefix"] = [&](const std::vector<Any>& v, const std::vector<std::string>& n) {
|
peg["Prefix"] = [&](const std::vector<Any>& v, const std::vector<std::string>& n) {
|
||||||
@ -1094,20 +1150,20 @@ inline std::shared_ptr<Grammar> make_grammar(
|
|||||||
};
|
};
|
||||||
|
|
||||||
peg["Literal"] = [](const std::vector<Any>& v) {
|
peg["Literal"] = [](const std::vector<Any>& v) {
|
||||||
return lit(v[0].get<std::string>().c_str());
|
return lit(v[0]);
|
||||||
};
|
};
|
||||||
peg["SQCont"] = [](const char*s, size_t l) {
|
peg["SQCont"] = [](const char*s, size_t l) {
|
||||||
return std::string(s, l);
|
return resolve_escape_sequence(s, l);
|
||||||
};
|
};
|
||||||
peg["DQCont"] = [](const char*s, size_t l) {
|
peg["DQCont"] = [](const char*s, size_t l) {
|
||||||
return std::string(s, l);
|
return resolve_escape_sequence(s, l);
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["Class"] = [](const std::vector<Any>& v) {
|
peg["Class"] = [](const std::vector<Any>& v) {
|
||||||
return cls(v[0].get<std::string>().c_str());
|
return cls(v[0]);
|
||||||
};
|
};
|
||||||
peg["ClassCont"] = [](const char*s, size_t l) {
|
peg["ClassCont"] = [](const char*s, size_t l) {
|
||||||
return std::string(s, l);
|
return resolve_escape_sequence(s, l);
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["DOT"] = []() {
|
peg["DOT"] = []() {
|
||||||
@ -1117,7 +1173,7 @@ inline std::shared_ptr<Grammar> make_grammar(
|
|||||||
auto m = peg["Grammar"].parse_with_match(syntax, syntax_len);
|
auto m = peg["Grammar"].parse_with_match(syntax, syntax_len);
|
||||||
if (!m.ret) {
|
if (!m.ret) {
|
||||||
if (log) {
|
if (log) {
|
||||||
auto line = find_line(syntax, m.ptr);
|
auto line = line_info(syntax, m.ptr);
|
||||||
log(line.first, line.second, m.msg.empty() ? "syntax error" : m.msg);
|
log(line.first, line.second, m.msg.empty() ? "syntax error" : m.msg);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -1128,7 +1184,7 @@ inline std::shared_ptr<Grammar> make_grammar(
|
|||||||
auto ptr = x.second;
|
auto ptr = x.second;
|
||||||
if (grammar->find(name) == grammar->end()) {
|
if (grammar->find(name) == grammar->end()) {
|
||||||
if (log) {
|
if (log) {
|
||||||
auto line = find_line(syntax, ptr);
|
auto line = line_info(syntax, ptr);
|
||||||
log(line.first, line.second, "'" + name + "' is not defined.");
|
log(line.first, line.second, "'" + name + "' is not defined.");
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -1140,7 +1196,7 @@ inline std::shared_ptr<Grammar> make_grammar(
|
|||||||
|
|
||||||
inline std::shared_ptr<Grammar> make_grammar(
|
inline std::shared_ptr<Grammar> make_grammar(
|
||||||
const char* syntax, std::string& start,
|
const char* syntax, std::string& start,
|
||||||
std::function<void (size_t, size_t, const std::string)> log = nullptr)
|
std::function<void (size_t, size_t, const std::string&)> log = nullptr)
|
||||||
{
|
{
|
||||||
return make_grammar(syntax, strlen(syntax), start, log);
|
return make_grammar(syntax, strlen(syntax), start, log);
|
||||||
}
|
}
|
||||||
@ -1156,30 +1212,17 @@ public:
|
|||||||
return grammar_ != nullptr;
|
return grammar_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_syntax(const char* s, size_t l, std::function<void (size_t, size_t, const std::string&)> log) {
|
bool load_syntax(const char* s, size_t l, std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
||||||
grammar_ = make_grammar(s, l, start_, log);
|
grammar_ = make_grammar(s, l, start_, log);
|
||||||
return grammar_ != nullptr;
|
return grammar_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(const char* s, Any& val) const {
|
|
||||||
if (grammar_ != nullptr)
|
|
||||||
return (*grammar_)[start_].parse(s, val);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool parse(const char* s) const {
|
|
||||||
if (grammar_ != nullptr) {
|
|
||||||
Any val;
|
|
||||||
return (*grammar_)[start_].parse(s, val);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool parse(const char* s, T& out) const {
|
bool parse(const char* s, size_t l, T& out) const {
|
||||||
if (grammar_ != nullptr) {
|
if (grammar_ != nullptr) {
|
||||||
|
const auto& rule = (*grammar_)[start_];
|
||||||
Any val;
|
Any val;
|
||||||
auto ret = (*grammar_)[start_].parse(s, val);
|
auto ret = rule.parse(s, l, val);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
out = val.get<T>();
|
out = val.get<T>();
|
||||||
}
|
}
|
||||||
@ -1188,6 +1231,33 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool parse(const char* s, size_t l) const {
|
||||||
|
if (grammar_ != nullptr) {
|
||||||
|
const auto& rule = (*grammar_)[start_];
|
||||||
|
return rule.parse(s, l);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool parse(const char* s, T& out) const {
|
||||||
|
auto l = strlen(s);
|
||||||
|
return parse(s, l, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse(const char* s) const {
|
||||||
|
auto l = strlen(s);
|
||||||
|
return parse(s, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
Match lint(const char* s, size_t l) const {
|
||||||
|
if (grammar_ != nullptr) {
|
||||||
|
const auto& rule = (*grammar_)[start_];
|
||||||
|
return rule.parse_with_match(s, l);
|
||||||
|
}
|
||||||
|
return Match{ false, 0, (size_t)-1, s, "invalid grammar" };
|
||||||
|
}
|
||||||
|
|
||||||
Definition& operator[](const char* s) {
|
Definition& operator[](const char* s) {
|
||||||
return (*grammar_)[s];
|
return (*grammar_)[s];
|
||||||
}
|
}
|
||||||
@ -1205,7 +1275,8 @@ inline Parser make_parser(const char* s, size_t l, std::function<void (size_t, s
|
|||||||
|
|
||||||
inline Parser make_parser(const char* s, std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
inline Parser make_parser(const char* s, std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
||||||
Parser parser;
|
Parser parser;
|
||||||
parser.load_syntax(s, strlen(s), log);
|
auto l = strlen(s);
|
||||||
|
parser.load_syntax(s, l, log);
|
||||||
return parser;
|
return parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,9 @@
|
|||||||
|
|
||||||
TEST_CASE("Empty syntax test", "[general]")
|
TEST_CASE("Empty syntax test", "[general]")
|
||||||
{
|
{
|
||||||
REQUIRE_THROWS(peglib::make_parser(""));
|
auto parser = peglib::make_parser("");
|
||||||
|
bool ret = parser;
|
||||||
|
REQUIRE(ret == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("String capture test", "[general]")
|
TEST_CASE("String capture test", "[general]")
|
||||||
|
Loading…
Reference in New Issue
Block a user