ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 带有boost变量递归包装器的字符串解析器

2019-09-02 02:07:01  阅读:186  来源: 互联网

标签: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;
}

部分错误消息:

/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> > &)’

提前致谢.

解决方法:

我建议问题是属性兼容性.与the documentation相反,ascii :: string解析器似乎暴露了迭代器范围而不是字符串.

name = string("no way");

没问题,因为ascii :: string公开的属性可以毫不费力地强制进入规则的属性类型.

但是,brac规则的属性类型是ast_branch,它只是一个变体,其中包含一个可能包含的类型.因此,ast_branch类型有几个构造函数,并且Spirit不清楚哪个适合这种特定的转换.

有几种方法(除了你已经展示的方法):

>使用attr_cast

brac = qi::attr_cast( string("no way") );

>使用as_string

brac = qi::as_string[ string("no way") ];

>使用自定义点

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);
            }
        };
}}}

这些中的每一个都具有相同的效果:使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;
}

标签:c,parsing,boost-spirit,boost-variant
来源: https://codeday.me/bug/20190902/1787413.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有