diff --git a/README.md b/README.md index a41f737..936ead0 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,14 @@ cpp-peglib C++11 header-only [PEG](http://en.wikipedia.org/wiki/Parsing_expression_grammar) (Parsing Expression Grammars) library. -*cpp-peglib* tries to provide more expressive parsing experience than common regular expression libraries such as std::regex. It also keeps it in mind that users can easily start using it. +*cpp-peglib* tries to provide more expressive parsing experience than common regular expression libraries such as std::regex. This library depends on only one header file. So, you can start using it right away just by including `peglib.h` in your project. -The PEG syntax that *cpp-peglib* understands is described on page 2 in the [document](http://pdos.csail.mit.edu/papers/parsing:popl04.pdf). +The PEG syntax is well described on page 2 in the [document](http://pdos.csail.mit.edu/papers/parsing:popl04.pdf). How to use ---------- -What if we want to extract only tag names in brackets from ` [tag1] [tag2] [tag3] [tag4]... `? It's a bit hard to do it with `std::regex`. We have to write a loop logic, since it doesn't support [Repeated Captures](http://www.boost.org/doc/libs/1_57_0/libs/regex/doc/html/boost_regex/captures.html#boost_regex.captures.repeated_captures). PEG can handle it pretty easily. +What if we want to extract only tag names in brackets from ` [tag1] [tag2] [tag3] [tag4]... `? It's a bit hard to do it with *std::regex*, since it doesn't support [Repeated Captures](http://www.boost.org/doc/libs/1_57_0/libs/regex/doc/html/boost_regex/captures.html#boost_regex.captures.repeated_captures). PEG can, however, handle the repetition pretty easily. PEG grammar for this task could be like this: @@ -20,7 +20,7 @@ TAG_NAME <- (!']' .)+ _ <- [ \t]* ``` -Here is how to parse text with the PEG syntax and retreive tag names: +Here is how to parse text with the PEG syntax and retrieve tag names: ```c++ @@ -131,14 +131,6 @@ _ = zom(cls(" \t")); auto ret = ROOT.parse(" [tag1] [tag:2] [tag-3] "); ``` -It is also possible to specify a *string match action* with a *grp* operator. The string match action doesn't affect the resular semantic action behavior. - -```c++ -ROOT = seq(_, zom(seq(chr('['), grp(TAG_NAME, [&](const char* s, size_t l) { tags.push_back(string(s, l)); }), chr(']'), _))); -TAG_NAME = oom(seq(npd(chr(']')), any())); -_ = zom(cls(" \t")); -``` - 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: @@ -182,6 +174,7 @@ Other C++ PEG parser libraries Thanks to the authors of the libraries that inspired *cpp-peglib*. + * [Boost Spirit X3](https://github.com/djowel/spirit_x3) - A set of C++ libraries for parsing and output generation implemented as Domain Specific Embedded Languages (DSEL) using Expression templates and Template Meta-Programming * [PEGTL](https://github.com/ColinH/PEGTL) - Parsing Expression Grammar Template Library * [lars::Parser](https://github.com/TheLartians/Parser) - A header-only linear-time c++ parsing expression grammar (PEG) parser generator supporting left-recursion and grammar ambiguity diff --git a/peglib.h b/peglib.h index d4001a2..ddf6ad0 100644 --- a/peglib.h +++ b/peglib.h @@ -16,6 +16,7 @@ #include #include #include +#include namespace peglib { @@ -114,6 +115,16 @@ public: return *this; } + operator const std::string&() const { + return get(); + } + + operator std::string&() { + return get(); + } + + // TODO: Add more implecit cast operators + private: struct placeholder { virtual ~placeholder() {}; @@ -140,338 +151,15 @@ private: * PEG *---------------------------------------------------------------------------*/ -/* - * Forward declalations - */ -class Definition; - /* * Semantic values */ -struct SemanticValues +struct Values { std::vector names; std::vector values; }; -/* - * Match - */ -struct Match -{ - Match(bool _ret, size_t _len) : ret(_ret), len(_len) {} - bool ret; - size_t len; -}; - -Match success(size_t len) { - return Match(true, len); -} - -Match fail() { - return Match(false, 0); -} - -/* - * Rules - */ -class Rule -{ - public: - virtual ~Rule() {}; - virtual Match parse(const char* s, size_t l, SemanticValues& sv) const = 0; -}; - -class Sequence : public Rule -{ -public: - Sequence(const Sequence& rhs) : rules_(rhs.rules_) {} - -#if defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015 - // NOTE: Compiler Error C2797 on Visual Studio 2013 - // "The C++ compiler in Visual Studio does not implement list - // initialization inside either a member initializer list or a non-static - // data member initializer. Before Visual Studio 2013 Update 3, this was - // silently converted to a function call, which could lead to bad code - // generation. Visual Studio 2013 Update 3 reports this as an error." - template - Sequence(const Args& ...args) { - rules_ = std::vector>{ static_cast>(args)... }; - } -#else - template - Sequence(const Args& ...args) : rules_{ static_cast>(args)... } {} -#endif - - Sequence(const std::vector>& rules) : rules_(rules) {} - Sequence(std::vector>&& rules) : rules_(std::move(rules)) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - size_t i = 0; - for (const auto& rule : rules_) { - auto m = rule->parse(s + i, l - i, sv); - if (!m.ret) { - return fail(); - } - i += m.len; - } - return success(i); - } - -private: - std::vector> rules_; -}; - -class PrioritizedChoice : public Rule -{ -public: -#if defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015 - // NOTE: Compiler Error C2797 on Visual Studio 2013 - // "The C++ compiler in Visual Studio does not implement list - // initialization inside either a member initializer list or a non-static - // data member initializer. Before Visual Studio 2013 Update 3, this was - // silently converted to a function call, which could lead to bad code - // generation. Visual Studio 2013 Update 3 reports this as an error." - template - PrioritizedChoice(const Args& ...args) { - rules_ = std::vector>{ static_cast>(args)... }; - } -#else - template - PrioritizedChoice(const Args& ...args) : rules_{ static_cast>(args)... } {} -#endif - - PrioritizedChoice(const std::vector>& rules) : rules_(rules) {} - PrioritizedChoice(std::vector>&& rules) : rules_(std::move(rules)) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - auto sz = sv.values.size(); - for (const auto& rule : rules_) { - auto m = rule->parse(s, l, sv); - if (m.ret) { - return success(m.len); - } - while (sv.values.size() > sz) { - sv.values.pop_back(); - sv.names.pop_back(); - } - } - return fail(); - } - - -private: - std::vector> rules_; -}; - -class ZeroOrMore : public Rule -{ -public: - ZeroOrMore(const std::shared_ptr& rule) : rule_(rule) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - auto i = 0; - while (l - i > 0) { - auto m = rule_->parse(s + i, l - i, sv); - if (!m.ret) { - break; - } - i += m.len; - } - return success(i); - } - -private: - std::shared_ptr rule_; -}; - -class OneOrMore : public Rule -{ -public: - OneOrMore(const std::shared_ptr& rule) : rule_(rule) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - auto m = rule_->parse(s, l, sv); - if (!m.ret) { - return fail(); - } - auto i = m.len; - while (l - i > 0) { - auto m = rule_->parse(s + i, l - i, sv); - if (!m.ret) { - break; - } - i += m.len; - } - return success(i); - } - -private: - std::shared_ptr rule_; -}; - -class Option : public Rule -{ -public: - Option(const std::shared_ptr& rule) : rule_(rule) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - auto m = rule_->parse(s, l, sv); - return success(m.ret ? m.len : 0); - } - -private: - std::shared_ptr rule_; -}; - -class AndPredicate : public Rule -{ -public: - AndPredicate(const std::shared_ptr& rule) : rule_(rule) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - auto m = rule_->parse(s, l, sv); - if (m.ret) { - return success(0); - } else { - return fail(); - } - } - -private: - std::shared_ptr rule_; -}; - -class NotPredicate : public Rule -{ -public: - NotPredicate(const std::shared_ptr& rule) : rule_(rule) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - auto m = rule_->parse(s, l, sv); - if (m.ret) { - return fail(); - } else { - return success(0); - } - } - -private: - std::shared_ptr rule_; -}; - -class LiteralString : public Rule -{ -public: - LiteralString(const char* s) : lit_(s) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - auto i = 0u; - for (; i < lit_.size(); i++) { - if (i >= l || s[i] != lit_[i]) { - return fail(); - } - } - return success(i); - } - -private: - std::string lit_; -}; - -class CharacterClass : public Rule -{ -public: - CharacterClass(const char* chars) : chars_(chars) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - if (l < 1) { - return fail(); - } - auto ch = s[0]; - auto i = 0u; - while (i < chars_.size()) { - if (i + 2 < chars_.size() && chars_[i + 1] == '-') { - if (chars_[i] <= ch && ch <= chars_[i + 2]) { - return success(1); - } - i += 3; - } else { - if (chars_[i] == ch) { - return success(1); - } - i += 1; - } - } - return fail(); - } - -private: - std::string chars_; -}; - -class Character : public Rule -{ -public: - Character(char ch) : ch_(ch) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - if (l < 1 || s[0] != ch_) { - return fail(); - } - return success(1); - } - -private: - char ch_; -}; - -class AnyCharacter : public Rule -{ -public: - Match parse(const char* s, size_t l, SemanticValues& sv) const { - if (l < 1) { - return fail(); - } - return success(1); - } -}; - -class Grouping : public Rule -{ -public: - Grouping(const std::shared_ptr& rule) : rule_(rule) {} - Grouping(const std::shared_ptr& rule, std::function match) : rule_(rule), match_(match) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - assert(rule_); - auto m = rule_->parse(s, l, sv); - if (m.ret && match_) { - match_(s, m.len); - } - return m; - } - -private: - std::shared_ptr rule_; - std::function match_; -}; - -class WeakHolder : public Rule -{ -public: - WeakHolder(const std::shared_ptr& rule) : weak_(rule) {} - - Match parse(const char* s, size_t l, SemanticValues& sv) const { - auto rule = weak_.lock(); - assert(rule); - return rule->parse(s, l, sv); - } - -private: - std::weak_ptr weak_; -}; - /* * Semantic action */ @@ -492,16 +180,20 @@ Any call(F fn, Args&&... args) { return Any(); } -class SemanticAction +class Action { public: - operator bool() const { - return (bool)fn_; - } + Action() = default; - Any operator()(const char* s, size_t l, const std::vector& v, const std::vector& n) const { - return fn_(s, l, v, n); - } + Action(const Action& rhs) : fn_(rhs.fn_) {} + + //Action(Action&& rhs) : fn_(std::move(rhs.fn_)) {} + + template ::value>::type*& = enabler> + Action(F fn) : fn_(make_adaptor(fn, &F::operator())) {} + + template ::value>::type*& = enabler> + Action(F fn) : fn_(make_adaptor(fn, fn)) {} template ::value>::type*& = enabler> void operator=(F fn) { @@ -513,6 +205,14 @@ public: fn_ = make_adaptor(fn, fn); } + operator bool() const { + return (bool)fn_; + } + + 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 { @@ -635,52 +335,398 @@ private: Fty fn_; }; +/* + * Match + */ +struct Match +{ + Match(bool _ret, size_t _len, size_t _id) : ret(_ret), len(_len), id(_id) {} + bool ret; + size_t len; + size_t id; +}; + +Match success(size_t len, size_t id = 0) { + return Match(true, len, id); +} + +Match fail() { + return Match(false, 0, -1); +} + +/* + * Parser operators + */ +class Ope +{ +public: + virtual ~Ope() {}; + + virtual Match parse_core(const char* s, size_t l, Values& v) const = 0; + + virtual Match parse(const char* s, size_t l, Values& v) const { + // NOTE: This is a good place to set a break point for debugging... + return parse_core(s, l, v); + } +}; + +class Sequence : public Ope +{ +public: + Sequence(const Sequence& rhs) : rules_(rhs.rules_) {} + +#if defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015 + // NOTE: Compiler Error C2797 on Visual Studio 2013 + // "The C++ compiler in Visual Studio does not implement list + // initialization inside either a member initializer list or a non-static + // data member initializer. Before Visual Studio 2013 Update 3, this was + // silently converted to a function call, which could lead to bad code + // generation. Visual Studio 2013 Update 3 reports this as an error." + template + Sequence(const Args& ...args) { + rules_ = std::vector>{ static_cast>(args)... }; + } +#else + template + Sequence(const Args& ...args) : rules_{ static_cast>(args)... } {} +#endif + + Sequence(const std::vector>& rules) : rules_(rules) {} + Sequence(std::vector>&& rules) : rules_(std::move(rules)) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + size_t i = 0; + for (const auto& rule : rules_) { + auto m = rule->parse(s + i, l - i, v); + if (!m.ret) { + return fail(); + } + i += m.len; + } + return success(i); + } + +private: + std::vector> rules_; +}; + +class PrioritizedChoice : public Ope +{ +public: +#if defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015 + // NOTE: Compiler Error C2797 on Visual Studio 2013 + // "The C++ compiler in Visual Studio does not implement list + // initialization inside either a member initializer list or a non-static + // data member initializer. Before Visual Studio 2013 Update 3, this was + // silently converted to a function call, which could lead to bad code + // generation. Visual Studio 2013 Update 3 reports this as an error." + template + PrioritizedChoice(const Args& ...args) { + rules_ = std::vector>{ static_cast>(args)... }; + } +#else + template + PrioritizedChoice(const Args& ...args) : rules_{ static_cast>(args)... } {} +#endif + + PrioritizedChoice(const std::vector>& rules) : rules_(rules) {} + PrioritizedChoice(std::vector>&& rules) : rules_(std::move(rules)) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + size_t id = 0; + for (const auto& rule : rules_) { + Values chldsv; + auto m = rule->parse(s, l, chldsv); + if (m.ret) { + if (!chldsv.values.empty()) { + for (const auto& x: chldsv.values) { + v.values.push_back(x); + } + for (const auto& x: chldsv.names) { + v.names.push_back(x); + } + } + return success(m.len, id); + } + id++; + } + return fail(); + } + + size_t size() const { return rules_.size(); } + +private: + std::vector> rules_; +}; + +class ZeroOrMore : public Ope +{ +public: + ZeroOrMore(const std::shared_ptr& rule) : rule_(rule) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + auto i = 0; + while (l - i > 0) { + auto m = rule_->parse(s + i, l - i, v); + if (!m.ret) { + break; + } + i += m.len; + } + return success(i); + } + +private: + std::shared_ptr rule_; +}; + +class OneOrMore : public Ope +{ +public: + OneOrMore(const std::shared_ptr& rule) : rule_(rule) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + auto m = rule_->parse(s, l, v); + if (!m.ret) { + return fail(); + } + auto i = m.len; + while (l - i > 0) { + auto m = rule_->parse(s + i, l - i, v); + if (!m.ret) { + break; + } + i += m.len; + } + return success(i); + } + +private: + std::shared_ptr rule_; +}; + +class Option : public Ope +{ +public: + Option(const std::shared_ptr& rule) : rule_(rule) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + auto m = rule_->parse(s, l, v); + return success(m.ret ? m.len : 0); + } + +private: + std::shared_ptr rule_; +}; + +class AndPredicate : public Ope +{ +public: + AndPredicate(const std::shared_ptr& rule) : rule_(rule) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + auto m = rule_->parse(s, l, v); + if (m.ret) { + return success(0); + } else { + return fail(); + } + } + +private: + std::shared_ptr rule_; +}; + +class NotPredicate : public Ope +{ +public: + NotPredicate(const std::shared_ptr& rule) : rule_(rule) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + auto m = rule_->parse(s, l, v); + if (m.ret) { + return fail(); + } else { + return success(0); + } + } + +private: + std::shared_ptr rule_; +}; + +class LiteralString : public Ope +{ +public: + LiteralString(const char* s) : lit_(s) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + auto i = 0u; + for (; i < lit_.size(); i++) { + if (i >= l || s[i] != lit_[i]) { + return fail(); + } + } + return success(i); + } + +private: + std::string lit_; +}; + +class CharacterClass : public Ope +{ +public: + CharacterClass(const char* chars) : chars_(chars) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + // TODO: UTF8 support + if (l < 1) { + return fail(); + } + auto ch = s[0]; + auto i = 0u; + while (i < chars_.size()) { + if (i + 2 < chars_.size() && chars_[i + 1] == '-') { + if (chars_[i] <= ch && ch <= chars_[i + 2]) { + return success(1); + } + i += 3; + } else { + if (chars_[i] == ch) { + return success(1); + } + i += 1; + } + } + return fail(); + } + +private: + std::string chars_; +}; + +class Character : public Ope +{ +public: + Character(char ch) : ch_(ch) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + // TODO: UTF8 support + if (l < 1 || s[0] != ch_) { + return fail(); + } + return success(1); + } + +private: + char ch_; +}; + +class AnyCharacter : public Ope +{ +public: + Match parse_core(const char* s, size_t l, Values& v) const { + // TODO: UTF8 support + if (l < 1) { + return fail(); + } + return success(1); + } + +}; + +class Grouping : public Ope +{ +public: + Grouping(const std::shared_ptr& rule) : rule_(rule) {} + Grouping(const std::shared_ptr& rule, std::function match) : rule_(rule), match_(match) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + assert(rule_); + auto m = rule_->parse(s, l, v); + if (m.ret && match_) { + match_(s, m.len); + } + return m; + } + +private: + std::shared_ptr rule_; + std::function match_; +}; + +class WeakHolder : public Ope +{ +public: + WeakHolder(const std::shared_ptr& rule) : weak_(rule) {} + + Match parse_core(const char* s, size_t l, Values& v) const { + auto rule = weak_.lock(); + assert(rule); + return rule->parse(s, l, v); + } + +private: + std::weak_ptr weak_; +}; + /* * Definition */ class Definition { public: - Definition() : rule_(std::make_shared(this)) {} + Definition() + : actions(1) + , holder_(std::make_shared(this)) {} Definition(const Definition& rhs) : name(rhs.name) - , rule_(rhs.rule_) + , actions(1) + , holder_(rhs.holder_) { - non_terminal().outer_ = this; + holder_->outer_ = this; } Definition(Definition&& rhs) : name(std::move(rhs.name)) - , rule_(std::move(rhs.rule_)) + , actions(1) + , holder_(std::move(rhs.holder_)) { - non_terminal().outer_ = this; + holder_->outer_ = this; } - Definition(const std::shared_ptr& rule) - : rule_(std::make_shared(this)) + Definition(const std::shared_ptr& rule) + : actions(1) + , holder_(std::make_shared(this)) { - set_rule(rule); + holder_->rule_ = rule; } - operator std::shared_ptr() { - return std::make_shared(rule_); + operator std::shared_ptr() { + return std::make_shared(holder_); } - Definition& operator<=(const std::shared_ptr& rule) { - set_rule(rule); + Definition& operator<=(const std::shared_ptr& rule) { + holder_->rule_ = rule; + return *this; + } + + Definition& rule(const std::shared_ptr& rule) { + holder_->rule_ = rule; return *this; } template bool parse(const char* s, size_t l, T& val) const { - SemanticValues sv; + Values v; - auto m = rule_->parse(s, l, sv); + auto m = holder_->parse(s, l, v); auto ret = m.ret && m.len == l; - if (ret && !sv.values.empty() && !sv.values.front().is_undefined()) { - val = sv.values[0].get(); + if (ret && !v.values.empty() && !v.values.front().is_undefined()) { + val = v.values[0].get(); } return ret; @@ -692,8 +738,8 @@ public: } bool parse(const char* s, size_t l) const { - SemanticValues sv; - auto m = rule_->parse(s, l, sv); + Values v; + auto m = holder_->parse(s, l, v); return m.ret && m.len == l; } @@ -701,72 +747,81 @@ public: return parse(s, strlen(s)); } - template - void operator,(F fn) { - action = fn; + Definition& operator=(Action ac) { + assert(!actions.empty()); + actions[0] = ac; + return *this; } - std::string name; - SemanticAction action; + Definition& operator=(std::initializer_list acs) { + actions = acs; + return *this; + } + + template + Definition& operator,(T fn) { + operator=(fn); + return *this; + } + + std::string name; + std::vector actions; private: friend class DefinitionReference; - class NonTerminal : public Rule + class Holder : public Ope { public: - NonTerminal(Definition* outer) : outer_(outer) {}; + Holder(Definition* outer) + : outer_(outer) {} - Match parse(const char* s, size_t l, SemanticValues& sv) const { + Match parse_core(const char* s, size_t l, Values& v) const { if (!rule_) { throw std::logic_error("Uninitialized definition rule was used..."); } - SemanticValues chldsv; - + Values chldsv; auto m = rule_->parse(s, l, chldsv); if (m.ret) { - sv.names.push_back(outer_->name); - auto val = reduce(s, m.len, chldsv, outer_->action); - sv.values.push_back(val); - } + v.names.push_back(outer_->name); + assert(!outer_->actions.empty()); + + auto id = m.id + 1; + const auto& ac = (id < outer_->actions.size() && outer_->actions[id]) + ? outer_->actions[id] + : outer_->actions[0]; + + v.values.push_back(reduce(s, m.len, chldsv, ac)); + } return m; } private: friend class Definition; - template - Any reduce(const char* s, size_t l, const SemanticValues& sv, Action action) const { + Any reduce(const char* s, size_t l, const Values& v, const Action& action) const { if (action) { - return action(s, l, sv.values, sv.names); - } else if (sv.values.empty()) { + return action(s, l, v.values, v.names); + } else if (v.values.empty()) { return Any(); } else { - return sv.values.front(); + return v.values.front(); } } - std::shared_ptr rule_; + std::shared_ptr rule_; Definition* outer_; }; Definition& operator=(const Definition& rhs); Definition& operator=(Definition&& rhs); - NonTerminal& non_terminal() { - return *dynamic_cast(rule_.get()); - } - - void set_rule(const std::shared_ptr& rule) { - non_terminal().rule_ = rule; - } - - std::shared_ptr rule_; + std::shared_ptr holder_; }; -class DefinitionReference : public Rule +class DefinitionReference : public Ope { public: DefinitionReference( @@ -774,90 +829,77 @@ public: : grammar_(grammar) , name_(name) {} - Match parse(const char* s, size_t l, SemanticValues& sv) const { - auto rule = grammar_.at(name_).rule_; - return rule->parse(s, l, sv); + Match parse_core(const char* s, size_t l, Values& v) const { + return grammar_.at(name_).holder_->parse(s, l, v); } + std::string name() const { return std::string(); }; + private: const std::map& grammar_; std::string name_; }; +typedef Definition rule; + /* * Factories */ template -std::shared_ptr seq(Args&& ...args) { - return std::make_shared(static_cast>(args)...); -} - -inline std::shared_ptr seq_v(const std::vector>& rules) { - return std::make_shared(rules); -} - -inline std::shared_ptr seq_v(std::vector>&& rules) { - return std::make_shared(std::move(rules)); +std::shared_ptr seq(Args&& ...args) { + return std::make_shared(static_cast>(args)...); } template -std::shared_ptr cho(Args&& ...args) { - return std::make_shared(static_cast>(args)...); +std::shared_ptr cho(Args&& ...args) { + return std::make_shared(static_cast>(args)...); } -inline std::shared_ptr cho_v(const std::vector>& rules) { - return std::make_shared(rules); -} - -inline std::shared_ptr cho_v(std::vector>&& rules) { - return std::make_shared(std::move(rules)); -} - -inline std::shared_ptr zom(const std::shared_ptr& rule) { +inline std::shared_ptr zom(const std::shared_ptr& rule) { return std::make_shared(rule); } -inline std::shared_ptr oom(const std::shared_ptr& rule) { +inline std::shared_ptr oom(const std::shared_ptr& rule) { return std::make_shared(rule); } -inline std::shared_ptr opt(const std::shared_ptr& rule) { +inline std::shared_ptr opt(const std::shared_ptr& rule) { return std::make_shared