Boost.Spirit Qi:同一个语法的不同入口点?
Boost.Spirit Qi: different entry points to the same grammar?
我有一个递归语法,想从它的不同规则开始解析。是否可以不多次重写相同的语法?
示例:我有 json 解析器:
template <typename It, typename Skipper = qi::space_type>
struct grammar : qi::grammar<It, value (), Skipper>
{
grammar () : grammar::base_type (value_)
{
using namespace qi;
static auto const null_ = proto::deep_copy ("null" >> qi::attr (null {}));
static auto const bool_ = proto::deep_copy (
"true" >> qi::attr (true) | "false" >> qi::attr (false));
static auto const text_ = proto::deep_copy (
'"' >> qi::raw [*('\' >> qi::char_ | ~qi::char_('"'))] >> '"');
value_ = null_ | bool_ | text_ | double_ | object_ | array_;
member_ = text_ >> ':' >> value_;
object_ = '{' >> -(member_ % ',') >> '}';
array_ = '[' >> -(value_ % ',') >> ']';
BOOST_SPIRIT_DEBUG_NODES((value_)(member_)(object_)(array_))
}
private:
qi::rule<It, json:: value (), Skipper> value_;
qi::rule<It, json::member (), Skipper> member_;
qi::rule<It, json::object (), Skipper> object_;
qi::rule<It, json:: array (), Skipper> array_;
};
通常我需要将输入解析为json value,但有时我需要将其解析为json array 或 json 对象 。我是否可以在不一遍又一遍地重写相同语法的情况下做到这一点,这些语法之间的唯一区别是入口点?
我找到的最接近的解决方案是将语法拆分为基础和派生 类,并在派生 类 中使用不同的开始规则。它并没有太多重复源代码,但看起来仍然是超重解决方案。
template <typename It, typename Data, typename Skipper = qi::space_type>
struct base : qi::grammar<It, Data (), Skipper>
{
using jbase_type = base;
template <typename Member>
base (Member& member) : base::base_type (member)
{
using namespace qi;
using namespace Json;
value_ = null_ | bool_ | text_ | double_ | object_ | array_;
member_ = text_ >> ':' >> value_;
object_ = '{' >> -(member_ % ',') >> '}';
array_ = '[' >> -(value_ % ',') >> ']';
BOOST_SPIRIT_DEBUG_NODES((value_)(member_)(object_)(array_))
}
protected:
escaped_string_grammar<It> text_;
qi::rule<It, Json:: Value (), Skipper> value_;
qi::rule<It, Json::Member (), Skipper> member_;
qi::rule<It, Json::Object (), Skipper> object_;
qi::rule<It, Json:: Array (), Skipper> array_;
};
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <typename It, typename Skipper = qi::space_type>
struct value : base<It, Json::Value, Skipper>
{
value () : value::jbase_type (value::jbase_type::value_) {}
};
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <typename It, typename Skipper = qi::space_type>
struct array : base<It, Json::Array, Skipper>
{
array () : array::jbase_type (array::jbase_type::array_) {}
};
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <typename It, typename Skipper = qi::space_type>
struct object : base<It, Json::Object, Skipper>
{
object () : object::jbase_type (object::jbase_type::object_) {}
};
我有一个递归语法,想从它的不同规则开始解析。是否可以不多次重写相同的语法?
示例:我有 json 解析器:
template <typename It, typename Skipper = qi::space_type>
struct grammar : qi::grammar<It, value (), Skipper>
{
grammar () : grammar::base_type (value_)
{
using namespace qi;
static auto const null_ = proto::deep_copy ("null" >> qi::attr (null {}));
static auto const bool_ = proto::deep_copy (
"true" >> qi::attr (true) | "false" >> qi::attr (false));
static auto const text_ = proto::deep_copy (
'"' >> qi::raw [*('\' >> qi::char_ | ~qi::char_('"'))] >> '"');
value_ = null_ | bool_ | text_ | double_ | object_ | array_;
member_ = text_ >> ':' >> value_;
object_ = '{' >> -(member_ % ',') >> '}';
array_ = '[' >> -(value_ % ',') >> ']';
BOOST_SPIRIT_DEBUG_NODES((value_)(member_)(object_)(array_))
}
private:
qi::rule<It, json:: value (), Skipper> value_;
qi::rule<It, json::member (), Skipper> member_;
qi::rule<It, json::object (), Skipper> object_;
qi::rule<It, json:: array (), Skipper> array_;
};
通常我需要将输入解析为json value,但有时我需要将其解析为json array 或 json 对象 。我是否可以在不一遍又一遍地重写相同语法的情况下做到这一点,这些语法之间的唯一区别是入口点?
我找到的最接近的解决方案是将语法拆分为基础和派生 类,并在派生 类 中使用不同的开始规则。它并没有太多重复源代码,但看起来仍然是超重解决方案。
template <typename It, typename Data, typename Skipper = qi::space_type>
struct base : qi::grammar<It, Data (), Skipper>
{
using jbase_type = base;
template <typename Member>
base (Member& member) : base::base_type (member)
{
using namespace qi;
using namespace Json;
value_ = null_ | bool_ | text_ | double_ | object_ | array_;
member_ = text_ >> ':' >> value_;
object_ = '{' >> -(member_ % ',') >> '}';
array_ = '[' >> -(value_ % ',') >> ']';
BOOST_SPIRIT_DEBUG_NODES((value_)(member_)(object_)(array_))
}
protected:
escaped_string_grammar<It> text_;
qi::rule<It, Json:: Value (), Skipper> value_;
qi::rule<It, Json::Member (), Skipper> member_;
qi::rule<It, Json::Object (), Skipper> object_;
qi::rule<It, Json:: Array (), Skipper> array_;
};
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <typename It, typename Skipper = qi::space_type>
struct value : base<It, Json::Value, Skipper>
{
value () : value::jbase_type (value::jbase_type::value_) {}
};
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <typename It, typename Skipper = qi::space_type>
struct array : base<It, Json::Array, Skipper>
{
array () : array::jbase_type (array::jbase_type::array_) {}
};
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <typename It, typename Skipper = qi::space_type>
struct object : base<It, Json::Object, Skipper>
{
object () : object::jbase_type (object::jbase_type::object_) {}
};