Changed the interfaces.

pull/3/head
yhirose 9 years ago
parent 6e8ea2b471
commit 3f639e37f0
  1. 36
      README.md
  2. 6
      example/calc.cc
  3. 2
      example/calc2.cc
  4. 3
      lint/peglint.cc
  5. 298
      peglib.h
  6. 82
      test/test.cc

@ -28,7 +28,7 @@ Here is how to parse text with the PEG syntax and retrieve tag names:
#include "peglib.h"
// (2) Make a parser
auto parser = peglib::make_parser(R"(
peglib::peg parser(R"(
ROOT <- _ ('[' TAG_NAME ']' _)*
TAG_NAME <- (!']' .)+
_ <- [ \t]*
@ -41,7 +41,7 @@ parser["TAG_NAME"] = [&](const char* s, size_t l) {
};
// (4) Parse
auto ret = parser.parse(" [tag1] [tag:2] [tag-3] ");
auto ret = parser.match(" [tag1] [tag:2] [tag-3] ");
assert(ret == true);
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:
```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 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 std::vector<std::string>& n)
[](const std::vector<peglib::Any>& v)
[](const std::vector<peglib::any>& v, const std::vector<std::string>& n)
[](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.
@ -84,34 +84,34 @@ int main(void) {
Number <- [0-9]+
)";
auto parser = make_parser(syntax);
peg parser(syntax);
parser["Additive"] = {
nullptr, // Default action
[](const vector<Any>& v) {
[](const vector<any>& v) {
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"] = {
nullptr, // Default action
[](const vector<Any>& v) {
[](const vector<any>& v) {
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];
};
parser["Number"] = [](const char* s, size_t l) -> long {
parser["Number"] = [](const char* s, size_t l) {
return stoi(string(s, l), nullptr, 10);
};
int val;
parser.parse("1+2*3", val);
parser.match("1+2*3", val);
assert(val == 7);
}
@ -130,14 +130,12 @@ vector<string> tags;
Definition ROOT, TAG_NAME, _;
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"));
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:
| Operator | Description |
@ -153,7 +151,7 @@ The following are available operators:
| lit | Literal string |
| cls | Character class |
| chr | Character |
| any | Any character |
| dot | Any character |
Sample codes
------------

@ -31,7 +31,7 @@ int main(int argc, const char** argv)
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>();
for (auto i = 1u; i < v.size(); i += 2) {
auto num = v[i + 1].get<long>();
@ -55,7 +55,7 @@ int main(int argc, const char** argv)
" NUMBER <- [0-9]+ "
;
Parser parser(syntax);
peg parser(syntax);
parser["EXPRESSION"] = 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); };
long val = 0;
if (parser.parse(s, val)) {
if (parser.match(s, val)) {
cout << s << " = " << val << endl;
return 0;
}

@ -31,7 +31,7 @@ int main(int argc, const char** argv)
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>();
for (auto i = 1u; i < v.size(); i += 2) {
auto num = v[i + 1].get<long>();

@ -9,7 +9,6 @@
#include <iostream>
#include "mmap.h"
using namespace peglib;
using namespace std;
int main(int argc, const char** argv)
@ -28,7 +27,7 @@ int main(int argc, const char** argv)
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;
});

@ -23,24 +23,24 @@ namespace peglib {
void* enabler;
/*-----------------------------------------------------------------------------
* Any
* any
*---------------------------------------------------------------------------*/
class Any
class any
{
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;
}
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 (content_) {
delete content_;
@ -50,7 +50,7 @@ public:
return *this;
}
Any& operator=(Any&& rhs) {
any& operator=(any&& rhs) {
if (this != &rhs) {
if (content_) {
delete content_;
@ -62,7 +62,7 @@ public:
}
template <typename T>
Any& operator=(const T& value) {
any& operator=(const T& value) {
if (content_) {
delete content_;
}
@ -70,7 +70,7 @@ public:
return *this;
}
~Any() {
~any() {
delete content_;
}
@ -80,7 +80,7 @@ public:
template <
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() {
assert(content_);
@ -89,7 +89,7 @@ public:
template <
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() {
return *this;
@ -97,7 +97,7 @@ public:
template <
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 {
assert(content_);
@ -106,9 +106,9 @@ public:
template <
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;
}
@ -166,7 +166,7 @@ private:
struct Values
{
std::vector<std::string> names;
std::vector<Any> values;
std::vector<any> values;
};
/*
@ -176,17 +176,17 @@ template <
typename R, typename F,
typename std::enable_if<!std::is_void<R>::value>::type*& = enabler,
typename... Args>
Any call(F fn, Args&&... args) {
return Any(fn(std::forward<Args>(args)...));
any call(F fn, Args&&... args) {
return any(fn(std::forward<Args>(args)...));
}
template <
typename R, typename F,
typename std::enable_if<std::is_void<R>::value>::type*& = enabler,
typename... Args>
Any call(F fn, Args&&... args) {
any call(F fn, Args&&... args) {
fn(std::forward<Args>(args)...);
return Any();
return any();
}
class Action
@ -224,35 +224,35 @@ public:
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);
}
private:
template <typename R>
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) {}
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);
}
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>
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) {}
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);
}
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>
struct TypeAdaptor_s_l {
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);
}
std::function<R (const char* s, size_t l)> fn_;
@ -260,50 +260,50 @@ private:
template <typename R>
struct TypeAdaptor_v_n {
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) {
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) {
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>
struct TypeAdaptor_v {
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) {
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) {
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>
struct TypeAdaptor_empty {
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_);
}
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>
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);
}
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);
}
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);
}
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);
}
@ -318,22 +318,22 @@ private:
}
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);
}
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);
}
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);
}
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);
}
@ -818,11 +818,11 @@ private:
private:
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) {
return action(s, l, v.values, v.names);
} else if (v.values.empty()) {
return Any();
return any();
} else {
return v.values.front();
}
@ -903,7 +903,7 @@ inline std::shared_ptr<Ope> chr(char c) {
return std::make_shared<Character>(c);
}
inline std::shared_ptr<Ope> any() {
inline std::shared_ptr<Ope> dot() {
return std::make_shared<AnyCharacter>();
}
@ -923,68 +923,6 @@ inline std::shared_ptr<Ope> ref(const std::map<std::string, Definition>& grammar
* PEG parser generator
*---------------------------------------------------------------------------*/
typedef std::map<std::string, Definition> Grammar;
inline Grammar make_peg_grammar()
{
Grammar g;
// Setup PEG syntax parser
g["Grammar"] <= seq(g["Spacing"], oom(g["Definition"]), g["EndOfFile"]);
g["Definition"] <= seq(g["Identifier"], g["LEFTARROW"], g["Expression"]);
g["Expression"] <= seq(g["Sequence"], zom(seq(g["SLASH"], g["Sequence"])));
g["Sequence"] <= zom(g["Prefix"]);
g["Prefix"] <= seq(opt(cho(g["AND"], g["NOT"])), g["Suffix"]);
g["Suffix"] <= seq(g["Primary"], opt(cho(g["QUESTION"], g["STAR"], g["PLUS"])));
g["Primary"] <= cho(seq(g["Identifier"], npd(g["LEFTARROW"])),
seq(g["OPEN"], g["Expression"], g["CLOSE"]),
g["Literal"], g["Class"], g["DOT"]);
g["Identifier"] <= seq(g["IdentCont"], g["Spacing"]);
g["IdentCont"] <= seq(g["IdentStart"], zom(g["IdentRest"]));
g["IdentStart"] <= cls("a-zA-Z_");
g["IdentRest"] <= cho(g["IdentStart"], cls("0-9"));
g["Literal"] <= cho(seq(cls("'"), g["SQCont"], cls("'"), g["Spacing"]),
seq(cls("\""), g["DQCont"], cls("\""), g["Spacing"]));
g["SQCont"] <= zom(seq(npd(cls("'")), g["Char"]));
g["DQCont"] <= zom(seq(npd(cls("\"")), g["Char"]));
g["Class"] <= seq(chr('['), g["ClassCont"], chr(']'), g["Spacing"]);
g["ClassCont"] <= zom(seq(npd(chr(']')), g["Range"]));
g["Range"] <= cho(seq(g["Char"], chr('-'), g["Char"]), g["Char"]);
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-7"), opt(cls("0-7"))),
seq(npd(chr('\\')), any()));
g["LEFTARROW"] <= seq(lit("<-"), g["Spacing"]);
g["SLASH"] <= seq(chr('/'), g["Spacing"]);
g["AND"] <= seq(chr('&'), g["Spacing"]);
g["NOT"] <= seq(chr('!'), g["Spacing"]);
g["QUESTION"] <= seq(chr('?'), g["Spacing"]);
g["STAR"] <= seq(chr('*'), g["Spacing"]);
g["PLUS"] <= seq(chr('+'), g["Spacing"]);
g["OPEN"] <= seq(chr('('), g["Spacing"]);
g["CLOSE"] <= seq(chr(')'), g["Spacing"]);
g["DOT"] <= seq(chr('.'), g["Spacing"]);
g["Spacing"] <= zom(cho(g["Space"], g["Comment"]));
g["Comment"] <= seq(chr('#'), zom(seq(npd(g["EndOfLine"]), any())), g["EndOfLine"]);
g["Space"] <= cho(chr(' '), chr('\t'), g["EndOfLine"]);
g["EndOfLine"] <= cho(lit("\r\n"), chr('\n'), chr('\r'));
g["EndOfFile"] <= npd(any());
// Set definition names
for (auto& x: g) {
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;
@ -1003,24 +941,90 @@ inline std::pair<size_t, size_t> line_info(const char* s, const char* ptr) {
return std::make_pair(no, col);
}
typedef std::map<std::string, Definition> Grammar;
typedef std::function<void (size_t, size_t, const std::string&)> Log;
class GrammarGenerator
class PEGParser
{
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);
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:
GrammarGenerator() : peg(make_peg_grammar()) {
initialize();
static PEGParser& get() {
static PEGParser instance;
return instance;
}
PEGParser() {
make_grammar();
setup_actions();
}
void make_grammar() {
// Setup PEG syntax parser
g["Grammar"] <= seq(g["Spacing"], oom(g["Definition"]), g["EndOfFile"]);
g["Definition"] <= seq(g["Identifier"], g["LEFTARROW"], g["Expression"]);
g["Expression"] <= seq(g["Sequence"], zom(seq(g["SLASH"], g["Sequence"])));
g["Sequence"] <= zom(g["Prefix"]);
g["Prefix"] <= seq(opt(cho(g["AND"], g["NOT"])), g["Suffix"]);
g["Suffix"] <= seq(g["Primary"], opt(cho(g["QUESTION"], g["STAR"], g["PLUS"])));
g["Primary"] <= cho(seq(g["Identifier"], npd(g["LEFTARROW"])),
seq(g["OPEN"], g["Expression"], g["CLOSE"]),
g["Literal"], g["Class"], g["DOT"]);
g["Identifier"] <= seq(g["IdentCont"], g["Spacing"]);
g["IdentCont"] <= seq(g["IdentStart"], zom(g["IdentRest"]));
g["IdentStart"] <= cls("a-zA-Z_");
g["IdentRest"] <= cho(g["IdentStart"], cls("0-9"));
g["Literal"] <= cho(seq(cls("'"), g["SQCont"], cls("'"), g["Spacing"]),
seq(cls("\""), g["DQCont"], cls("\""), g["Spacing"]));
g["SQCont"] <= zom(seq(npd(cls("'")), g["Char"]));
g["DQCont"] <= zom(seq(npd(cls("\"")), g["Char"]));
g["Class"] <= seq(chr('['), g["ClassCont"], chr(']'), g["Spacing"]);
g["ClassCont"] <= zom(seq(npd(chr(']')), g["Range"]));
g["Range"] <= cho(seq(g["Char"], chr('-'), g["Char"]), g["Char"]);
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-7"), opt(cls("0-7"))),
seq(npd(chr('\\')), dot()));
g["LEFTARROW"] <= seq(lit("<-"), g["Spacing"]);
g["SLASH"] <= seq(chr('/'), g["Spacing"]);
g["AND"] <= seq(chr('&'), g["Spacing"]);
g["NOT"] <= seq(chr('!'), g["Spacing"]);
g["QUESTION"] <= seq(chr('?'), g["Spacing"]);
g["STAR"] <= seq(chr('*'), g["Spacing"]);
g["PLUS"] <= seq(chr('+'), g["Spacing"]);
g["OPEN"] <= seq(chr('('), g["Spacing"]);
g["CLOSE"] <= seq(chr(')'), g["Spacing"]);
g["DOT"] <= seq(chr('.'), g["Spacing"]);
g["Spacing"] <= zom(cho(g["Space"], g["Comment"]));
g["Comment"] <= seq(chr('#'), zom(seq(npd(g["EndOfLine"]), dot())), g["EndOfLine"]);
g["Space"] <= cho(chr(' '), chr('\t'), g["EndOfLine"]);
g["EndOfLine"] <= cho(lit("\r\n"), chr('\n'), chr('\r'));
g["EndOfFile"] <= npd(dot());
// Set definition names
for (auto& x: g) {
x.second.name = x.first;
}
}
void initialize() {
void setup_actions() {
peg["Expression"] = [&](const std::vector<Any>& v) {
g["Expression"] = [&](const std::vector<any>& v) {
if (v.size() == 1) {
return v[0].get<std::shared_ptr<Ope>>();
} else {
@ -1035,7 +1039,7 @@ private:
}
};
peg["Sequence"] = [&](const std::vector<Any>& v) {
g["Sequence"] = [&](const std::vector<any>& v) {
if (v.size() == 1) {
return v[0].get<std::shared_ptr<Ope>>();
} 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;
if (v.size() == 1) {
ope = v[0].get<std::shared_ptr<Ope>>();
@ -1064,7 +1068,7 @@ private:
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>>();
if (v.size() == 1) {
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);
};
peg["Literal"] = [](const std::vector<Any>& v) {
g["Literal"] = [](const std::vector<any>& v) {
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);
};
peg["DQCont"] = [this](const char*s, size_t l) {
g["DQCont"] = [this](const char*s, size_t 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]);
};
peg["ClassCont"] = [this](const char*s, size_t l) {
g["ClassCont"] = [this](const char*s, size_t l) {
return resolve_escape_sequence(s, l);
};
peg["DOT"] = []() {
return any();
g["DOT"] = []() {
return dot();
};
}
@ -1111,7 +1115,7 @@ private:
start.clear();
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>();
(*grammar)[name] <= v[2].get<std::shared_ptr<Ope>>();
(*grammar)[name].name = name;
@ -1121,20 +1125,20 @@ private:
}
};
peg["Primary"].actions = {
[&](const std::vector<Any>& v) {
g["Primary"].actions = {
[&](const std::vector<any>& v) {
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;
return ref(*grammar, v[0]);
},
[&](const std::vector<Any>& v) {
[&](const std::vector<any>& v) {
return v[1];
}
};
auto r = peg["Grammar"].parse(s, l);
auto r = g["Grammar"].parse(s, l);
if (!r.ret) {
if (log) {
auto line = line_info(s, r.ptr);
@ -1188,23 +1192,23 @@ private:
return r;
}
Grammar peg;
Grammar g;
};
/*-----------------------------------------------------------------------------
* Parser
* peg
*---------------------------------------------------------------------------*/
class Parser
class peg
{
public:
Parser(const char* s, size_t l, Log log = nullptr) {
grammar_ = GrammarGenerator::perform(s, l, start_, log);
peg(const char* s, size_t l, Log log = nullptr) {
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);
grammar_ = GrammarGenerator::perform(s, l, start_, log);
grammar_ = PEGParser::parse(s, l, start_, log);
}
operator bool() {
@ -1212,7 +1216,7 @@ public:
}
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) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, l, out);
@ -1221,7 +1225,7 @@ public:
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) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, l);
@ -1231,14 +1235,14 @@ public:
}
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);
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);
return parse(s, l, exact);
return match(s, l, exact);
}
bool lint(const char* s, size_t l, bool exact, Log log = nullptr) {

@ -7,14 +7,14 @@
TEST_CASE("Empty syntax test", "[general]")
{
peglib::Parser parser("");
peglib::peg parser("");
bool ret = parser;
REQUIRE(ret == false);
}
TEST_CASE("String capture test", "[general]")
{
peglib::Parser parser(
peglib::peg parser(
" ROOT <- _ ('[' TAG_NAME ']' _)* "
" TAG_NAME <- (!']' .)+ "
" _ <- [ \t]* "
@ -26,7 +26,7 @@ TEST_CASE("String capture test", "[general]")
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(tags.size() == 3);
@ -45,7 +45,7 @@ TEST_CASE("String capture test2", "[general]")
rule ROOT, TAG, TAG_NAME, WS;
ROOT <= seq(WS, zom(TAG));
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"));
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));
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"));
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]")
{
Parser parser(
peg parser(
" START <- (CHAR)* "
" CHAR <- . ");
@ -97,14 +97,14 @@ TEST_CASE("Lambda action test", "[general]")
ss += *s;
};
bool ret = parser.parse("hello");
bool ret = parser.match("hello");
REQUIRE(ret == true);
REQUIRE(ss == "hello");
}
TEST_CASE("Backtracking test", "[general]")
{
Parser parser(
peg parser(
" START <- PAT1 / PAT2 "
" PAT1 <- HELLO ' One' "
" PAT2 <- HELLO ' Two' "
@ -116,7 +116,7 @@ TEST_CASE("Backtracking test", "[general]")
count++;
};
bool ret = parser.parse("Hello Two");
bool ret = parser.match("Hello Two");
REQUIRE(ret == true);
REQUIRE(count == 2);
}
@ -129,22 +129,22 @@ TEST_CASE("Simple calculator test", "[general]")
" Primary <- '(' Additive ')' / Number "
" Number <- [0-9]+ ";
Parser parser(syntax);
peg parser(syntax);
parser["Additive"] = {
// Default action
nullptr,
// 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
[](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>();
};
parser["Primary"] = [](const vector<Any>& v) {
parser["Primary"] = [](const vector<any>& v) {
return v.size() == 1 ? v[0] : v[1];
};
@ -153,7 +153,7 @@ TEST_CASE("Simple calculator test", "[general]")
};
int val;
parser.parse("1+2*3", val);
parser.match("1+2*3", val);
REQUIRE(val == 7);
}
@ -171,7 +171,7 @@ TEST_CASE("Calculator test", "[general]")
NUMBER <= oom(cls("0-9"));
// Setup actions
auto reduce = [](const vector<Any>& v) -> long {
auto reduce = [](const vector<any>& v) -> long {
long ret = v[0].get<long>();
for (auto i = 1u; i < v.size(); i += 2) {
auto num = v[i + 1].get<long>();
@ -213,11 +213,11 @@ TEST_CASE("Calculator test2", "[general]")
;
string start;
auto grammar = GrammarGenerator::perform(syntax, strlen(syntax), start, nullptr);
auto grammar = PEGParser::parse(syntax, strlen(syntax), start, nullptr);
auto& g = *grammar;
// Setup actions
auto reduce = [](const vector<Any>& v) -> long {
auto reduce = [](const vector<any>& v) -> long {
long ret = v[0].get<long>();
for (auto i = 1u; i < v.size(); i += 2) {
auto num = v[i + 1].get<long>();
@ -248,7 +248,7 @@ TEST_CASE("Calculator test2", "[general]")
TEST_CASE("Calculator test3", "[general]")
{
// Parse syntax
Parser parser(
peg parser(
" # Grammar for Calculator...\n "
" EXPRESSION <- TERM (TERM_OPERATOR TERM)* "
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
@ -258,7 +258,7 @@ TEST_CASE("Calculator test3", "[general]")
" NUMBER <- [0-9]+ "
);
auto reduce = [](const vector<Any>& v) -> long {
auto reduce = [](const vector<any>& v) -> long {
long ret = v[0].get<long>();
for (auto i = 1u; i < v.size(); i += 2) {
auto num = v[i + 1].get<long>();
@ -281,7 +281,7 @@ TEST_CASE("Calculator test3", "[general]")
// Parse
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(val == -3);
@ -293,15 +293,19 @@ bool exact(Grammar& g, const char* d, const char* s) {
return r.ret && r.len == l;
}
Grammar& make_peg_grammar() {
return PEGParser::grammar();
}
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);
}
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 ") == false);
@ -312,7 +316,7 @@ TEST_CASE("PEG Definition", "[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 ") == true);
@ -323,7 +327,7 @@ TEST_CASE("PEG Expression", "[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", "") == true);
REQUIRE(exact(g, "Sequence", "!") == false);
@ -333,7 +337,7 @@ TEST_CASE("PEG Sequence", "[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", "![']") == true);
REQUIRE(exact(g, "Prefix", "-[']") == false);
@ -343,7 +347,7 @@ TEST_CASE("PEG Prefix", "[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);
@ -356,7 +360,7 @@ TEST_CASE("PEG Suffix", "[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_<-") == false);
REQUIRE(exact(g, "Primary", "( _Identifier0_ _Identifier1_ )") == true);
@ -372,7 +376,7 @@ TEST_CASE("PEG Primary", "[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", "0Identifier_ ") == false);
REQUIRE(exact(g, "Identifier", "Iden|t ") == false);
@ -383,7 +387,7 @@ TEST_CASE("PEG Identifier", "[peg]")
TEST_CASE("PEG IdentStart", "[peg]")
{
Grammar g = make_peg_grammar();
auto g = PEGParser::grammar();
REQUIRE(exact(g, "IdentStart", "_") == true);
REQUIRE(exact(g, "IdentStart", "a") == true);
REQUIRE(exact(g, "IdentStart", "Z") == true);
@ -394,7 +398,7 @@ TEST_CASE("PEG IdentStart", "[peg]")
TEST_CASE("PEG IdentRest", "[peg]")
{
Grammar g = make_peg_grammar();
auto g = PEGParser::grammar();
REQUIRE(exact(g, "IdentRest", "_") == true);
REQUIRE(exact(g, "IdentRest", "a") == true);
REQUIRE(exact(g, "IdentRest", "Z") == true);
@ -405,7 +409,7 @@ TEST_CASE("PEG IdentRest", "[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", "'a\\nb\\tc' ") == true);
REQUIRE(exact(g, "Literal", "'a\\277\tc' ") == true);
@ -424,7 +428,7 @@ TEST_CASE("PEG Literal", "[peg]")
TEST_CASE("PEG Class", "[peg]")
{
Grammar g = make_peg_grammar();
auto g = PEGParser::grammar();
REQUIRE(exact(g, "Class", "[]") == true);
REQUIRE(exact(g, "Class", "[a]") == true);
REQUIRE(exact(g, "Class", "[a-z]") == true);
@ -444,7 +448,7 @@ TEST_CASE("PEG Class", "[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-z") == true);
REQUIRE(exact(g, "Range", "az") == false);
@ -455,7 +459,7 @@ TEST_CASE("PEG Range", "[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", "\\r") == true);
REQUIRE(exact(g, "Char", "\\t") == true);
@ -488,7 +492,7 @@ TEST_CASE("PEG Char", "[peg]")
TEST_CASE("PEG Operators", "[peg]")
{
Grammar g = make_peg_grammar();
auto g = PEGParser::grammar();
REQUIRE(exact(g, "LEFTARROW", "<-") == true);
REQUIRE(exact(g, "SLASH", "/ ") == true);
REQUIRE(exact(g, "AND", "& ") == true);
@ -503,7 +507,7 @@ TEST_CASE("PEG Operators", "[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.") == false);
REQUIRE(exact(g, "Comment", " ") == false);
@ -512,7 +516,7 @@ TEST_CASE("PEG Comment", "[peg]")
TEST_CASE("PEG Space", "[peg]")
{
Grammar g = make_peg_grammar();
auto g = PEGParser::grammar();
REQUIRE(exact(g, "Space", " ") == true);
REQUIRE(exact(g, "Space", "\t") == true);
REQUIRE(exact(g, "Space", "\n") == true);
@ -522,7 +526,7 @@ TEST_CASE("PEG Space", "[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", "\n") == true);
REQUIRE(exact(g, "EndOfLine", "\r") == true);

Loading…
Cancel
Save