From 3f639e37f0ec1bcfd26aaaf9c73cc5a121a879f7 Mon Sep 17 00:00:00 2001 From: yhirose Date: Sat, 14 Feb 2015 10:13:10 -0500 Subject: [PATCH] Changed the interfaces. --- README.md | 36 +++--- example/calc.cc | 6 +- example/calc2.cc | 2 +- lint/peglint.cc | 3 +- peglib.h | 298 ++++++++++++++++++++++++----------------------- test/test.cc | 82 ++++++------- 6 files changed, 216 insertions(+), 211 deletions(-) diff --git a/README.md b/README.md index 47fbef0..63b26f9 100644 --- a/README.md +++ b/README.md @@ -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& v, const std::vector& n) -[](const char* s, size_t l, const std::vector& v) +[](const char* s, size_t l, const std::vector& v, const std::vector& n) +[](const char* s, size_t l, const std::vector& v) [](const char* s, size_t l) -[](const std::vector& v, const std::vector& n) -[](const std::vector& v) +[](const std::vector& v, const std::vector& n) +[](const std::vector& v) []() ``` -`const std::vector& 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& 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& 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& v) { + [](const vector& v) { return v[0].get() + v[1].get(); // 1st choice }, - [](const vector& v) { return v[0]; } // 2nd choice + [](const vector& v) { return v[0]; } // 2nd choice }; parser["Multitive"] = { nullptr, // Default action - [](const vector& v) { + [](const vector& v) { return v[0].get() * v[1].get(); // 1st choice }, - [](const vector& v) { return v[0]; } // 2nd choice + [](const vector& v) { return v[0]; } // 2nd choice }; - parser["Primary"] = [](const vector& v) { + parser["Primary"] = [](const vector& 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 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 ------------ diff --git a/example/calc.cc b/example/calc.cc index e329448..5953fe5 100644 --- a/example/calc.cc +++ b/example/calc.cc @@ -31,7 +31,7 @@ int main(int argc, const char** argv) const char* s = argv[1]; - auto reduce = [](const vector& v) -> long { + auto reduce = [](const vector& v) -> long { auto result = v[0].get(); for (auto i = 1u; i < v.size(); i += 2) { auto num = v[i + 1].get(); @@ -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; } diff --git a/example/calc2.cc b/example/calc2.cc index eb6d59c..aa27dfc 100644 --- a/example/calc2.cc +++ b/example/calc2.cc @@ -31,7 +31,7 @@ int main(int argc, const char** argv) const char* s = argv[1]; - auto reduce = [](const vector& v) -> long { + auto reduce = [](const vector& v) -> long { auto result = v[0].get(); for (auto i = 1u; i < v.size(); i += 2) { auto num = v[i + 1].get(); diff --git a/lint/peglint.cc b/lint/peglint.cc index 901e42c..ded43be 100644 --- a/lint/peglint.cc +++ b/lint/peglint.cc @@ -9,7 +9,6 @@ #include #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; }); diff --git a/peglib.h b/peglib.h index 5299b06..4c32427 100644 --- a/peglib.h +++ b/peglib.h @@ -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 - Any(const T& value) : content_(new holder(value)) {} + any(const T& value) : content_(new holder(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 - 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::value>::type*& = enabler + typename std::enable_if::value>::type*& = enabler > T& get() { assert(content_); @@ -89,7 +89,7 @@ public: template < typename T, - typename std::enable_if::value>::type*& = enabler + typename std::enable_if::value>::type*& = enabler > T& get() { return *this; @@ -97,7 +97,7 @@ public: template < typename T, - typename std::enable_if::value>::type*& = enabler + typename std::enable_if::value>::type*& = enabler > const T& get() const { assert(content_); @@ -106,9 +106,9 @@ public: template < typename T, - typename std::enable_if::value>::type*& = enabler + typename std::enable_if::value>::type*& = enabler > - const Any& get() const { + const any& get() const { return *this; } @@ -166,7 +166,7 @@ private: struct Values { std::vector names; - std::vector values; + std::vector values; }; /* @@ -176,17 +176,17 @@ template < typename R, typename F, typename std::enable_if::value>::type*& = enabler, typename... Args> -Any call(F fn, Args&&... args) { - return Any(fn(std::forward(args)...)); +any call(F fn, Args&&... args) { + return any(fn(std::forward(args)...)); } template < typename R, typename F, typename std::enable_if::value>::type*& = enabler, typename... Args> -Any call(F fn, Args&&... args) { +any call(F fn, Args&&... args) { fn(std::forward(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& v, const std::vector& n) const { + any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) const { return fn_(s, l, v, n); } private: template struct TypeAdaptor { - TypeAdaptor(std::function& v, const std::vector& n)> fn) + TypeAdaptor(std::function& v, const std::vector& n)> fn) : fn_(fn) {} - Any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { + any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { return call(fn_, s, l, v, n); } - std::function& v, const std::vector& n)> fn_; + std::function& v, const std::vector& n)> fn_; }; template struct TypeAdaptor_s_l_v { - TypeAdaptor_s_l_v(std::function& v)> fn) + TypeAdaptor_s_l_v(std::function& v)> fn) : fn_(fn) {} - Any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { + any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { return call(fn_, s, l, v); } - std::function& v)> fn_; + std::function& v)> fn_; }; template struct TypeAdaptor_s_l { TypeAdaptor_s_l(std::function fn) : fn_(fn) {} - Any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { + any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { return call(fn_, s, l); } std::function fn_; @@ -260,50 +260,50 @@ private: template struct TypeAdaptor_v_n { - TypeAdaptor_v_n(std::function& v, const std::vector& n)> fn) : fn_(fn) {} - Any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { + TypeAdaptor_v_n(std::function& v, const std::vector& n)> fn) : fn_(fn) {} + any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { return call(fn_, v, n); } - std::function& v, const std::vector& n)> fn_; + std::function& v, const std::vector& n)> fn_; }; template struct TypeAdaptor_v { - TypeAdaptor_v(std::function& v)> fn) : fn_(fn) {} - Any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { + TypeAdaptor_v(std::function& v)> fn) : fn_(fn) {} + any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { return call(fn_, v); } - std::function& v)> fn_; + std::function& v)> fn_; }; template struct TypeAdaptor_empty { TypeAdaptor_empty(std::function fn) : fn_(fn) {} - Any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { + any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) { return call(fn_); } std::function fn_; }; - typedef std::function& v, const std::vector& n)> Fty; + typedef std::function& v, const std::vector& n)> Fty; template - Fty make_adaptor(F fn, R (F::*mf)(const char*, size_t, const std::vector& v, const std::vector& n) const) { + Fty make_adaptor(F fn, R (F::*mf)(const char*, size_t, const std::vector& v, const std::vector& n) const) { return TypeAdaptor(fn); } template - Fty make_adaptor(F fn, R(*mf)(const char*, size_t, const std::vector& v, const std::vector& n)) { + Fty make_adaptor(F fn, R(*mf)(const char*, size_t, const std::vector& v, const std::vector& n)) { return TypeAdaptor(fn); } template - Fty make_adaptor(F fn, R (F::*mf)(const char*, size_t, const std::vector& v) const) { + Fty make_adaptor(F fn, R (F::*mf)(const char*, size_t, const std::vector& v) const) { return TypeAdaptor_s_l_v(fn); } template - Fty make_adaptor(F fn, R(*mf)(const char*, size_t, const std::vector& v)) { + Fty make_adaptor(F fn, R(*mf)(const char*, size_t, const std::vector& v)) { return TypeAdaptor_s_l_v(fn); } @@ -318,22 +318,22 @@ private: } template - Fty make_adaptor(F fn, R (F::*mf)(const std::vector& v, const std::vector& n) const) { + Fty make_adaptor(F fn, R (F::*mf)(const std::vector& v, const std::vector& n) const) { return TypeAdaptor_v_n(fn); } template - Fty make_adaptor(F fn, R (*mf)(const std::vector& v, const std::vector& n)) { + Fty make_adaptor(F fn, R (*mf)(const std::vector& v, const std::vector& n)) { return TypeAdaptor_v_n(fn); } template - Fty make_adaptor(F fn, R (F::*mf)(const std::vector& v) const) { + Fty make_adaptor(F fn, R (F::*mf)(const std::vector& v) const) { return TypeAdaptor_v(fn); } template - Fty make_adaptor(F fn, R (*mf)(const std::vector& v)) { + Fty make_adaptor(F fn, R (*mf)(const std::vector& v)) { return TypeAdaptor_v(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 chr(char c) { return std::make_shared(c); } -inline std::shared_ptr any() { +inline std::shared_ptr dot() { return std::make_shared(); } @@ -923,68 +923,6 @@ inline std::shared_ptr ref(const std::map& grammar * PEG parser generator *---------------------------------------------------------------------------*/ -typedef std::map 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 line_info(const char* s, const char* ptr) { auto p = s; auto col_ptr = p; @@ -1003,24 +941,90 @@ inline std::pair line_info(const char* s, const char* ptr) { return std::make_pair(no, col); } +typedef std::map Grammar; typedef std::function Log; -class GrammarGenerator +class PEGParser { public: - static std::shared_ptr 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 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& v) { + g["Expression"] = [&](const std::vector& v) { if (v.size() == 1) { return v[0].get>(); } else { @@ -1035,7 +1039,7 @@ private: } }; - peg["Sequence"] = [&](const std::vector& v) { + g["Sequence"] = [&](const std::vector& v) { if (v.size() == 1) { return v[0].get>(); } else { @@ -1048,7 +1052,7 @@ private: } }; - peg["Prefix"] = [&](const std::vector& v, const std::vector& n) { + g["Prefix"] = [&](const std::vector& v, const std::vector& n) { std::shared_ptr ope; if (v.size() == 1) { ope = v[0].get>(); @@ -1064,7 +1068,7 @@ private: return ope; }; - peg["Suffix"] = [&](const std::vector& v, const std::vector& n) { + g["Suffix"] = [&](const std::vector& v, const std::vector& n) { auto ope = v[0].get>(); 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& v) { + g["Literal"] = [](const std::vector& 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& v) { + g["Class"] = [](const std::vector& 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 refs; - peg["Definition"] = [&](const std::vector& v) { + g["Definition"] = [&](const std::vector& v) { const auto& name = v[0].get(); (*grammar)[name] <= v[2].get>(); (*grammar)[name].name = name; @@ -1121,20 +1125,20 @@ private: } }; - peg["Primary"].actions = { - [&](const std::vector& v) { + g["Primary"].actions = { + [&](const std::vector& v) { return v[0]; }, - [&](const char* s, size_t l, const std::vector& v) { + [&](const char* s, size_t l, const std::vector& v) { refs[v[0]] = s; return ref(*grammar, v[0]); }, - [&](const std::vector& v) { + [&](const std::vector& 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 - 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 - 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) { diff --git a/test/test.cc b/test/test.cc index 8696553..ba6f656 100644 --- a/test/test.cc +++ b/test/test.cc @@ -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& v) { return v[0].get() + v[1].get(); }, + [](const vector& v) { return v[0].get() + v[1].get(); }, // Action for the second choice - [](const vector& v) { return v[0]; } + [](const vector& v) { return v[0]; } }; - parser["Multitive"] = [](const vector& v) { + parser["Multitive"] = [](const vector& v) { return v.size() == 1 ? int(v[0]) : v[0].get() * v[1].get(); }; - parser["Primary"] = [](const vector& v) { + parser["Primary"] = [](const vector& 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& v) -> long { + auto reduce = [](const vector& v) -> long { long ret = v[0].get(); for (auto i = 1u; i < v.size(); i += 2) { auto num = v[i + 1].get(); @@ -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& v) -> long { + auto reduce = [](const vector& v) -> long { long ret = v[0].get(); for (auto i = 1u; i < v.size(); i += 2) { auto num = v[i + 1].get(); @@ -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& v) -> long { + auto reduce = [](const vector& v) -> long { long ret = v[0].get(); for (auto i = 1u; i < v.size(); i += 2) { auto num = v[i + 1].get(); @@ -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);