[英]Can spirit X3 work with BOOST_FUSION_ADAPT_ADT?
Change my codes from QI to X3, and get some compile error with BOOST_FUSION_ADAPT_ADT
. 将我的代码从QI更改为X3,并使用
BOOST_FUSION_ADAPT_ADT
获得一些编译错误。 I tried boost 1.64 and 1.67, neither of them work. 我试过提升1.64和1.67,它们都不起作用。 I modified the spirit X3 example
rexpr_min
, adding getter and setter to struct rexpr
, changing the BOOST_FUSION_ADAPT_STRUCT
to BOOST_FUSION_ADAPT_ADT
, and compile it fail, too. 我修改了精灵X3示例
rexpr_min
,将getter和setter添加到struct rexpr
,将BOOST_FUSION_ADAPT_STRUCT
更改为BOOST_FUSION_ADAPT_ADT
,并将其编译失败。
Enviroment: 环境:
ubuntu 16.04 ubuntu 16.04
G++ 5.4, with -std=c++17
flag G ++ 5.4,带
-std=c++17
标志
boost 1.67 提升1.67
Error message: 错误信息:
boost/spirit/home/x3/core/detail/parse_into_container.hpp:142:35: error: invalid initialization of non-const reference of type ‘boost::fusion::extension::adt_attribute_proxy<client::ast::rexpr, 0, false>&’ from an rvalue of type ‘boost::fusion::extension::deref_impl<boost::fusion::struct_iterator_tag>::apply<boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, client::ast::rexpr, 0> >::type {aka boost::fusion::extension::adt_attribute_proxy<client::ast::rexpr, 0, false>}’
return call_synthesize(parser, first, last, context, rcontext,
I guess the fusion::front(attr)
return a const reference, and the call_synthesize
want a non-const reference (at boost_1_64_0/boost/spirit/home/x3/core/detail/parse_into_container.hpp
, line 146). 我猜
fusion::front(attr)
返回一个const引用,而call_synthesize
想要一个非const引用(在boost_1_64_0/boost/spirit/home/x3/core/detail/parse_into_container.hpp
,第146行)。 But I don't know what to do. 但我不知道该怎么办。
I googled and find some regression of QI and they are patched in newest version. 我用谷歌搜索并找到QI的一些回归,并在最新版本中修补它们。 But there is no information with X3.
但X3没有任何信息。
The original code spirit X3 example rexpr_min
, And my modification: 原代码精灵X3示例
rexpr_min
,而我的修改:
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// A simple parser for X3 intended as a minimal starting point.
// 'rexpr' is a parser for a language resembling a minimal subset
// of json, but limited to a dictionary (composed of key=value pairs)
// where the value can itself be a string or a recursive dictionary.
//
// Example:
//
// {
// "color" = "blue"
// "size" = "29 cm."
// "position" = {
// "x" = "123"
// "y" = "456"
// }
// }
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_adt.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/io.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
///////////////////////////////////////////////////////////////////////////////
// Our AST
///////////////////////////////////////////////////////////////////////////////
namespace client { namespace ast
{
namespace fusion = boost::fusion;
namespace x3 = boost::spirit::x3;
struct rexpr;
struct rexpr_value : x3::variant<
std::string
, x3::forward_ast<rexpr>
>
{
using base_type::base_type;
using base_type::operator=;
};
typedef std::map<std::string, rexpr_value> rexpr_map;
typedef std::pair<std::string, rexpr_value> rexpr_key_value;
struct rexpr
{
rexpr_map i_entries;
const rexpr_map& entries() const { return i_entries; }
void entries(const rexpr_map& ent) { i_entries = ent; }
};
}}
// We need to tell fusion about our rexpr struct
// to make it a first-class fusion citizen
BOOST_FUSION_ADAPT_ADT(client::ast::rexpr,
(obj.entries(), obj.entries(val))
)
///////////////////////////////////////////////////////////////////////////////
// AST processing
///////////////////////////////////////////////////////////////////////////////
namespace client { namespace ast
{
///////////////////////////////////////////////////////////////////////////
// Print out the rexpr tree
///////////////////////////////////////////////////////////////////////////
int const tabsize = 4;
struct rexpr_printer
{
typedef void result_type;
rexpr_printer(int indent = 0)
: indent(indent) {}
void operator()(rexpr const& ast) const
{
std::cout << '{' << std::endl;
for (auto const& entry : ast.entries())
{
tab(indent+tabsize);
std::cout << '"' << entry.first << "\" = ";
boost::apply_visitor(rexpr_printer(indent+tabsize), entry.second);
}
tab(indent);
std::cout << '}' << std::endl;
}
void operator()(std::string const& text) const
{
std::cout << '"' << text << '"' << std::endl;
}
void tab(int spaces) const
{
for (int i = 0; i < spaces; ++i)
std::cout << ' ';
}
int indent;
};
}}
///////////////////////////////////////////////////////////////////////////////
// Our rexpr grammar
///////////////////////////////////////////////////////////////////////////////
namespace client { namespace parser
{
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
using x3::lit;
using x3::lexeme;
using ascii::char_;
using ascii::string;
x3::rule<class rexpr_value, ast::rexpr_value>
rexpr_value = "rexpr_value";
x3::rule<class rexpr, ast::rexpr>
rexpr = "rexpr";
x3::rule<class rexpr_key_value, ast::rexpr_key_value>
rexpr_key_value = "rexpr_key_value";
auto const quoted_string =
lexeme['"' >> *(char_ - '"') >> '"'];
auto const rexpr_value_def =
quoted_string | rexpr;
auto const rexpr_key_value_def =
quoted_string >> '=' >> rexpr_value;
auto const rexpr_def =
'{' >> *rexpr_key_value >> '}';
BOOST_SPIRIT_DEFINE(rexpr_value, rexpr, rexpr_key_value);
}}
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
char const* filename;
if (argc > 1)
{
filename = argv[1];
}
else
{
std::cerr << "Error: No input file provided." << std::endl;
return 1;
}
std::ifstream in(filename, std::ios_base::in);
if (!in)
{
std::cerr << "Error: Could not open input file: "
<< filename << std::endl;
return 1;
}
std::string storage; // We will read the contents here.
in.unsetf(std::ios::skipws); // No white space skipping!
std::copy(
std::istream_iterator<char>(in),
std::istream_iterator<char>(),
std::back_inserter(storage));
using client::parser::rexpr; // Our grammar
client::ast::rexpr ast; // Our tree
using boost::spirit::x3::ascii::space;
std::string::const_iterator iter = storage.begin();
std::string::const_iterator end = storage.end();
bool r = phrase_parse(iter, end, rexpr, space, ast);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "-------------------------\n";
client::ast::rexpr_printer printer;
printer(ast);
return 0;
}
else
{
std::string::const_iterator some = iter+30;
std::string context(iter, (some>end)?end:some);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << context << "...\"\n";
std::cout << "-------------------------\n";
return 1;
}
}
As I've been warning people before ¹ you're pushing limits right on the intersection of things that frequently break Spirit's gears: 正如我在 ¹ 之前一直在警告人们的那样,你会在经常打破精神齿轮的事物的交叉点上施加限制:
I won't spend much time on this because it's a rather old, boring, well-documented² and not essential to your question. 我不会花太多时间在这上面,因为它是一个相当陈旧,枯燥,记录良好的²,对你的问题不是必不可少的。
Let's side-step it by adding a dummy field: 让我们通过添加一个虚拟字段来支持它:
struct rexpr
{
rexpr_map i_entries;
const rexpr_map& entries() const { return i_entries; }
rexpr_map& entries() { return i_entries; }
void entries(const rexpr_map& ent) { i_entries = ent; }
int i_dummy;
int dummy() const { return i_dummy; }
void dummy(int i) { i_dummy = i; }
};
// ... later:
BOOST_FUSION_ADAPT_ADT(client::ast::rexpr,
(obj.entries(), obj.entries(val))
(obj.dummy(), obj.dummy(val))
)
// ... even later:
auto const rexpr_def =
'{' >> *rexpr_key_value >> '}' >> x3::attr(42);
The attribute-category machinery of Spirit detects the entries
property as a container attribute ( is_container<...>{}
evaluates to true
). Spirit的属性类别机制将
entries
属性检测为容器属性( is_container<...>{}
计算为true
)。
However the requisite container traits are not in place. 然而,必要的容器特征不到位。
What's more, because of the restrictive interface that ADT proxies grant, the property values can only replaced whole-sale, meaning that we can only implement a very suboptimal version of it: 更重要的是,由于ADT代理授予的限制性接口,属性值只能替换整个销售,这意味着我们只能实现非常不理想的版本:
namespace boost { namespace spirit { namespace x3 { namespace traits {
template <typename T, auto... Other>
struct container_value<boost::fusion::extension::adt_attribute_proxy<T, Other...> >
: container_value<typename boost::fusion::extension::adt_attribute_proxy<T, Other...>::type>
{ };
template <typename T, auto... Other>
struct push_back_container<boost::fusion::extension::adt_attribute_proxy<T, Other...> >
{
using underlying_type = typename boost::fusion::extension::adt_attribute_proxy<T, Other...>::type;
template <typename X, typename Y>
static bool call(X& proxy, Y&& v) {
auto u = proxy.get();
bool b = push_back_container<underlying_type>::call(u, std::forward<Y>(v));
proxy = u;
return b;
}
};
} } } }
You require the commits: 您需要提交:
commit ae78e1ec2431517a8b0580099aeba8f9122d8abb
Author: Nikita Kniazev <nok.raven@gmail.com>
Date: Thu Mar 15 17:33:36 2018 +0300
X3: sequence: Fixed reference to temporary bug
commit e7f31017ec7c0b5584d12ec1b718d8c415b26fa1
Author: Nikita Kniazev <nok.raven@gmail.com>
Date: Wed Mar 14 18:54:35 2018 +0300
Qi: Fixed ADT support by permutation and sequence_or operator
This is follow-up to 0f2b3c49ce55a41a7d22cc5533e0f4ba59e491ae
These are more recent than 1.67.0 and currently in the develop
branch. 这些比1.67.0更新,目前在
develop
分支中。 They (in part) fix an old issue: https://github.com/boostorg/spirit/pull/153#issuecomment-152879056 . 他们(部分)解决了一个老问题: https : //github.com/boostorg/spirit/pull/153#issuecomment-152879056 。 The current behaviour may also be impacted by commit
当前行为也可能受到提交的影响
commit a0df3c098ff4e42c0958796c4f47d4d72a20c164
Merge: f73b121 fac9dfa
Author: Nikita Kniazev <nok.raven@gmail.com>
Date: Thu Mar 1 13:44:27 2018 +0300
Merge pull request #370 from Kojoley/x3-pass-container-attribute-through-sequence
X3: Pass container attribute through sequence
It's hard to gauge whether the impact is positive or negative in this ... turbulent landscape. 在这个......动荡的景观中,很难判断这种影响是积极的还是消极的。
Suffice it to say that iff you 我只想说, 如果你
develop
) develop
) then I see the expected output: 然后我看到了预期的输出:
-------------------------
Parsing succeeded
-------------------------
{
"color" = "blue"
"position" = {
"x" = "123"
"y" = "456"
}
"size" = "29 cm."
}
(based on libs/spirit/example/x3/rexpr/rexpr_examples/a.rexpr
input). (基于
libs/spirit/example/x3/rexpr/rexpr_examples/a.rexpr
输入)。
I hope you don't think this is "fine". 我希望你不要认为这很“好”。 Please consider filing an issue at the mailing list/github.
请考虑在邮件列表/ github上提交问题。 Also take these into account:
还考虑到这些:
In the light of recent recurring issues revolving arround container-attributes, I think a change around boost 1.65.1 caused container attributes to regress across the board: 鉴于最近反复出现的容器属性周期性问题,我认为围绕boost 1.65.1的变化导致容器属性全面回归:
¹ not to mention my dislike for it in most cases: Using spirit to parse into classes? ¹在大多数情况下,更不用说我不喜欢它了: 用精神来解析课程?
² Spirit Qi attribute propagation issue with single-member struct , X3, what is attr_gen? ²SpiritQi 属性传播问题与单成员结构 , X3,什么是attr_gen? , boost::spirit::x3 attribute compatibility rules, intuition or code?
, boost :: spirit :: x3属性兼容性规则,直觉还是代码?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.