我想解析键值对,将字符串映射到字符串。既然我想支持右侧的{ ... }
块,我想出一个简单的语法来开始
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/std_pair.hpp>
namespace grammar::map
{
using namespace boost::spirit::x3;
auto expression = rule<class expression, std::pair<std::string, std::string>>{"expression"};
auto lhs = *(~char_('='));
auto rest = *(~char_(';'));
auto block = '{' >> *expression >> '}';
auto expression_def = lhs >> '=' >> (block | rest) >> ';';
BOOST_SPIRIT_DEFINE(expression)
}
但它无法组合编译,除非我将表达式的属性更改为std::string
。
//! Transform a string into a key-value map of strings.
template <class M, class R>
requires InputRange<R>() && _ContainerLike<M>
&& Same<value_type_t<M>, std::pair<const std::string, std::string>>()
// && Assignable<std::pair<std::string, std::string>, value_type_t<M>>()
M parse(R&& range)
{
auto begin = rng::begin(range);
auto end = rng::end(range);
auto map = M{};
auto ret = x3::phrase_parse(begin, end, *grammar::map::expression, x3::space, map);
if (!ret)
throw std::runtime_error{"parse error"};
return map;
}
我收到错误
boost/spirit/home/x3/support/traits/move_to.hpp:62:18: error: cannot convert ‘std::remove_reference<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&>::type {aka std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >}’ to ‘char’ in assignment
dest = std::move(src);
位于
boost/spirit/home/x3/support/traits/move_to.hpp: In instantiation of ‘void boost::spirit::x3::traits::detail::move_to_plain(Source&&, Dest&, mpl_::false_) [with Source = std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >; Dest = char; mpl_::false_ = mpl_::bool_<false>]’:
如果尝试以下表达式
,也会发生同样的事情auto pair = std::pair<std::string, std::string>{};
auto ret = x3::phrase_parse(begin, end, grammar::map::expression, x3::space, map);
我将在几天后来到它,但无法找到如何正确地做到这一点。我感谢任何帮助......:^)
使用boost-1.60 {-62}和gcc 6.1.1,6.2以及更近期的主干版本进行测试。
答案 0 :(得分:2)
您的问题是,您已定义expression
属性为pair<string,string>
,但lhs >> '=' >> (block|rest) >> ';'
的合成属性为synt_attr=tuple<string,variant<vector<synt_attr>,string>>
,基本上为synt_attr=pair<string,variant<map_of_value_type_synt_attr,string>>
。因此,根据您想要的结果,您至少有两个选项:
将合成属性更改为pair<string,string>
。使用x3::raw
指令(running on WandBox):
auto expression_def = lhs >> '=' >> (raw[block] | rest) >> ';';
更改expression
的定义,使其属性与合成属性兼容。这需要使用递归变体,并且因为您需要创建访问者(running on WandBox),因此需要访问解析地图中的数据的方式变得复杂。
//A value is either a `string` or a `map<string,Value>`
using Value = boost::make_recursive_variant<std::string,std::map<std::string,boost::recursive_variant_>>::type;
...
struct printer : boost::static_visitor<void>
{
printer(int indent) :indent(indent) {}
void operator()(const std::string& val) const
{
std::cout << std::string(indent, ' ') << val << std::endl;
}
void operator()(const std::map<std::string,Value>& val) const
{
for (const auto& pair : val)
{
std::cout << std::string(indent, ' ') << pair.first << ':' << std::endl;
boost::apply_visitor(printer(indent + 4), pair.second);
std::cout << std::string(indent, ' ') << std::endl;
}
}
int indent;
};
void print_map(const Value& val)
{
boost::apply_visitor(printer(0), val);
}