// // peglib.h // // Copyright (c) 2015 Yuji Hirose. All rights reserved. // MIT License // #ifndef _CPPEXPATLIB_PEGLIB_H_ #define _CPPEXPATLIB_PEGLIB_H_ #include #include #include #include #include #include #include #include #include namespace peglib { void* enabler; /*----------------------------------------------------------------------------- * 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; } template Any& operator=(const T& value) { if (content_) { delete content_; } content_ = new holder(value); return *this; } ~Any() { delete content_; } bool is_undefined() const { return content_ == nullptr; } template < typename T, typename std::enable_if::value>::type*& = enabler > T& get() { assert(content_); return dynamic_cast*>(content_)->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_); return dynamic_cast*>(content_)->value_; } template < typename T, typename std::enable_if::value>::type*& = enabler > const Any& get() const { return *this; } // TODO: Add more implecit cast operators operator bool() const { return get(); } operator char() const { return get(); } operator wchar_t() const { return get(); } operator char16_t() const { return get(); } operator char32_t() const { return get(); } operator unsigned char() const { return get(); } operator int() const { return get(); } operator unsigned int() const { return get(); } operator short() const { return get(); } operator unsigned short() const { return get(); } operator long() const { return get(); } operator unsigned long() const { return get(); } operator long long() const { return get(); } operator unsigned long long() const { return get(); } operator float() const { return get(); } operator double() const { return get(); } operator const std::string&() const { return get(); } 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_; }; /*----------------------------------------------------------------------------- * PEG *---------------------------------------------------------------------------*/ /* * Semantic values */ struct Values { std::vector names; std::vector values; }; /* * Semantic action */ 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)...)); } 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(); } class Action { public: Action() = default; Action(const Action& rhs) : fn_(rhs.fn_) {} //Action(Action&& rhs) : fn_(std::move(rhs.fn_)) {} template ::value && !std::is_null_pointer::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_null_pointer::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) {} 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 { 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) { return call(fn_, s, l, v, n); } std::function& v, const std::vector& n)> fn_; }; template struct TypeAdaptor_s_l_v { 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) { return call(fn_, s, l, v); } 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) { return call(fn_, s, l); } std::function fn_; }; 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) { return call(fn_, v, n); } 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) { return call(fn_, v); } 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) { return call(fn_); } std::function fn_; }; 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) { return TypeAdaptor(fn); } template 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) { return TypeAdaptor_s_l_v(fn); } template Fty make_adaptor(F fn, R(*mf)(const char*, size_t, const std::vector& v)) { return TypeAdaptor_s_l_v(fn); } template Fty make_adaptor(F fn, R (F::*mf)(const char*, size_t) const) { return TypeAdaptor_s_l(fn); } template Fty make_adaptor(F fn, R (*mf)(const char*, size_t)) { return TypeAdaptor_s_l(fn); } template 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)) { return TypeAdaptor_v_n(fn); } template 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)) { return TypeAdaptor_v(fn); } template Fty make_adaptor(F fn, R (F::*mf)() const) { return TypeAdaptor_empty(fn); } template Fty make_adaptor(F fn, R (*mf)()) { return TypeAdaptor_empty(fn); } 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() : actions(1) , holder_(std::make_shared(this)) {} Definition(const Definition& rhs) : name(rhs.name) , actions(1) , holder_(rhs.holder_) { holder_->outer_ = this; } Definition(Definition&& rhs) : name(std::move(rhs.name)) , actions(1) , holder_(std::move(rhs.holder_)) { holder_->outer_ = this; } Definition(const std::shared_ptr& rule) : actions(1) , holder_(std::make_shared(this)) { holder_->rule_ = rule; } operator std::shared_ptr() { return std::make_shared(holder_); } 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 { Values v; auto m = holder_->parse(s, l, v); auto ret = m.ret && m.len == l; if (ret && !v.values.empty() && !v.values.front().is_undefined()) { val = v.values[0].get(); } return ret; } template bool parse(const char* s, T& val) const { return parse(s, strlen(s), val); } bool parse(const char* s, size_t l) const { Values v; auto m = holder_->parse(s, l, v); return m.ret && m.len == l; } bool parse(const char* s) const { return parse(s, strlen(s)); } Definition& operator=(Action ac) { assert(!actions.empty()); actions[0] = ac; return *this; } 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 Holder : public Ope { public: Holder(Definition* outer) : outer_(outer) {} Match parse_core(const char* s, size_t l, Values& v) const { if (!rule_) { throw std::logic_error("Uninitialized definition rule was used..."); } Values chldsv; auto m = rule_->parse(s, l, chldsv); if (m.ret) { 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; 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(); } else { return v.values.front(); } } std::shared_ptr rule_; Definition* outer_; }; Definition& operator=(const Definition& rhs); Definition& operator=(Definition&& rhs); std::shared_ptr holder_; }; class DefinitionReference : public Ope { public: DefinitionReference( const std::map& grammar, const std::string& name) : grammar_(grammar) , name_(name) {} 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)...); } template std::shared_ptr cho(Args&& ...args) { return std::make_shared(static_cast>(args)...); } 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) { return std::make_shared(rule); } inline std::shared_ptr opt(const std::shared_ptr& rule) { return std::make_shared