// // peglib.h // // Copyright (c) 2015-18 Yuji Hirose. All rights reserved. // MIT License // #ifndef CPPPEGLIB_PEGLIB_H #define CPPPEGLIB_PEGLIB_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include // guard for older versions of VC++ #ifdef _MSC_VER // VS2013 has no constexpr #if (_MSC_VER == 1800) #define PEGLIB_NO_CONSTEXPR_SUPPORT #elif (_MSC_VER >= 1800) // good to go #else (_MSC_VER < 1800) #error "Requires C+11 support" #endif #endif // define if the compiler doesn't support unicode characters reliably in the // source code //#define PEGLIB_NO_UNICODE_CHARS namespace peg { #if __clang__ == 1 && __clang_major__ <= 5 static void* enabler = nullptr; // workaround for Clang version <= 5.0.0 #else extern void* enabler; #endif /*----------------------------------------------------------------------------- * any *---------------------------------------------------------------------------*/ class any { public: any() : content_(nullptr) {} any(const any& rhs) : content_(rhs.clone()) {} any(any&& rhs) : content_(rhs.content_) { rhs.content_ = nullptr; } template any(const T& value) : content_(new holder(value)) {} any& operator=(const any& rhs) { if (this != &rhs) { if (content_) { delete content_; } content_ = rhs.clone(); } return *this; } any& operator=(any&& rhs) { if (this != &rhs) { if (content_) { delete content_; } content_ = rhs.content_; rhs.content_ = nullptr; } return *this; } ~any() { delete content_; } bool is_undefined() const { return content_ == nullptr; } template < typename T, typename std::enable_if::value>::type*& = enabler > T& get() { if (!content_) { throw std::bad_cast(); } auto p = dynamic_cast*>(content_); assert(p); if (!p) { throw std::bad_cast(); } return p->value_; } template < typename T, typename std::enable_if::value>::type*& = enabler > T& get() { return *this; } template < typename T, typename std::enable_if::value>::type*& = enabler > const T& get() const { assert(content_); auto p = dynamic_cast*>(content_); assert(p); if (!p) { throw std::bad_cast(); } return p->value_; } template < typename T, typename std::enable_if::value>::type*& = enabler > const any& get() const { return *this; } private: struct placeholder { virtual ~placeholder() {} virtual placeholder* clone() const = 0; }; template struct holder : placeholder { holder(const T& value) : value_(value) {} placeholder* clone() const override { return new holder(value_); } T value_; }; placeholder* clone() const { return content_ ? content_->clone() : nullptr; } placeholder* content_; }; /*----------------------------------------------------------------------------- * scope_exit *---------------------------------------------------------------------------*/ // This is based on "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189". template struct scope_exit { explicit scope_exit(EF&& f) : exit_function(std::move(f)) , execute_on_destruction{true} {} scope_exit(scope_exit&& rhs) : exit_function(std::move(rhs.exit_function)) , execute_on_destruction{rhs.execute_on_destruction} { rhs.release(); } ~scope_exit() { if (execute_on_destruction) { this->exit_function(); } } void release() { this->execute_on_destruction = false; } private: scope_exit(const scope_exit&) = delete; void operator=(const scope_exit&) = delete; scope_exit& operator=(scope_exit&&) = delete; EF exit_function; bool execute_on_destruction; }; template auto make_scope_exit(EF&& exit_function) -> scope_exit { return scope_exit::type>(std::forward(exit_function)); } /*----------------------------------------------------------------------------- * PEG *---------------------------------------------------------------------------*/ /* * Line information utility function */ inline std::pair line_info(const char* start, const char* cur) { auto p = start; auto col_ptr = p; auto no = 1; while (p < cur) { if (*p == '\n') { no++; col_ptr = p + 1; } p++; } auto col = p - col_ptr + 1; return std::make_pair(no, col); } /* * Semantic values */ struct SemanticValues : protected std::vector { // Input text const char* path; const char* ss; // Matched string const char* c_str() const { return s_; } size_t length() const { return n_; } std::string str() const { return std::string(s_, n_); } // Line number and column at which the matched string is std::pair line_info() const { return peg::line_info(ss, s_); } // Choice number (0 based index) size_t choice() const { return choice_; } // Tokens std::vector> tokens; std::string token(size_t id = 0) const { if (!tokens.empty()) { assert(id < tokens.size()); const auto& tok = tokens[id]; return std::string(tok.first, tok.second); } return std::string(s_, n_); } // Transform the semantic value vector to another vector template auto transform(size_t beg = 0, size_t end = static_cast(-1)) const -> vector { return this->transform(beg, end, [](const any& v) { return v.get(); }); } SemanticValues() : s_(nullptr), n_(0), choice_(0) {} using std::vector::iterator; using std::vector::const_iterator; using std::vector::size; using std::vector::empty; using std::vector::assign; using std::vector::begin; using std::vector::end; using std::vector::rbegin; using std::vector::rend; using std::vector::operator[]; using std::vector::at; using std::vector::resize; using std::vector::front; using std::vector::back; using std::vector::push_back; using std::vector::pop_back; using std::vector::insert; using std::vector::erase; using std::vector::clear; using std::vector::swap; using std::vector::emplace; using std::vector::emplace_back; private: friend class Context; friend class PrioritizedChoice; friend class Holder; const char* s_; size_t n_; size_t choice_; template auto transform(F f) const -> vector::type> { vector::type> r; for (const auto& v: *this) { r.emplace_back(f(v)); } return r; } template auto transform(size_t beg, size_t end, F f) const -> vector::type> { vector::type> r; end = (std::min)(end, size()); for (size_t i = beg; i < end; i++) { r.emplace_back(f((*this)[i])); } return r; } }; /* * Semantic action */ template < typename R, typename F, typename std::enable_if::value>::type*& = enabler, typename... Args> any call(F fn, Args&&... args) { fn(std::forward(args)...); return any(); } template < typename R, typename F, typename std::enable_if::type, any>::value>::type*& = enabler, typename... Args> any call(F fn, Args&&... args) { return fn(std::forward(args)...); } template < typename R, typename F, typename std::enable_if< !std::is_void::value && !std::is_same::type, any>::value>::type*& = enabler, typename... Args> any call(F fn, Args&&... args) { return any(fn(std::forward(args)...)); } class Action { public: Action() = default; Action(const Action& rhs) : fn_(rhs.fn_) {} template ::value && !std::is_same::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> Action(F /*fn*/) {} template ::value && !std::is_same::value>::type*& = enabler> void operator=(F fn) { fn_ = make_adaptor(fn, &F::operator()); } template ::value>::type*& = enabler> void operator=(F fn) { fn_ = make_adaptor(fn, fn); } template ::value>::type*& = enabler> void operator=(F /*fn*/) {} Action& operator=(const Action& rhs) = default; operator bool() const { return bool(fn_); } any operator()(const SemanticValues& sv, any& dt) const { return fn_(sv, dt); } private: template struct TypeAdaptor { TypeAdaptor(std::function fn) : fn_(fn) {} any operator()(const SemanticValues& sv, any& /*dt*/) { return call(fn_, sv); } std::function fn_; }; template struct TypeAdaptor_c { TypeAdaptor_c(std::function fn) : fn_(fn) {} any operator()(const SemanticValues& sv, any& dt) { return call(fn_, sv, dt); } std::function fn_; }; typedef std::function Fty; template Fty make_adaptor(F fn, R (F::* /*mf*/)(const SemanticValues& sv) const) { return TypeAdaptor(fn); } template Fty make_adaptor(F fn, R (F::* /*mf*/)(const SemanticValues& sv)) { return TypeAdaptor(fn); } template Fty make_adaptor(F fn, R (* /*mf*/)(const SemanticValues& sv)) { return TypeAdaptor(fn); } template Fty make_adaptor(F fn, R (F::* /*mf*/)(const SemanticValues& sv, any& dt) const) { return TypeAdaptor_c(fn); } template Fty make_adaptor(F fn, R (F::* /*mf*/)(const SemanticValues& sv, any& dt)) { return TypeAdaptor_c(fn); } template Fty make_adaptor(F fn, R(* /*mf*/)(const SemanticValues& sv, any& dt)) { return TypeAdaptor_c(fn); } Fty fn_; }; /* * Semantic predicate */ // Note: 'parse_error' exception class should be be used in sematic action handlers to reject the rule. struct parse_error { parse_error() = default; parse_error(const char* s) : s_(s) {} const char* what() const { return s_.empty() ? nullptr : s_.c_str(); } private: std::string s_; }; /* * Result */ inline bool success(size_t len) { return len != static_cast(-1); } inline bool fail(size_t len) { return len == static_cast(-1); } /* * Context */ class Context; class Ope; class Definition; typedef std::function Tracer; class Context { public: const char* path; const char* s; const size_t l; const char* error_pos; const char* message_pos; std::string message; // TODO: should be `int`. std::vector> value_stack; size_t value_stack_size; std::vector>> args_stack; size_t nest_level; bool in_token; std::shared_ptr whitespaceOpe; bool in_whitespace; std::shared_ptr wordOpe; std::vector> capture_scope_stack; const size_t def_count; const bool enablePackratParsing; std::vector cache_registered; std::vector cache_success; std::map, std::tuple> cache_values; std::function tracer; Context( const char* a_path, const char* a_s, size_t a_l, size_t a_def_count, std::shared_ptr a_whitespaceOpe, std::shared_ptr a_wordOpe, bool a_enablePackratParsing, Tracer a_tracer) : path(a_path) , s(a_s) , l(a_l) , error_pos(nullptr) , message_pos(nullptr) , value_stack_size(0) , nest_level(0) , in_token(false) , whitespaceOpe(a_whitespaceOpe) , in_whitespace(false) , wordOpe(a_wordOpe) , def_count(a_def_count) , enablePackratParsing(a_enablePackratParsing) , cache_registered(enablePackratParsing ? def_count * (l + 1) : 0) , cache_success(enablePackratParsing ? def_count * (l + 1) : 0) , tracer(a_tracer) { args_stack.resize(1); capture_scope_stack.resize(1); } template void packrat(const char* a_s, size_t def_id, size_t& len, any& val, T fn) { if (!enablePackratParsing) { fn(val); return; } auto col = a_s - s; auto idx = def_count * static_cast(col) + def_id; if (cache_registered[idx]) { if (cache_success[idx]) { auto key = std::make_pair(col, def_id); std::tie(len, val) = cache_values[key]; return; } else { len = static_cast(-1); return; } } else { fn(val); cache_registered[idx] = true; cache_success[idx] = success(len); if (success(len)) { auto key = std::make_pair(col, def_id); cache_values[key] = std::make_pair(len, val); } return; } } SemanticValues& push() { assert(value_stack_size <= value_stack.size()); if (value_stack_size == value_stack.size()) { value_stack.emplace_back(std::make_shared()); } auto& sv = *value_stack[value_stack_size++]; if (!sv.empty()) { sv.clear(); } sv.path = path; sv.ss = s; sv.s_ = nullptr; sv.n_ = 0; sv.tokens.clear(); return sv; } void pop() { value_stack_size--; } void push_args(const std::vector>& args) { args_stack.push_back(args); } void pop_args() { args_stack.pop_back(); } const std::vector>& top_args() const { return args_stack[args_stack.size() - 1]; } void push_capture_scope() { capture_scope_stack.resize(capture_scope_stack.size() + 1); } void pop_capture_scope() { capture_scope_stack.pop_back(); } void shift_capture_values() { assert(capture_scope_stack.size() >= 2); auto it = capture_scope_stack.rbegin(); auto it_prev = it + 1; for (const auto& kv: *it) { (*it_prev)[kv.first] = kv.second; } } void set_error_pos(const char* a_s) { if (error_pos < a_s) error_pos = a_s; } void trace(const char* name, const char* a_s, size_t n, SemanticValues& sv, any& dt) const { if (tracer) tracer(name, a_s, n, sv, *this, dt); } }; /* * Parser operators */ class Ope { public: struct Visitor; virtual ~Ope() {} virtual size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const = 0; virtual void accept(Visitor& v) = 0; }; class Sequence : public Ope { public: Sequence(const Sequence& rhs) : opes_(rhs.opes_) {} #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) { opes_ = std::vector>{ static_cast>(args)... }; } #else template Sequence(const Args& ...args) : opes_{ static_cast>(args)... } {} #endif Sequence(const std::vector>& opes) : opes_(opes) {} Sequence(std::vector>&& opes) : opes_(opes) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("Sequence", s, n, sv, dt); size_t i = 0; for (const auto& ope : opes_) { c.nest_level++; auto se = make_scope_exit([&]() { c.nest_level--; }); const auto& rule = *ope; auto len = rule.parse(s + i, n - i, sv, c, dt); if (fail(len)) { return static_cast(-1); } i += len; } return i; } void accept(Visitor& v) override; std::vector> opes_; }; 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) { opes_ = std::vector>{ static_cast>(args)... }; } #else template PrioritizedChoice(const Args& ...args) : opes_{ static_cast>(args)... } {} #endif PrioritizedChoice(const std::vector>& opes) : opes_(opes) {} PrioritizedChoice(std::vector>&& opes) : opes_(opes) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("PrioritizedChoice", s, n, sv, dt); size_t id = 0; for (const auto& ope : opes_) { c.nest_level++; auto& chldsv = c.push(); c.push_capture_scope(); auto se = make_scope_exit([&]() { c.nest_level--; c.pop(); c.pop_capture_scope(); }); const auto& rule = *ope; auto len = rule.parse(s, n, chldsv, c, dt); if (success(len)) { if (!chldsv.empty()) { sv.insert(sv.end(), chldsv.begin(), chldsv.end()); } sv.s_ = chldsv.c_str(); sv.n_ = chldsv.length(); sv.choice_ = id; sv.tokens.insert(sv.tokens.end(), chldsv.tokens.begin(), chldsv.tokens.end()); c.shift_capture_values(); return len; } id++; } return static_cast(-1); } void accept(Visitor& v) override; size_t size() const { return opes_.size(); } std::vector> opes_; }; class ZeroOrMore : public Ope { public: ZeroOrMore(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("ZeroOrMore", s, n, sv, dt); auto save_error_pos = c.error_pos; size_t i = 0; while (n - i > 0) { c.nest_level++; c.push_capture_scope(); auto se = make_scope_exit([&]() { c.nest_level--; c.pop_capture_scope(); }); auto save_sv_size = sv.size(); auto save_tok_size = sv.tokens.size(); const auto& rule = *ope_; auto len = rule.parse(s + i, n - i, sv, c, dt); if (success(len)) { c.shift_capture_values(); } else { if (sv.size() != save_sv_size) { sv.erase(sv.begin() + static_cast(save_sv_size)); } if (sv.tokens.size() != save_tok_size) { sv.tokens.erase(sv.tokens.begin() + static_cast(save_tok_size)); } c.error_pos = save_error_pos; break; } i += len; } return i; } void accept(Visitor& v) override; std::shared_ptr ope_; }; class OneOrMore : public Ope { public: OneOrMore(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("OneOrMore", s, n, sv, dt); size_t len = 0; { c.nest_level++; c.push_capture_scope(); auto se = make_scope_exit([&]() { c.nest_level--; c.pop_capture_scope(); }); const auto& rule = *ope_; len = rule.parse(s, n, sv, c, dt); if (success(len)) { c.shift_capture_values(); } else { return static_cast(-1); } } auto save_error_pos = c.error_pos; auto i = len; while (n - i > 0) { c.nest_level++; c.push_capture_scope(); auto se = make_scope_exit([&]() { c.nest_level--; c.pop_capture_scope(); }); auto save_sv_size = sv.size(); auto save_tok_size = sv.tokens.size(); const auto& rule = *ope_; len = rule.parse(s + i, n - i, sv, c, dt); if (success(len)) { c.shift_capture_values(); } else { if (sv.size() != save_sv_size) { sv.erase(sv.begin() + static_cast(save_sv_size)); } if (sv.tokens.size() != save_tok_size) { sv.tokens.erase(sv.tokens.begin() + static_cast(save_tok_size)); } c.error_pos = save_error_pos; break; } i += len; } return i; } void accept(Visitor& v) override; std::shared_ptr ope_; }; class Option : public Ope { public: Option(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("Option", s, n, sv, dt); auto save_error_pos = c.error_pos; c.nest_level++; auto save_sv_size = sv.size(); auto save_tok_size = sv.tokens.size(); c.push_capture_scope(); auto se = make_scope_exit([&]() { c.nest_level--; c.pop_capture_scope(); }); const auto& rule = *ope_; auto len = rule.parse(s, n, sv, c, dt); if (success(len)) { c.shift_capture_values(); return len; } else { if (sv.size() != save_sv_size) { sv.erase(sv.begin() + static_cast(save_sv_size)); } if (sv.tokens.size() != save_tok_size) { sv.tokens.erase(sv.tokens.begin() + static_cast(save_tok_size)); } c.error_pos = save_error_pos; return 0; } } void accept(Visitor& v) override; std::shared_ptr ope_; }; class AndPredicate : public Ope { public: AndPredicate(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("AndPredicate", s, n, sv, dt); c.nest_level++; auto& chldsv = c.push(); c.push_capture_scope(); auto se = make_scope_exit([&]() { c.nest_level--; c.pop(); c.pop_capture_scope(); }); const auto& rule = *ope_; auto len = rule.parse(s, n, chldsv, c, dt); if (success(len)) { return 0; } else { return static_cast(-1); } } void accept(Visitor& v) override; std::shared_ptr ope_; }; class NotPredicate : public Ope { public: NotPredicate(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("NotPredicate", s, n, sv, dt); auto save_error_pos = c.error_pos; c.nest_level++; auto& chldsv = c.push(); c.push_capture_scope(); auto se = make_scope_exit([&]() { c.nest_level--; c.pop(); c.pop_capture_scope(); }); const auto& rule = *ope_; auto len = rule.parse(s, n, chldsv, c, dt); if (success(len)) { c.set_error_pos(s); return static_cast(-1); } else { c.error_pos = save_error_pos; return 0; } } void accept(Visitor& v) override; std::shared_ptr ope_; }; class LiteralString : public Ope , public std::enable_shared_from_this { public: LiteralString(const std::string& s) : lit_(s) , init_is_word_(false) , is_word_(false) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override; void accept(Visitor& v) override; std::string lit_; mutable bool init_is_word_; mutable bool is_word_; }; class CharacterClass : public Ope , public std::enable_shared_from_this { public: CharacterClass(const std::string& chars) : chars_(chars) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("CharacterClass", s, n, sv, dt); // TODO: UTF8 support if (n < 1) { c.set_error_pos(s); return static_cast(-1); } 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 1; } i += 3; } else { if (chars_[i] == ch) { return 1; } i += 1; } } c.set_error_pos(s); return static_cast(-1); } void accept(Visitor& v) override; std::string chars_; }; class Character : public Ope , public std::enable_shared_from_this { public: Character(char ch) : ch_(ch) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("Character", s, n, sv, dt); // TODO: UTF8 support if (n < 1 || s[0] != ch_) { c.set_error_pos(s); return static_cast(-1); } return 1; } void accept(Visitor& v) override; char ch_; }; class AnyCharacter : public Ope , public std::enable_shared_from_this { public: size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.trace("AnyCharacter", s, n, sv, dt); // TODO: UTF8 support if (n < 1) { c.set_error_pos(s); return static_cast(-1); } return 1; } void accept(Visitor& v) override; }; class CaptureScope : public Ope { public: CaptureScope(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { c.push_capture_scope(); auto se = make_scope_exit([&]() { c.pop_capture_scope(); }); const auto& rule = *ope_; auto len = rule.parse(s, n, sv, c, dt); return len; } void accept(Visitor& v) override; std::shared_ptr ope_; }; class Capture : public Ope { public: typedef std::function MatchAction; Capture(const std::shared_ptr& ope, MatchAction ma) : ope_(ope), match_action_(ma) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { const auto& rule = *ope_; auto len = rule.parse(s, n, sv, c, dt); if (success(len) && match_action_) { match_action_(s, len, c); } return len; } void accept(Visitor& v) override; std::shared_ptr ope_; MatchAction match_action_; }; class TokenBoundary : public Ope { public: TokenBoundary(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override; void accept(Visitor& v) override; std::shared_ptr ope_; }; class Ignore : public Ope { public: Ignore(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& /*sv*/, Context& c, any& dt) const override { const auto& rule = *ope_; auto& chldsv = c.push(); auto se = make_scope_exit([&]() { c.pop(); }); return rule.parse(s, n, chldsv, c, dt); } void accept(Visitor& v) override; std::shared_ptr ope_; }; typedef std::function Parser; class WeakHolder : public Ope { public: WeakHolder(const std::shared_ptr& ope) : weak_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { auto ope = weak_.lock(); assert(ope); const auto& rule = *ope; return rule.parse(s, n, sv, c, dt); } void accept(Visitor& v) override; std::weak_ptr weak_; }; class Holder : public Ope { public: Holder(Definition* outer) : outer_(outer) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override; void accept(Visitor& v) override; any reduce(const SemanticValues& sv, any& dt) const; std::shared_ptr ope_; Definition* outer_; friend class Definition; }; typedef std::unordered_map Grammar; class Reference : public Ope , public std::enable_shared_from_this { public: Reference( const Grammar& grammar, const std::string& name, const char* s, bool is_macro, const std::vector>& args) : grammar_(grammar) , name_(name) , s_(s) , is_macro_(is_macro) , args_(args) , rule_(nullptr) , iarg_(0) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override; void accept(Visitor& v) override; std::shared_ptr get_core_operator() const; const Grammar& grammar_; const std::string name_; const char* s_; const bool is_macro_; const std::vector> args_; Definition* rule_; size_t iarg_; }; class Whitespace : public Ope { public: Whitespace(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { if (c.in_whitespace) { return 0; } c.in_whitespace = true; auto se = make_scope_exit([&]() { c.in_whitespace = false; }); const auto& rule = *ope_; return rule.parse(s, n, sv, c, dt); } void accept(Visitor& v) override; std::shared_ptr ope_; }; class BackReference : public Ope { public: BackReference(const std::string& name) : name_(name) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override; void accept(Visitor& v) override; std::string name_; }; /* * Factories */ template 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)...); } inline std::shared_ptr zom(const std::shared_ptr& ope) { return std::make_shared(ope); } inline std::shared_ptr oom(const std::shared_ptr& ope) { return std::make_shared(ope); } inline std::shared_ptr opt(const std::shared_ptr& ope) { return std::make_shared