mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Changed the interfaces.
This commit is contained in:
parent
6e8ea2b471
commit
3f639e37f0
36
README.md
36
README.md
@ -28,7 +28,7 @@ Here is how to parse text with the PEG syntax and retrieve tag names:
|
|||||||
#include "peglib.h"
|
#include "peglib.h"
|
||||||
|
|
||||||
// (2) Make a parser
|
// (2) Make a parser
|
||||||
auto parser = peglib::make_parser(R"(
|
peglib::peg parser(R"(
|
||||||
ROOT <- _ ('[' TAG_NAME ']' _)*
|
ROOT <- _ ('[' TAG_NAME ']' _)*
|
||||||
TAG_NAME <- (!']' .)+
|
TAG_NAME <- (!']' .)+
|
||||||
_ <- [ \t]*
|
_ <- [ \t]*
|
||||||
@ -41,7 +41,7 @@ parser["TAG_NAME"] = [&](const char* s, size_t l) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// (4) Parse
|
// (4) Parse
|
||||||
auto ret = parser.parse(" [tag1] [tag:2] [tag-3] ");
|
auto ret = parser.match(" [tag1] [tag:2] [tag-3] ");
|
||||||
|
|
||||||
assert(ret == true);
|
assert(ret == true);
|
||||||
assert(tags[0] == "tag1");
|
assert(tags[0] == "tag1");
|
||||||
@ -54,15 +54,15 @@ This action `[&](const char* s, size_t l)` gives a pointer and length of the mat
|
|||||||
There are more actions available. Here is a complete list:
|
There are more actions available. Here is a complete list:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
[](const char* s, size_t l, const std::vector<peglib::Any>& v, const std::vector<std::string>& n)
|
[](const char* s, size_t l, const std::vector<peglib::any>& v, const std::vector<std::string>& n)
|
||||||
[](const char* s, size_t l, const std::vector<peglib::Any>& v)
|
[](const char* s, size_t l, const std::vector<peglib::any>& v)
|
||||||
[](const char* s, size_t l)
|
[](const char* s, size_t l)
|
||||||
[](const std::vector<peglib::Any>& v, const std::vector<std::string>& n)
|
[](const std::vector<peglib::any>& v, const std::vector<std::string>& n)
|
||||||
[](const std::vector<peglib::Any>& v)
|
[](const std::vector<peglib::any>& v)
|
||||||
[]()
|
[]()
|
||||||
```
|
```
|
||||||
|
|
||||||
`const std::vector<peglib::Any>& v` contains semantic values. `peglib::Any` class is very similar to [boost::any](http://www.boost.org/doc/libs/1_57_0/doc/html/any.html). You can obtain a value by castning it to the actual type. In order to determine the actual type, you have to check the return value type of the child action for the semantic value.
|
`const std::vector<peglib::any>& v` contains semantic values. `peglib::any` class is very similar to [boost::any](http://www.boost.org/doc/libs/1_57_0/doc/html/any.html). You can obtain a value by castning it to the actual type. In order to determine the actual type, you have to check the return value type of the child action for the semantic value.
|
||||||
|
|
||||||
`const std::vector<std::string>& n` contains definition names of semantic values.
|
`const std::vector<std::string>& n` contains definition names of semantic values.
|
||||||
|
|
||||||
@ -84,34 +84,34 @@ int main(void) {
|
|||||||
Number <- [0-9]+
|
Number <- [0-9]+
|
||||||
)";
|
)";
|
||||||
|
|
||||||
auto parser = make_parser(syntax);
|
peg parser(syntax);
|
||||||
|
|
||||||
parser["Additive"] = {
|
parser["Additive"] = {
|
||||||
nullptr, // Default action
|
nullptr, // Default action
|
||||||
[](const vector<Any>& v) {
|
[](const vector<any>& v) {
|
||||||
return v[0].get<int>() + v[1].get<int>(); // 1st choice
|
return v[0].get<int>() + v[1].get<int>(); // 1st choice
|
||||||
},
|
},
|
||||||
[](const vector<Any>& v) { return v[0]; } // 2nd choice
|
[](const vector<any>& v) { return v[0]; } // 2nd choice
|
||||||
};
|
};
|
||||||
|
|
||||||
parser["Multitive"] = {
|
parser["Multitive"] = {
|
||||||
nullptr, // Default action
|
nullptr, // Default action
|
||||||
[](const vector<Any>& v) {
|
[](const vector<any>& v) {
|
||||||
return v[0].get<int>() * v[1].get<int>(); // 1st choice
|
return v[0].get<int>() * v[1].get<int>(); // 1st choice
|
||||||
},
|
},
|
||||||
[](const vector<Any>& v) { return v[0]; } // 2nd choice
|
[](const vector<any>& v) { return v[0]; } // 2nd choice
|
||||||
};
|
};
|
||||||
|
|
||||||
parser["Primary"] = [](const vector<Any>& v) {
|
parser["Primary"] = [](const vector<any>& v) {
|
||||||
return v.size() == 1 ? v[0] : v[1];
|
return v.size() == 1 ? v[0] : v[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
parser["Number"] = [](const char* s, size_t l) -> long {
|
parser["Number"] = [](const char* s, size_t l) {
|
||||||
return stoi(string(s, l), nullptr, 10);
|
return stoi(string(s, l), nullptr, 10);
|
||||||
};
|
};
|
||||||
|
|
||||||
int val;
|
int val;
|
||||||
parser.parse("1+2*3", val);
|
parser.match("1+2*3", val);
|
||||||
|
|
||||||
assert(val == 7);
|
assert(val == 7);
|
||||||
}
|
}
|
||||||
@ -130,14 +130,12 @@ vector<string> tags;
|
|||||||
|
|
||||||
Definition ROOT, TAG_NAME, _;
|
Definition ROOT, TAG_NAME, _;
|
||||||
ROOT = seq(_, zom(seq(chr('['), TAG_NAME, chr(']'), _)));
|
ROOT = seq(_, zom(seq(chr('['), TAG_NAME, chr(']'), _)));
|
||||||
TAG_NAME = oom(seq(npd(chr(']')), any())), [&](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)); };
|
||||||
_ = zom(cls(" \t"));
|
_ = zom(cls(" \t"));
|
||||||
|
|
||||||
auto ret = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
|
auto ret = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
|
||||||
```
|
```
|
||||||
|
|
||||||
In fact, the PEG parser generator is made with the parser operators. You can see the code at `make_peg_grammar` function in `peglib.h`.
|
|
||||||
|
|
||||||
The following are available operators:
|
The following are available operators:
|
||||||
|
|
||||||
| Operator | Description |
|
| Operator | Description |
|
||||||
@ -153,7 +151,7 @@ The following are available operators:
|
|||||||
| lit | Literal string |
|
| lit | Literal string |
|
||||||
| cls | Character class |
|
| cls | Character class |
|
||||||
| chr | Character |
|
| chr | Character |
|
||||||
| any | Any character |
|
| dot | Any character |
|
||||||
|
|
||||||
Sample codes
|
Sample codes
|
||||||
------------
|
------------
|
||||||
|
@ -31,7 +31,7 @@ int main(int argc, const char** argv)
|
|||||||
|
|
||||||
const char* s = argv[1];
|
const char* s = argv[1];
|
||||||
|
|
||||||
auto reduce = [](const vector<Any>& v) -> long {
|
auto reduce = [](const vector<any>& v) -> long {
|
||||||
auto result = v[0].get<long>();
|
auto result = v[0].get<long>();
|
||||||
for (auto i = 1u; i < v.size(); i += 2) {
|
for (auto i = 1u; i < v.size(); i += 2) {
|
||||||
auto num = v[i + 1].get<long>();
|
auto num = v[i + 1].get<long>();
|
||||||
@ -55,7 +55,7 @@ int main(int argc, const char** argv)
|
|||||||
" NUMBER <- [0-9]+ "
|
" NUMBER <- [0-9]+ "
|
||||||
;
|
;
|
||||||
|
|
||||||
Parser parser(syntax);
|
peg parser(syntax);
|
||||||
|
|
||||||
parser["EXPRESSION"] = reduce;
|
parser["EXPRESSION"] = reduce;
|
||||||
parser["TERM"] = reduce;
|
parser["TERM"] = reduce;
|
||||||
@ -64,7 +64,7 @@ int main(int argc, const char** argv)
|
|||||||
parser["NUMBER"] = [](const char* s, size_t l) { return atol(s); };
|
parser["NUMBER"] = [](const char* s, size_t l) { return atol(s); };
|
||||||
|
|
||||||
long val = 0;
|
long val = 0;
|
||||||
if (parser.parse(s, val)) {
|
if (parser.match(s, val)) {
|
||||||
cout << s << " = " << val << endl;
|
cout << s << " = " << val << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ int main(int argc, const char** argv)
|
|||||||
|
|
||||||
const char* s = argv[1];
|
const char* s = argv[1];
|
||||||
|
|
||||||
auto reduce = [](const vector<Any>& v) -> long {
|
auto reduce = [](const vector<any>& v) -> long {
|
||||||
auto result = v[0].get<long>();
|
auto result = v[0].get<long>();
|
||||||
for (auto i = 1u; i < v.size(); i += 2) {
|
for (auto i = 1u; i < v.size(); i += 2) {
|
||||||
auto num = v[i + 1].get<long>();
|
auto num = v[i + 1].get<long>();
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "mmap.h"
|
#include "mmap.h"
|
||||||
|
|
||||||
using namespace peglib;
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int main(int argc, const char** argv)
|
int main(int argc, const char** argv)
|
||||||
@ -28,7 +27,7 @@ int main(int argc, const char** argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parser = make_parser(syntax.data(), syntax.size(), [&](size_t ln, size_t col, const string& msg) {
|
peglib::peg parser(syntax.data(), syntax.size(), [&](size_t ln, size_t col, const string& msg) {
|
||||||
cerr << syntax_path << ":" << ln << ":" << col << ": " << msg << endl;
|
cerr << syntax_path << ":" << ln << ":" << col << ": " << msg << endl;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
242
peglib.h
242
peglib.h
@ -23,24 +23,24 @@ namespace peglib {
|
|||||||
void* enabler;
|
void* enabler;
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* Any
|
* any
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
class Any
|
class any
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Any() : content_(nullptr) {}
|
any() : content_(nullptr) {}
|
||||||
|
|
||||||
Any(const Any& rhs) : content_(rhs.clone()) {}
|
any(const any& rhs) : content_(rhs.clone()) {}
|
||||||
|
|
||||||
Any(Any&& rhs) : content_(rhs.content_) {
|
any(any&& rhs) : content_(rhs.content_) {
|
||||||
rhs.content_ = nullptr;
|
rhs.content_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Any(const T& value) : content_(new holder<T>(value)) {}
|
any(const T& value) : content_(new holder<T>(value)) {}
|
||||||
|
|
||||||
Any& operator=(const Any& rhs) {
|
any& operator=(const any& rhs) {
|
||||||
if (this != &rhs) {
|
if (this != &rhs) {
|
||||||
if (content_) {
|
if (content_) {
|
||||||
delete content_;
|
delete content_;
|
||||||
@ -50,7 +50,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Any& operator=(Any&& rhs) {
|
any& operator=(any&& rhs) {
|
||||||
if (this != &rhs) {
|
if (this != &rhs) {
|
||||||
if (content_) {
|
if (content_) {
|
||||||
delete content_;
|
delete content_;
|
||||||
@ -62,7 +62,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Any& operator=(const T& value) {
|
any& operator=(const T& value) {
|
||||||
if (content_) {
|
if (content_) {
|
||||||
delete content_;
|
delete content_;
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Any() {
|
~any() {
|
||||||
delete content_;
|
delete content_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ public:
|
|||||||
|
|
||||||
template <
|
template <
|
||||||
typename T,
|
typename T,
|
||||||
typename std::enable_if<!std::is_same<T, Any>::value>::type*& = enabler
|
typename std::enable_if<!std::is_same<T, any>::value>::type*& = enabler
|
||||||
>
|
>
|
||||||
T& get() {
|
T& get() {
|
||||||
assert(content_);
|
assert(content_);
|
||||||
@ -89,7 +89,7 @@ public:
|
|||||||
|
|
||||||
template <
|
template <
|
||||||
typename T,
|
typename T,
|
||||||
typename std::enable_if<std::is_same<T, Any>::value>::type*& = enabler
|
typename std::enable_if<std::is_same<T, any>::value>::type*& = enabler
|
||||||
>
|
>
|
||||||
T& get() {
|
T& get() {
|
||||||
return *this;
|
return *this;
|
||||||
@ -97,7 +97,7 @@ public:
|
|||||||
|
|
||||||
template <
|
template <
|
||||||
typename T,
|
typename T,
|
||||||
typename std::enable_if<!std::is_same<T, Any>::value>::type*& = enabler
|
typename std::enable_if<!std::is_same<T, any>::value>::type*& = enabler
|
||||||
>
|
>
|
||||||
const T& get() const {
|
const T& get() const {
|
||||||
assert(content_);
|
assert(content_);
|
||||||
@ -106,9 +106,9 @@ public:
|
|||||||
|
|
||||||
template <
|
template <
|
||||||
typename T,
|
typename T,
|
||||||
typename std::enable_if<std::is_same<T, Any>::value>::type*& = enabler
|
typename std::enable_if<std::is_same<T, any>::value>::type*& = enabler
|
||||||
>
|
>
|
||||||
const Any& get() const {
|
const any& get() const {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ private:
|
|||||||
struct Values
|
struct Values
|
||||||
{
|
{
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
std::vector<Any> values;
|
std::vector<any> values;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -176,17 +176,17 @@ template <
|
|||||||
typename R, typename F,
|
typename R, typename F,
|
||||||
typename std::enable_if<!std::is_void<R>::value>::type*& = enabler,
|
typename std::enable_if<!std::is_void<R>::value>::type*& = enabler,
|
||||||
typename... Args>
|
typename... Args>
|
||||||
Any call(F fn, Args&&... args) {
|
any call(F fn, Args&&... args) {
|
||||||
return Any(fn(std::forward<Args>(args)...));
|
return any(fn(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename R, typename F,
|
typename R, typename F,
|
||||||
typename std::enable_if<std::is_void<R>::value>::type*& = enabler,
|
typename std::enable_if<std::is_void<R>::value>::type*& = enabler,
|
||||||
typename... Args>
|
typename... Args>
|
||||||
Any call(F fn, Args&&... args) {
|
any call(F fn, Args&&... args) {
|
||||||
fn(std::forward<Args>(args)...);
|
fn(std::forward<Args>(args)...);
|
||||||
return Any();
|
return any();
|
||||||
}
|
}
|
||||||
|
|
||||||
class Action
|
class Action
|
||||||
@ -224,35 +224,35 @@ public:
|
|||||||
return (bool)fn_;
|
return (bool)fn_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Any operator()(const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n) const {
|
any operator()(const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n) const {
|
||||||
return fn_(s, l, v, n);
|
return fn_(s, l, v, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename R>
|
template <typename R>
|
||||||
struct TypeAdaptor {
|
struct TypeAdaptor {
|
||||||
TypeAdaptor(std::function<R (const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n)> fn)
|
TypeAdaptor(std::function<R (const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n)> fn)
|
||||||
: fn_(fn) {}
|
: fn_(fn) {}
|
||||||
Any operator()(const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n) {
|
any operator()(const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n) {
|
||||||
return call<R>(fn_, s, l, v, n);
|
return call<R>(fn_, s, l, v, n);
|
||||||
}
|
}
|
||||||
std::function<R (const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n)> fn_;
|
std::function<R (const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n)> fn_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename R>
|
template <typename R>
|
||||||
struct TypeAdaptor_s_l_v {
|
struct TypeAdaptor_s_l_v {
|
||||||
TypeAdaptor_s_l_v(std::function<R (const char* s, size_t l, const std::vector<Any>& v)> fn)
|
TypeAdaptor_s_l_v(std::function<R (const char* s, size_t l, const std::vector<any>& v)> fn)
|
||||||
: fn_(fn) {}
|
: fn_(fn) {}
|
||||||
Any operator()(const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n) {
|
any operator()(const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n) {
|
||||||
return call<R>(fn_, s, l, v);
|
return call<R>(fn_, s, l, v);
|
||||||
}
|
}
|
||||||
std::function<R (const char* s, size_t l, const std::vector<Any>& v)> fn_;
|
std::function<R (const char* s, size_t l, const std::vector<any>& v)> fn_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename R>
|
template <typename R>
|
||||||
struct TypeAdaptor_s_l {
|
struct TypeAdaptor_s_l {
|
||||||
TypeAdaptor_s_l(std::function<R (const char* s, size_t l)> fn) : fn_(fn) {}
|
TypeAdaptor_s_l(std::function<R (const char* s, size_t l)> fn) : fn_(fn) {}
|
||||||
Any operator()(const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n) {
|
any operator()(const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n) {
|
||||||
return call<R>(fn_, s, l);
|
return call<R>(fn_, s, l);
|
||||||
}
|
}
|
||||||
std::function<R (const char* s, size_t l)> fn_;
|
std::function<R (const char* s, size_t l)> fn_;
|
||||||
@ -260,50 +260,50 @@ private:
|
|||||||
|
|
||||||
template <typename R>
|
template <typename R>
|
||||||
struct TypeAdaptor_v_n {
|
struct TypeAdaptor_v_n {
|
||||||
TypeAdaptor_v_n(std::function<R (const std::vector<Any>& v, const std::vector<std::string>& n)> fn) : fn_(fn) {}
|
TypeAdaptor_v_n(std::function<R (const std::vector<any>& v, const std::vector<std::string>& n)> fn) : fn_(fn) {}
|
||||||
Any operator()(const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n) {
|
any operator()(const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n) {
|
||||||
return call<R>(fn_, v, n);
|
return call<R>(fn_, v, n);
|
||||||
}
|
}
|
||||||
std::function<R (const std::vector<Any>& v, const std::vector<std::string>& n)> fn_;
|
std::function<R (const std::vector<any>& v, const std::vector<std::string>& n)> fn_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename R>
|
template <typename R>
|
||||||
struct TypeAdaptor_v {
|
struct TypeAdaptor_v {
|
||||||
TypeAdaptor_v(std::function<R (const std::vector<Any>& v)> fn) : fn_(fn) {}
|
TypeAdaptor_v(std::function<R (const std::vector<any>& v)> fn) : fn_(fn) {}
|
||||||
Any operator()(const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n) {
|
any operator()(const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n) {
|
||||||
return call<R>(fn_, v);
|
return call<R>(fn_, v);
|
||||||
}
|
}
|
||||||
std::function<R (const std::vector<Any>& v)> fn_;
|
std::function<R (const std::vector<any>& v)> fn_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename R>
|
template <typename R>
|
||||||
struct TypeAdaptor_empty {
|
struct TypeAdaptor_empty {
|
||||||
TypeAdaptor_empty(std::function<R ()> fn) : fn_(fn) {}
|
TypeAdaptor_empty(std::function<R ()> fn) : fn_(fn) {}
|
||||||
Any operator()(const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n) {
|
any operator()(const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n) {
|
||||||
return call<R>(fn_);
|
return call<R>(fn_);
|
||||||
}
|
}
|
||||||
std::function<R ()> fn_;
|
std::function<R ()> fn_;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::function<Any (const char* s, size_t l, const std::vector<Any>& v, const std::vector<std::string>& n)> Fty;
|
typedef std::function<any (const char* s, size_t l, const std::vector<any>& v, const std::vector<std::string>& n)> Fty;
|
||||||
|
|
||||||
template<typename F, typename R>
|
template<typename F, typename R>
|
||||||
Fty make_adaptor(F fn, R (F::*mf)(const char*, size_t, const std::vector<Any>& v, const std::vector<std::string>& n) const) {
|
Fty make_adaptor(F fn, R (F::*mf)(const char*, size_t, const std::vector<any>& v, const std::vector<std::string>& n) const) {
|
||||||
return TypeAdaptor<R>(fn);
|
return TypeAdaptor<R>(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename R>
|
template<typename F, typename R>
|
||||||
Fty make_adaptor(F fn, R(*mf)(const char*, size_t, const std::vector<Any>& v, const std::vector<std::string>& n)) {
|
Fty make_adaptor(F fn, R(*mf)(const char*, size_t, const std::vector<any>& v, const std::vector<std::string>& n)) {
|
||||||
return TypeAdaptor<R>(fn);
|
return TypeAdaptor<R>(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename R>
|
template<typename F, typename R>
|
||||||
Fty make_adaptor(F fn, R (F::*mf)(const char*, size_t, const std::vector<Any>& v) const) {
|
Fty make_adaptor(F fn, R (F::*mf)(const char*, size_t, const std::vector<any>& v) const) {
|
||||||
return TypeAdaptor_s_l_v<R>(fn);
|
return TypeAdaptor_s_l_v<R>(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename R>
|
template<typename F, typename R>
|
||||||
Fty make_adaptor(F fn, R(*mf)(const char*, size_t, const std::vector<Any>& v)) {
|
Fty make_adaptor(F fn, R(*mf)(const char*, size_t, const std::vector<any>& v)) {
|
||||||
return TypeAdaptor_s_l_v<R>(fn);
|
return TypeAdaptor_s_l_v<R>(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,22 +318,22 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename R>
|
template<typename F, typename R>
|
||||||
Fty make_adaptor(F fn, R (F::*mf)(const std::vector<Any>& v, const std::vector<std::string>& n) const) {
|
Fty make_adaptor(F fn, R (F::*mf)(const std::vector<any>& v, const std::vector<std::string>& n) const) {
|
||||||
return TypeAdaptor_v_n<R>(fn);
|
return TypeAdaptor_v_n<R>(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename R>
|
template<typename F, typename R>
|
||||||
Fty make_adaptor(F fn, R (*mf)(const std::vector<Any>& v, const std::vector<std::string>& n)) {
|
Fty make_adaptor(F fn, R (*mf)(const std::vector<any>& v, const std::vector<std::string>& n)) {
|
||||||
return TypeAdaptor_v_n<R>(fn);
|
return TypeAdaptor_v_n<R>(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename R>
|
template<typename F, typename R>
|
||||||
Fty make_adaptor(F fn, R (F::*mf)(const std::vector<Any>& v) const) {
|
Fty make_adaptor(F fn, R (F::*mf)(const std::vector<any>& v) const) {
|
||||||
return TypeAdaptor_v<R>(fn);
|
return TypeAdaptor_v<R>(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename R>
|
template<typename F, typename R>
|
||||||
Fty make_adaptor(F fn, R (*mf)(const std::vector<Any>& v)) {
|
Fty make_adaptor(F fn, R (*mf)(const std::vector<any>& v)) {
|
||||||
return TypeAdaptor_v<R>(fn);
|
return TypeAdaptor_v<R>(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,11 +818,11 @@ private:
|
|||||||
private:
|
private:
|
||||||
friend class Definition;
|
friend class Definition;
|
||||||
|
|
||||||
Any reduce(const char* s, size_t l, const Values& v, const Action& action) const {
|
any reduce(const char* s, size_t l, const Values& v, const Action& action) const {
|
||||||
if (action) {
|
if (action) {
|
||||||
return action(s, l, v.values, v.names);
|
return action(s, l, v.values, v.names);
|
||||||
} else if (v.values.empty()) {
|
} else if (v.values.empty()) {
|
||||||
return Any();
|
return any();
|
||||||
} else {
|
} else {
|
||||||
return v.values.front();
|
return v.values.front();
|
||||||
}
|
}
|
||||||
@ -903,7 +903,7 @@ inline std::shared_ptr<Ope> chr(char c) {
|
|||||||
return std::make_shared<Character>(c);
|
return std::make_shared<Character>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<Ope> any() {
|
inline std::shared_ptr<Ope> dot() {
|
||||||
return std::make_shared<AnyCharacter>();
|
return std::make_shared<AnyCharacter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -923,12 +923,51 @@ inline std::shared_ptr<Ope> ref(const std::map<std::string, Definition>& grammar
|
|||||||
* PEG parser generator
|
* PEG parser generator
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
inline std::pair<size_t, size_t> line_info(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);
|
||||||
|
}
|
||||||
|
|
||||||
typedef std::map<std::string, Definition> Grammar;
|
typedef std::map<std::string, Definition> Grammar;
|
||||||
|
typedef std::function<void (size_t, size_t, const std::string&)> Log;
|
||||||
|
|
||||||
inline Grammar make_peg_grammar()
|
class PEGParser
|
||||||
{
|
{
|
||||||
Grammar g;
|
public:
|
||||||
|
static std::shared_ptr<Grammar> parse(const char* s, size_t l, std::string& start, Log log) {
|
||||||
|
static PEGParser instance;
|
||||||
|
return get().perform_core(s, l, start, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Grammar& grammar() {
|
||||||
|
return get().g;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static PEGParser& get() {
|
||||||
|
static PEGParser instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
PEGParser() {
|
||||||
|
make_grammar();
|
||||||
|
setup_actions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void make_grammar() {
|
||||||
// Setup PEG syntax parser
|
// Setup PEG syntax parser
|
||||||
g["Grammar"] <= seq(g["Spacing"], oom(g["Definition"]), g["EndOfFile"]);
|
g["Grammar"] <= seq(g["Spacing"], oom(g["Definition"]), g["EndOfFile"]);
|
||||||
g["Definition"] <= seq(g["Identifier"], g["LEFTARROW"], g["Expression"]);
|
g["Definition"] <= seq(g["Identifier"], g["LEFTARROW"], g["Expression"]);
|
||||||
@ -958,7 +997,7 @@ inline Grammar make_peg_grammar()
|
|||||||
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")), // TODO: 0-2 should be 0-3. bug in the spec...
|
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('\\')), dot()));
|
||||||
|
|
||||||
g["LEFTARROW"] <= seq(lit("<-"), g["Spacing"]);
|
g["LEFTARROW"] <= seq(lit("<-"), g["Spacing"]);
|
||||||
g["SLASH"] <= seq(chr('/'), g["Spacing"]);
|
g["SLASH"] <= seq(chr('/'), g["Spacing"]);
|
||||||
@ -972,55 +1011,20 @@ inline Grammar make_peg_grammar()
|
|||||||
g["DOT"] <= seq(chr('.'), g["Spacing"]);
|
g["DOT"] <= seq(chr('.'), g["Spacing"]);
|
||||||
|
|
||||||
g["Spacing"] <= zom(cho(g["Space"], g["Comment"]));
|
g["Spacing"] <= zom(cho(g["Space"], g["Comment"]));
|
||||||
g["Comment"] <= seq(chr('#'), zom(seq(npd(g["EndOfLine"]), any())), g["EndOfLine"]);
|
g["Comment"] <= seq(chr('#'), zom(seq(npd(g["EndOfLine"]), dot())), g["EndOfLine"]);
|
||||||
g["Space"] <= cho(chr(' '), chr('\t'), g["EndOfLine"]);
|
g["Space"] <= cho(chr(' '), chr('\t'), g["EndOfLine"]);
|
||||||
g["EndOfLine"] <= cho(lit("\r\n"), chr('\n'), chr('\r'));
|
g["EndOfLine"] <= cho(lit("\r\n"), chr('\n'), chr('\r'));
|
||||||
g["EndOfFile"] <= npd(any());
|
g["EndOfFile"] <= npd(dot());
|
||||||
|
|
||||||
// Set definition names
|
// Set definition names
|
||||||
for (auto& x: g) {
|
for (auto& x: g) {
|
||||||
x.second.name = x.first;
|
x.second.name = x.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::pair<size_t, size_t> line_info(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;
|
void setup_actions() {
|
||||||
|
|
||||||
return std::make_pair(no, col);
|
g["Expression"] = [&](const std::vector<any>& v) {
|
||||||
}
|
|
||||||
|
|
||||||
typedef std::function<void (size_t, size_t, const std::string&)> Log;
|
|
||||||
|
|
||||||
class GrammarGenerator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static std::shared_ptr<Grammar> perform(const char* s, size_t l, std::string& start, Log log) {
|
|
||||||
static GrammarGenerator instance;
|
|
||||||
return instance.perform_core(s, l, start, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
GrammarGenerator() : peg(make_peg_grammar()) {
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialize() {
|
|
||||||
|
|
||||||
peg["Expression"] = [&](const std::vector<Any>& v) {
|
|
||||||
if (v.size() == 1) {
|
if (v.size() == 1) {
|
||||||
return v[0].get<std::shared_ptr<Ope>>();
|
return v[0].get<std::shared_ptr<Ope>>();
|
||||||
} else {
|
} else {
|
||||||
@ -1035,7 +1039,7 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["Sequence"] = [&](const std::vector<Any>& v) {
|
g["Sequence"] = [&](const std::vector<any>& v) {
|
||||||
if (v.size() == 1) {
|
if (v.size() == 1) {
|
||||||
return v[0].get<std::shared_ptr<Ope>>();
|
return v[0].get<std::shared_ptr<Ope>>();
|
||||||
} else {
|
} else {
|
||||||
@ -1048,7 +1052,7 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["Prefix"] = [&](const std::vector<Any>& v, const std::vector<std::string>& n) {
|
g["Prefix"] = [&](const std::vector<any>& v, const std::vector<std::string>& n) {
|
||||||
std::shared_ptr<Ope> ope;
|
std::shared_ptr<Ope> ope;
|
||||||
if (v.size() == 1) {
|
if (v.size() == 1) {
|
||||||
ope = v[0].get<std::shared_ptr<Ope>>();
|
ope = v[0].get<std::shared_ptr<Ope>>();
|
||||||
@ -1064,7 +1068,7 @@ private:
|
|||||||
return ope;
|
return ope;
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["Suffix"] = [&](const std::vector<Any>& v, const std::vector<std::string>& n) {
|
g["Suffix"] = [&](const std::vector<any>& v, const std::vector<std::string>& n) {
|
||||||
auto ope = v[0].get<std::shared_ptr<Ope>>();
|
auto ope = v[0].get<std::shared_ptr<Ope>>();
|
||||||
if (v.size() == 1) {
|
if (v.size() == 1) {
|
||||||
return ope;
|
return ope;
|
||||||
@ -1080,29 +1084,29 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["IdentCont"] = [](const char*s, size_t l) {
|
g["IdentCont"] = [](const char*s, size_t l) {
|
||||||
return std::string(s, l);
|
return std::string(s, l);
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["Literal"] = [](const std::vector<Any>& v) {
|
g["Literal"] = [](const std::vector<any>& v) {
|
||||||
return lit(v[0]);
|
return lit(v[0]);
|
||||||
};
|
};
|
||||||
peg["SQCont"] = [this](const char*s, size_t l) {
|
g["SQCont"] = [this](const char*s, size_t l) {
|
||||||
return resolve_escape_sequence(s, l);
|
return resolve_escape_sequence(s, l);
|
||||||
};
|
};
|
||||||
peg["DQCont"] = [this](const char*s, size_t l) {
|
g["DQCont"] = [this](const char*s, size_t l) {
|
||||||
return resolve_escape_sequence(s, l);
|
return resolve_escape_sequence(s, l);
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["Class"] = [](const std::vector<Any>& v) {
|
g["Class"] = [](const std::vector<any>& v) {
|
||||||
return cls(v[0]);
|
return cls(v[0]);
|
||||||
};
|
};
|
||||||
peg["ClassCont"] = [this](const char*s, size_t l) {
|
g["ClassCont"] = [this](const char*s, size_t l) {
|
||||||
return resolve_escape_sequence(s, l);
|
return resolve_escape_sequence(s, l);
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["DOT"] = []() {
|
g["DOT"] = []() {
|
||||||
return any();
|
return dot();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1111,7 +1115,7 @@ private:
|
|||||||
start.clear();
|
start.clear();
|
||||||
std::map<std::string, const char*> refs;
|
std::map<std::string, const char*> refs;
|
||||||
|
|
||||||
peg["Definition"] = [&](const std::vector<Any>& v) {
|
g["Definition"] = [&](const std::vector<any>& v) {
|
||||||
const auto& name = v[0].get<std::string>();
|
const auto& name = v[0].get<std::string>();
|
||||||
(*grammar)[name] <= v[2].get<std::shared_ptr<Ope>>();
|
(*grammar)[name] <= v[2].get<std::shared_ptr<Ope>>();
|
||||||
(*grammar)[name].name = name;
|
(*grammar)[name].name = name;
|
||||||
@ -1121,20 +1125,20 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
peg["Primary"].actions = {
|
g["Primary"].actions = {
|
||||||
[&](const std::vector<Any>& v) {
|
[&](const std::vector<any>& v) {
|
||||||
return v[0];
|
return v[0];
|
||||||
},
|
},
|
||||||
[&](const char* s, size_t l, const std::vector<Any>& v) {
|
[&](const char* s, size_t l, const std::vector<any>& v) {
|
||||||
refs[v[0]] = s;
|
refs[v[0]] = s;
|
||||||
return ref(*grammar, v[0]);
|
return ref(*grammar, v[0]);
|
||||||
},
|
},
|
||||||
[&](const std::vector<Any>& v) {
|
[&](const std::vector<any>& v) {
|
||||||
return v[1];
|
return v[1];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto r = peg["Grammar"].parse(s, l);
|
auto r = g["Grammar"].parse(s, l);
|
||||||
if (!r.ret) {
|
if (!r.ret) {
|
||||||
if (log) {
|
if (log) {
|
||||||
auto line = line_info(s, r.ptr);
|
auto line = line_info(s, r.ptr);
|
||||||
@ -1188,23 +1192,23 @@ private:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grammar peg;
|
Grammar g;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* Parser
|
* peg
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
class Parser
|
class peg
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Parser(const char* s, size_t l, Log log = nullptr) {
|
peg(const char* s, size_t l, Log log = nullptr) {
|
||||||
grammar_ = GrammarGenerator::perform(s, l, start_, log);
|
grammar_ = PEGParser::parse(s, l, start_, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser(const char* s, Log log = nullptr) {
|
peg(const char* s, Log log = nullptr) {
|
||||||
auto l = strlen(s);
|
auto l = strlen(s);
|
||||||
grammar_ = GrammarGenerator::perform(s, l, start_, log);
|
grammar_ = PEGParser::parse(s, l, start_, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool() {
|
operator bool() {
|
||||||
@ -1212,7 +1216,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool parse(const char* s, size_t l, T& out, bool exact = true) const {
|
bool match(const char* s, size_t l, T& out, bool exact = true) const {
|
||||||
if (grammar_ != nullptr) {
|
if (grammar_ != nullptr) {
|
||||||
const auto& rule = (*grammar_)[start_];
|
const auto& rule = (*grammar_)[start_];
|
||||||
auto r = rule.parse(s, l, out);
|
auto r = rule.parse(s, l, out);
|
||||||
@ -1221,7 +1225,7 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(const char* s, size_t l, bool exact = true) const {
|
bool match(const char* s, size_t l, bool exact = true) const {
|
||||||
if (grammar_ != nullptr) {
|
if (grammar_ != nullptr) {
|
||||||
const auto& rule = (*grammar_)[start_];
|
const auto& rule = (*grammar_)[start_];
|
||||||
auto r = rule.parse(s, l);
|
auto r = rule.parse(s, l);
|
||||||
@ -1231,14 +1235,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool parse(const char* s, T& out, bool exact = true) const {
|
bool match(const char* s, T& out, bool exact = true) const {
|
||||||
auto l = strlen(s);
|
auto l = strlen(s);
|
||||||
return parse(s, l, out, exact);
|
return match(s, l, out, exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(const char* s, bool exact = true) const {
|
bool match(const char* s, bool exact = true) const {
|
||||||
auto l = strlen(s);
|
auto l = strlen(s);
|
||||||
return parse(s, l, exact);
|
return match(s, l, exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lint(const char* s, size_t l, bool exact, Log log = nullptr) {
|
bool lint(const char* s, size_t l, bool exact, Log log = nullptr) {
|
||||||
|
82
test/test.cc
82
test/test.cc
@ -7,14 +7,14 @@
|
|||||||
|
|
||||||
TEST_CASE("Empty syntax test", "[general]")
|
TEST_CASE("Empty syntax test", "[general]")
|
||||||
{
|
{
|
||||||
peglib::Parser parser("");
|
peglib::peg parser("");
|
||||||
bool ret = parser;
|
bool ret = parser;
|
||||||
REQUIRE(ret == false);
|
REQUIRE(ret == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("String capture test", "[general]")
|
TEST_CASE("String capture test", "[general]")
|
||||||
{
|
{
|
||||||
peglib::Parser parser(
|
peglib::peg parser(
|
||||||
" ROOT <- _ ('[' TAG_NAME ']' _)* "
|
" ROOT <- _ ('[' TAG_NAME ']' _)* "
|
||||||
" TAG_NAME <- (!']' .)+ "
|
" TAG_NAME <- (!']' .)+ "
|
||||||
" _ <- [ \t]* "
|
" _ <- [ \t]* "
|
||||||
@ -26,7 +26,7 @@ TEST_CASE("String capture test", "[general]")
|
|||||||
tags.push_back(std::string(s, l));
|
tags.push_back(std::string(s, l));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto ret = parser.parse(" [tag1] [tag:2] [tag-3] ");
|
auto ret = parser.match(" [tag1] [tag:2] [tag-3] ");
|
||||||
|
|
||||||
REQUIRE(ret == true);
|
REQUIRE(ret == true);
|
||||||
REQUIRE(tags.size() == 3);
|
REQUIRE(tags.size() == 3);
|
||||||
@ -45,7 +45,7 @@ TEST_CASE("String capture test2", "[general]")
|
|||||||
rule ROOT, TAG, TAG_NAME, WS;
|
rule ROOT, TAG, TAG_NAME, WS;
|
||||||
ROOT <= seq(WS, zom(TAG));
|
ROOT <= seq(WS, zom(TAG));
|
||||||
TAG <= seq(chr('['), TAG_NAME, chr(']'), WS);
|
TAG <= seq(chr('['), TAG_NAME, chr(']'), WS);
|
||||||
TAG_NAME <= oom(seq(npd(chr(']')), any())), [&](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 m = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
|
||||||
@ -65,7 +65,7 @@ TEST_CASE("String capture test with embedded match action", "[general]")
|
|||||||
|
|
||||||
ROOT <= seq(WS, zom(TAG));
|
ROOT <= seq(WS, zom(TAG));
|
||||||
TAG <= seq(chr('['), grp(TAG_NAME, [&](const char* s, size_t l) { tags.push_back(string(s, l)); }), chr(']'), WS);
|
TAG <= seq(chr('['), grp(TAG_NAME, [&](const char* s, size_t l) { tags.push_back(string(s, l)); }), chr(']'), WS);
|
||||||
TAG_NAME <= oom(seq(npd(chr(']')), any()));
|
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 m = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
|
||||||
@ -88,7 +88,7 @@ TEST_CASE("Cyclic grammer test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Lambda action test", "[general]")
|
TEST_CASE("Lambda action test", "[general]")
|
||||||
{
|
{
|
||||||
Parser parser(
|
peg parser(
|
||||||
" START <- (CHAR)* "
|
" START <- (CHAR)* "
|
||||||
" CHAR <- . ");
|
" CHAR <- . ");
|
||||||
|
|
||||||
@ -97,14 +97,14 @@ TEST_CASE("Lambda action test", "[general]")
|
|||||||
ss += *s;
|
ss += *s;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ret = parser.parse("hello");
|
bool ret = parser.match("hello");
|
||||||
REQUIRE(ret == true);
|
REQUIRE(ret == true);
|
||||||
REQUIRE(ss == "hello");
|
REQUIRE(ss == "hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Backtracking test", "[general]")
|
TEST_CASE("Backtracking test", "[general]")
|
||||||
{
|
{
|
||||||
Parser parser(
|
peg parser(
|
||||||
" START <- PAT1 / PAT2 "
|
" START <- PAT1 / PAT2 "
|
||||||
" PAT1 <- HELLO ' One' "
|
" PAT1 <- HELLO ' One' "
|
||||||
" PAT2 <- HELLO ' Two' "
|
" PAT2 <- HELLO ' Two' "
|
||||||
@ -116,7 +116,7 @@ TEST_CASE("Backtracking test", "[general]")
|
|||||||
count++;
|
count++;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ret = parser.parse("Hello Two");
|
bool ret = parser.match("Hello Two");
|
||||||
REQUIRE(ret == true);
|
REQUIRE(ret == true);
|
||||||
REQUIRE(count == 2);
|
REQUIRE(count == 2);
|
||||||
}
|
}
|
||||||
@ -129,22 +129,22 @@ TEST_CASE("Simple calculator test", "[general]")
|
|||||||
" Primary <- '(' Additive ')' / Number "
|
" Primary <- '(' Additive ')' / Number "
|
||||||
" Number <- [0-9]+ ";
|
" Number <- [0-9]+ ";
|
||||||
|
|
||||||
Parser parser(syntax);
|
peg parser(syntax);
|
||||||
|
|
||||||
parser["Additive"] = {
|
parser["Additive"] = {
|
||||||
// Default action
|
// Default action
|
||||||
nullptr,
|
nullptr,
|
||||||
// Action for the first choice
|
// Action for the first choice
|
||||||
[](const vector<Any>& v) { return v[0].get<int>() + v[1].get<int>(); },
|
[](const vector<any>& v) { return v[0].get<int>() + v[1].get<int>(); },
|
||||||
// Action for the second choice
|
// Action for the second choice
|
||||||
[](const vector<Any>& v) { return v[0]; }
|
[](const vector<any>& v) { return v[0]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
parser["Multitive"] = [](const vector<Any>& v) {
|
parser["Multitive"] = [](const vector<any>& v) {
|
||||||
return v.size() == 1 ? int(v[0]) : v[0].get<int>() * v[1].get<int>();
|
return v.size() == 1 ? int(v[0]) : v[0].get<int>() * v[1].get<int>();
|
||||||
};
|
};
|
||||||
|
|
||||||
parser["Primary"] = [](const vector<Any>& v) {
|
parser["Primary"] = [](const vector<any>& v) {
|
||||||
return v.size() == 1 ? v[0] : v[1];
|
return v.size() == 1 ? v[0] : v[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ TEST_CASE("Simple calculator test", "[general]")
|
|||||||
};
|
};
|
||||||
|
|
||||||
int val;
|
int val;
|
||||||
parser.parse("1+2*3", val);
|
parser.match("1+2*3", val);
|
||||||
|
|
||||||
REQUIRE(val == 7);
|
REQUIRE(val == 7);
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ TEST_CASE("Calculator test", "[general]")
|
|||||||
NUMBER <= oom(cls("0-9"));
|
NUMBER <= oom(cls("0-9"));
|
||||||
|
|
||||||
// Setup actions
|
// Setup actions
|
||||||
auto reduce = [](const vector<Any>& v) -> long {
|
auto reduce = [](const vector<any>& v) -> long {
|
||||||
long ret = v[0].get<long>();
|
long ret = v[0].get<long>();
|
||||||
for (auto i = 1u; i < v.size(); i += 2) {
|
for (auto i = 1u; i < v.size(); i += 2) {
|
||||||
auto num = v[i + 1].get<long>();
|
auto num = v[i + 1].get<long>();
|
||||||
@ -213,11 +213,11 @@ TEST_CASE("Calculator test2", "[general]")
|
|||||||
;
|
;
|
||||||
|
|
||||||
string start;
|
string start;
|
||||||
auto grammar = GrammarGenerator::perform(syntax, strlen(syntax), start, nullptr);
|
auto grammar = PEGParser::parse(syntax, strlen(syntax), start, nullptr);
|
||||||
auto& g = *grammar;
|
auto& g = *grammar;
|
||||||
|
|
||||||
// Setup actions
|
// Setup actions
|
||||||
auto reduce = [](const vector<Any>& v) -> long {
|
auto reduce = [](const vector<any>& v) -> long {
|
||||||
long ret = v[0].get<long>();
|
long ret = v[0].get<long>();
|
||||||
for (auto i = 1u; i < v.size(); i += 2) {
|
for (auto i = 1u; i < v.size(); i += 2) {
|
||||||
auto num = v[i + 1].get<long>();
|
auto num = v[i + 1].get<long>();
|
||||||
@ -248,7 +248,7 @@ TEST_CASE("Calculator test2", "[general]")
|
|||||||
TEST_CASE("Calculator test3", "[general]")
|
TEST_CASE("Calculator test3", "[general]")
|
||||||
{
|
{
|
||||||
// Parse syntax
|
// Parse syntax
|
||||||
Parser parser(
|
peg parser(
|
||||||
" # Grammar for Calculator...\n "
|
" # Grammar for Calculator...\n "
|
||||||
" EXPRESSION <- TERM (TERM_OPERATOR TERM)* "
|
" EXPRESSION <- TERM (TERM_OPERATOR TERM)* "
|
||||||
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
||||||
@ -258,7 +258,7 @@ TEST_CASE("Calculator test3", "[general]")
|
|||||||
" NUMBER <- [0-9]+ "
|
" NUMBER <- [0-9]+ "
|
||||||
);
|
);
|
||||||
|
|
||||||
auto reduce = [](const vector<Any>& v) -> long {
|
auto reduce = [](const vector<any>& v) -> long {
|
||||||
long ret = v[0].get<long>();
|
long ret = v[0].get<long>();
|
||||||
for (auto i = 1u; i < v.size(); i += 2) {
|
for (auto i = 1u; i < v.size(); i += 2) {
|
||||||
auto num = v[i + 1].get<long>();
|
auto num = v[i + 1].get<long>();
|
||||||
@ -281,7 +281,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.match("1+2*3*(4-5+6)/7-8", val);
|
||||||
|
|
||||||
REQUIRE(ret == true);
|
REQUIRE(ret == true);
|
||||||
REQUIRE(val == -3);
|
REQUIRE(val == -3);
|
||||||
@ -293,15 +293,19 @@ bool exact(Grammar& g, const char* d, const char* s) {
|
|||||||
return r.ret && r.len == l;
|
return r.ret && r.len == l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Grammar& make_peg_grammar() {
|
||||||
|
return PEGParser::grammar();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Grammar", "[peg]")
|
TEST_CASE("PEG Grammar", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Grammar", " Definition <- a / ( b c ) / d \n rule2 <- [a-zA-Z][a-z0-9-]+ ") == true);
|
REQUIRE(exact(g, "Grammar", " Definition <- a / ( b c ) / d \n rule2 <- [a-zA-Z][a-z0-9-]+ ") == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Definition", "[peg]")
|
TEST_CASE("PEG Definition", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Definition", "Definition <- a / (b c) / d ") == true);
|
REQUIRE(exact(g, "Definition", "Definition <- a / (b c) / d ") == true);
|
||||||
REQUIRE(exact(g, "Definition", "Definition <- a / b c / d ") == true);
|
REQUIRE(exact(g, "Definition", "Definition <- a / b c / d ") == true);
|
||||||
REQUIRE(exact(g, "Definition", "Definition ") == false);
|
REQUIRE(exact(g, "Definition", "Definition ") == false);
|
||||||
@ -312,7 +316,7 @@ TEST_CASE("PEG Definition", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Expression", "[peg]")
|
TEST_CASE("PEG Expression", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Expression", "a / (b c) / d ") == true);
|
REQUIRE(exact(g, "Expression", "a / (b c) / d ") == true);
|
||||||
REQUIRE(exact(g, "Expression", "a / b c / d ") == true);
|
REQUIRE(exact(g, "Expression", "a / b c / d ") == true);
|
||||||
REQUIRE(exact(g, "Expression", "a b ") == true);
|
REQUIRE(exact(g, "Expression", "a b ") == true);
|
||||||
@ -323,7 +327,7 @@ TEST_CASE("PEG Expression", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Sequence", "[peg]")
|
TEST_CASE("PEG Sequence", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Sequence", "a b c d ") == true);
|
REQUIRE(exact(g, "Sequence", "a b c d ") == true);
|
||||||
REQUIRE(exact(g, "Sequence", "") == true);
|
REQUIRE(exact(g, "Sequence", "") == true);
|
||||||
REQUIRE(exact(g, "Sequence", "!") == false);
|
REQUIRE(exact(g, "Sequence", "!") == false);
|
||||||
@ -333,7 +337,7 @@ TEST_CASE("PEG Sequence", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Prefix", "[peg]")
|
TEST_CASE("PEG Prefix", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Prefix", "&[a]") == true);
|
REQUIRE(exact(g, "Prefix", "&[a]") == true);
|
||||||
REQUIRE(exact(g, "Prefix", "![']") == true);
|
REQUIRE(exact(g, "Prefix", "![']") == true);
|
||||||
REQUIRE(exact(g, "Prefix", "-[']") == false);
|
REQUIRE(exact(g, "Prefix", "-[']") == false);
|
||||||
@ -343,7 +347,7 @@ TEST_CASE("PEG Prefix", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Suffix", "[peg]")
|
TEST_CASE("PEG Suffix", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Suffix", "aaa ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa ") == true);
|
||||||
REQUIRE(exact(g, "Suffix", "aaa? ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa? ") == true);
|
||||||
REQUIRE(exact(g, "Suffix", "aaa* ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa* ") == true);
|
||||||
@ -356,7 +360,7 @@ TEST_CASE("PEG Suffix", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Primary", "[peg]")
|
TEST_CASE("PEG Primary", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Primary", "_Identifier0_ ") == true);
|
REQUIRE(exact(g, "Primary", "_Identifier0_ ") == true);
|
||||||
REQUIRE(exact(g, "Primary", "_Identifier0_<-") == false);
|
REQUIRE(exact(g, "Primary", "_Identifier0_<-") == false);
|
||||||
REQUIRE(exact(g, "Primary", "( _Identifier0_ _Identifier1_ )") == true);
|
REQUIRE(exact(g, "Primary", "( _Identifier0_ _Identifier1_ )") == true);
|
||||||
@ -372,7 +376,7 @@ TEST_CASE("PEG Primary", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Identifier", "[peg]")
|
TEST_CASE("PEG Identifier", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Identifier", "_Identifier0_ ") == true);
|
REQUIRE(exact(g, "Identifier", "_Identifier0_ ") == true);
|
||||||
REQUIRE(exact(g, "Identifier", "0Identifier_ ") == false);
|
REQUIRE(exact(g, "Identifier", "0Identifier_ ") == false);
|
||||||
REQUIRE(exact(g, "Identifier", "Iden|t ") == false);
|
REQUIRE(exact(g, "Identifier", "Iden|t ") == false);
|
||||||
@ -383,7 +387,7 @@ TEST_CASE("PEG Identifier", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG IdentStart", "[peg]")
|
TEST_CASE("PEG IdentStart", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "IdentStart", "_") == true);
|
REQUIRE(exact(g, "IdentStart", "_") == true);
|
||||||
REQUIRE(exact(g, "IdentStart", "a") == true);
|
REQUIRE(exact(g, "IdentStart", "a") == true);
|
||||||
REQUIRE(exact(g, "IdentStart", "Z") == true);
|
REQUIRE(exact(g, "IdentStart", "Z") == true);
|
||||||
@ -394,7 +398,7 @@ TEST_CASE("PEG IdentStart", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG IdentRest", "[peg]")
|
TEST_CASE("PEG IdentRest", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "IdentRest", "_") == true);
|
REQUIRE(exact(g, "IdentRest", "_") == true);
|
||||||
REQUIRE(exact(g, "IdentRest", "a") == true);
|
REQUIRE(exact(g, "IdentRest", "a") == true);
|
||||||
REQUIRE(exact(g, "IdentRest", "Z") == true);
|
REQUIRE(exact(g, "IdentRest", "Z") == true);
|
||||||
@ -405,7 +409,7 @@ TEST_CASE("PEG IdentRest", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Literal", "[peg]")
|
TEST_CASE("PEG Literal", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Literal", "'abc' ") == true);
|
REQUIRE(exact(g, "Literal", "'abc' ") == true);
|
||||||
REQUIRE(exact(g, "Literal", "'a\\nb\\tc' ") == true);
|
REQUIRE(exact(g, "Literal", "'a\\nb\\tc' ") == true);
|
||||||
REQUIRE(exact(g, "Literal", "'a\\277\tc' ") == true);
|
REQUIRE(exact(g, "Literal", "'a\\277\tc' ") == true);
|
||||||
@ -424,7 +428,7 @@ TEST_CASE("PEG Literal", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Class", "[peg]")
|
TEST_CASE("PEG Class", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Class", "[]") == true);
|
REQUIRE(exact(g, "Class", "[]") == true);
|
||||||
REQUIRE(exact(g, "Class", "[a]") == true);
|
REQUIRE(exact(g, "Class", "[a]") == true);
|
||||||
REQUIRE(exact(g, "Class", "[a-z]") == true);
|
REQUIRE(exact(g, "Class", "[a-z]") == true);
|
||||||
@ -444,7 +448,7 @@ TEST_CASE("PEG Class", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Range", "[peg]")
|
TEST_CASE("PEG Range", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Range", "a") == true);
|
REQUIRE(exact(g, "Range", "a") == true);
|
||||||
REQUIRE(exact(g, "Range", "a-z") == true);
|
REQUIRE(exact(g, "Range", "a-z") == true);
|
||||||
REQUIRE(exact(g, "Range", "az") == false);
|
REQUIRE(exact(g, "Range", "az") == false);
|
||||||
@ -455,7 +459,7 @@ TEST_CASE("PEG Range", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Char", "[peg]")
|
TEST_CASE("PEG Char", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Char", "\\n") == true);
|
REQUIRE(exact(g, "Char", "\\n") == true);
|
||||||
REQUIRE(exact(g, "Char", "\\r") == true);
|
REQUIRE(exact(g, "Char", "\\r") == true);
|
||||||
REQUIRE(exact(g, "Char", "\\t") == true);
|
REQUIRE(exact(g, "Char", "\\t") == true);
|
||||||
@ -488,7 +492,7 @@ TEST_CASE("PEG Char", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Operators", "[peg]")
|
TEST_CASE("PEG Operators", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "LEFTARROW", "<-") == true);
|
REQUIRE(exact(g, "LEFTARROW", "<-") == true);
|
||||||
REQUIRE(exact(g, "SLASH", "/ ") == true);
|
REQUIRE(exact(g, "SLASH", "/ ") == true);
|
||||||
REQUIRE(exact(g, "AND", "& ") == true);
|
REQUIRE(exact(g, "AND", "& ") == true);
|
||||||
@ -503,7 +507,7 @@ TEST_CASE("PEG Operators", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Comment", "[peg]")
|
TEST_CASE("PEG Comment", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Comment", "# Comment.\n") == true);
|
REQUIRE(exact(g, "Comment", "# Comment.\n") == true);
|
||||||
REQUIRE(exact(g, "Comment", "# Comment.") == false);
|
REQUIRE(exact(g, "Comment", "# Comment.") == false);
|
||||||
REQUIRE(exact(g, "Comment", " ") == false);
|
REQUIRE(exact(g, "Comment", " ") == false);
|
||||||
@ -512,7 +516,7 @@ TEST_CASE("PEG Comment", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Space", "[peg]")
|
TEST_CASE("PEG Space", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "Space", " ") == true);
|
REQUIRE(exact(g, "Space", " ") == true);
|
||||||
REQUIRE(exact(g, "Space", "\t") == true);
|
REQUIRE(exact(g, "Space", "\t") == true);
|
||||||
REQUIRE(exact(g, "Space", "\n") == true);
|
REQUIRE(exact(g, "Space", "\n") == true);
|
||||||
@ -522,7 +526,7 @@ TEST_CASE("PEG Space", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG EndOfLine", "[peg]")
|
TEST_CASE("PEG EndOfLine", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
auto g = PEGParser::grammar();
|
||||||
REQUIRE(exact(g, "EndOfLine", "\r\n") == true);
|
REQUIRE(exact(g, "EndOfLine", "\r\n") == true);
|
||||||
REQUIRE(exact(g, "EndOfLine", "\n") == true);
|
REQUIRE(exact(g, "EndOfLine", "\n") == true);
|
||||||
REQUIRE(exact(g, "EndOfLine", "\r") == true);
|
REQUIRE(exact(g, "EndOfLine", "\r") == true);
|
||||||
|
Loading…
Reference in New Issue
Block a user