pdu*_*dug 4 c++ parsing boost-spirit boost-variant
下面的代码(改编自spirit qi mini_xml示例)无法编译.存在与brac具有递归属性的规则相关的错误boost::variant.
但是,所有注释掉的版本brac都会编译.
我非常好奇在这种情况下知道是什么让简单的字符串解析器如此特殊:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <string>
#include <vector>
namespace client
{
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct ast_node;
typedef boost::variant<
boost::recursive_wrapper<ast_node>,
std::string
> ast_branch;
struct ast_node
{
std::string text;
std::vector<ast_branch> children;
};
}
BOOST_FUSION_ADAPT_STRUCT(
client::ast_node,
(std::string, text)
(std::vector<client::ast_branch>, children)
)
namespace client
{
template <typename Iterator>
struct ast_node_grammar
: qi::grammar<Iterator, ast_branch(), ascii::space_type>
{
ast_node_grammar()
: ast_node_grammar::base_type(brac)
{
using qi::_1;
using qi::_val;
using ascii::char_;
using ascii::string;
name %= *char_;
brac %= string("no way") ;
// brac = string("works")[_val = _1] ;
// brac %= string("this") | string("works");
// brac %= name ; // works
// brac %= *char_ ; // works
}
qi::rule<Iterator, std::string()> name;
qi::rule<Iterator, ast_branch(), ascii::space_type> brac;
};
}
int main(int argc, char **argv)
{
typedef client::ast_node_grammar<std::string::const_iterator> ast_node_grammar;
ast_node_grammar gram;
client::ast_branch ast;
std::string text("dummy");
using boost::spirit::ascii::space;
std::string::const_iterator iter = text.begin();
std::string::const_iterator end = text.end();
bool r = phrase_parse(iter, end, gram, space, ast);
return r ? 0 : 1;
}
Run Code Online (Sandbox Code Playgroud)
部分错误消息:
/usr/include/boost/spirit/home/qi/detail/assign_to.hpp:38:17: error: No match for ‘boost::variant<
boost::recursive_wrapper<client::ast_node>, basic_string<char>
>::variant(
const __normal_iterator<const char *, basic_string<char> > &, const __normal_iterator<
const char *, basic_string<char> > &)’
Run Code Online (Sandbox Code Playgroud)
提前致谢.
我建议问题是属性兼容性.与文档相反,ascii :: string解析器似乎暴露了迭代器范围而不是字符串.
name = string("no way");
Run Code Online (Sandbox Code Playgroud)
没问题,因为ascii :: string公开的属性可以毫不费力地强制进入规则的属性类型.
但是,brac规则的属性类型是ast_branch,它只是一种可能包含类型的变体.因此,该ast_branch类型有几个构造函数,并且Spirit不清楚哪一个适合于这种特定的转换.
有几种方法(除了你已经展示的方法):
使用 attr_cast
brac = qi::attr_cast( string("no way") );
Run Code Online (Sandbox Code Playgroud)使用 as_string
brac = qi::as_string[ string("no way") ];
Run Code Online (Sandbox Code Playgroud)使用自定义点
namespace boost { namespace spirit { namespace traits {
template <typename It>
struct assign_to_attribute_from_iterators<client::ast_branch, It>
{
static void call(It const& f, It const& l, client::ast_branch& val)
{
val = std::string(f, l);
}
};
}}}
Run Code Online (Sandbox Code Playgroud)这些中的每一个都具有相同的效果:使Spirit实现要使用的属性转换.
这是一个完整的工作样本,显示所有三个:
// #define BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <string>
#include <vector>
namespace client
{
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct ast_node;
typedef boost::variant<
boost::recursive_wrapper<ast_node>,
std::string
> ast_branch;
struct ast_node
{
std::string text;
std::vector<ast_branch> children;
};
}
namespace boost { namespace spirit { namespace traits {
template <typename It>
struct assign_to_attribute_from_iterators<client::ast_branch, It>
{
static void call(It const& f, It const& l, client::ast_branch& val)
{
val = std::string(f, l);
}
};
}}}
BOOST_FUSION_ADAPT_STRUCT(
client::ast_node,
(std::string, text)
(std::vector<client::ast_branch>, children)
)
namespace client
{
template <typename Iterator>
struct ast_node_grammar : qi::grammar<Iterator, ast_branch(), ascii::space_type>
{
ast_node_grammar()
: ast_node_grammar::base_type(brac)
{
using qi::_1;
using qi::_val;
using ascii::char_;
using ascii::string;
name %= *char_;
brac = string("works");
brac = string("works")[_val = _1] ;
brac %= string("this") | string("works");
brac %= name ; // works
brac %= *char_ ; // works
brac = qi::as_string[ string("no way") ];
brac = qi::attr_cast( string("no way") );
}
qi::rule<Iterator, std::string()> name;
qi::rule<Iterator, ast_branch(), ascii::space_type> brac;
};
}
int main(int argc, char **argv)
{
typedef client::ast_node_grammar<std::string::const_iterator> ast_node_grammar;
ast_node_grammar gram;
client::ast_branch ast;
std::string text("dummy");
using boost::spirit::ascii::space;
std::string::const_iterator iter = text.begin();
std::string::const_iterator end = text.end();
bool r = phrase_parse(iter, end, gram, space, ast);
return r ? 0 : 1;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1347 次 |
| 最近记录: |