【问题标题】:Capturing string until end of line with Boost.Spirit.Qi使用 Boost.Spirit.Qi 捕获字符串直到行尾
【发布时间】:2021-09-30 03:49:16
【问题描述】:

我正在尝试编写一个自定义结构来捕获字符串,直到 EOL 或 EOS 作为更大语法的一部分,但我无法编译它。我关注了tutorial code,但我无法在下面的 sn-p 中找出错误。

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>

#include <string>
#include <cassert>

namespace qi = boost::spirit::qi;

namespace project {

struct RawValue {
    std::string str;
};

}

BOOST_FUSION_ADAPT_STRUCT(project::RawValue, str)

namespace project::parser {

struct RawValueParser : qi::grammar<std::string::const_iterator, RawValue(), qi::space_type> {
  RawValueParser() : RawValueParser::base_type(expr) {
    using qi::blank;
    using qi::char_;
    using qi::eol;
    using qi::lexeme;

    expr %= lexeme[*(char_ - eol) >> (char_ - blank)];
  }

  qi::rule<iterator_type, RawValue(), skipper_type> expr;
};

}

int main() {
  project::parser::RawValueParser expr;
  project::RawValue result;
  std::string s1 = "test1";
  auto iter = s1.cbegin();
  auto end = s1.cend();
  assert(qi::phrase_parse(iter, end, expr, qi::space, result));
  return 0;
}

https://wandbox.org/permlink/PjaaYwO0Qz18998y

这应该是一个相当简单的例子。我做错了什么?

【问题讨论】:

    标签: c++ boost c++17 boost-spirit boost-spirit-qi


    【解决方案1】:

    编译错误源自这里:

    test.cpp|21 col 58| required from here
    /home/sehe/custom/spirit/include/boost/spirit/home/qi/nonterminal/grammar.hpp|77 col 13| error: static assertion failed: incompatible_start_rule
    ||    77 |             BOOST_SPIRIT_ASSERT_MSG(
    ||       |             ^~~~~~~~~~~~~~~~~~~~~~~
    

    如果您前往指定位置(另请参阅How do I grok boost spirit compiler errors):

    // If you see the assertion below failing then the start rule
    // passed to the constructor of the grammar is not compatible with
    // the grammar (i.e. it uses different template parameters).
    BOOST_SPIRIT_ASSERT_MSG(
        (is_same<start_type, rule<Iterator_, T1_, T2_, T3_, T4_> >::value)
      , incompatible_start_rule, (rule<Iterator_, T1_, T2_, T3_, T4_>));
    

    那是你的问题。语法是&lt;It, RawValue(), qi::space_type&gt;,但起始规则是&lt;iterator_type, RawValue(), skipper_type&gt;,其中

        static_assert(std::is_same_v<It, iterator_type>);
        static_assert(std::is_same_v<qi::space_type, skipper_type>);
        qi::space_type _y = skipper_type{};
    

    显示第二个断言失败。第三行导致更详细的诊断:Live

    test.cpp|33 col 29| error: could not convert ‘boost::spirit::qi::grammar<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, project::RawValue(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0> >::skipper_type{}’ from ‘boost::spirit::qi::grammar<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, project::RawValue(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0> >::skipper_type’ {aka ‘boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >’} to ‘boost::spirit::standard::space_type’ {aka ‘boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::te
    ||    33 |         qi::space_type _y = skipper_type{};
    ||       |                             ^~~~~~~~~~~~~~
    ||       |                             |
    ||       |                             boost::spirit::qi::grammar<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, project::RawValue(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0> >::skipper_type {aka boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >}
    

    您可以将整个事情分开,但只要说您认为skipper_type 等于第三个模板参数的假设是错误的就足够了。

    只需拼出您期望的类型:Live

    qi::rule<It, RawValue(), qi::space_type> expr;
    

    附注

    1. lexeme 禁用船长。考虑到简化整个事情:Live(另见Boost spirit skipper issues

    2. operator %= 没有语义动作就没有意义

    3. expr 似乎用词不当

    4. 否定字符类比减法解析器更有效;你的意思是(char_ - blank)eol 更有意义吗?

    5. 现在不接受输入结尾而不是 eol。也许你应该允许它。我会这样写

      start = *~qi::char_("\n\r") >> (eol | eoi);
      

    简化列表

    Live On Coliru

    #include <boost/fusion/adapted/struct.hpp>
    #include <boost/spirit/include/qi.hpp>
    
    #include <iomanip>
    
    namespace qi = boost::spirit::qi;
    using It = std::string::const_iterator;
    
    struct RawValue { std::string str; };
    
    BOOST_FUSION_ADAPT_STRUCT(RawValue, str)
    
    struct RawValueParser : qi::grammar<It, RawValue()> {
        RawValueParser() : RawValueParser::base_type(start)
        {
            using namespace qi;
            start = *~qi::char_("\n\r") >> (eol | eoi);
        }
    
      private:
        qi::rule<It, RawValue()> start;
    };
    
    int main() {
        RawValueParser expr;
    
        for (std::string const s : {
                 "test1",
                 " test2\tbla   \n",
             }) {
    
            RawValue result;
            std::cout
                << std::boolalpha
                //<< qi::phrase_parse(begin(s), end(s), expr, qi::space, result)
                << qi::parse(begin(s), end(s), expr, result) << " -> "
                << std::quoted(result.str) << "\n";
        }
    }
    

    打印

    true -> "test1"
    true -> " test2 bla   "
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-23
    • 2014-07-06
    • 1970-01-01
    • 2014-09-21
    • 2017-03-19
    相关资源
    最近更新 更多