用凤凰绑定结构来提升精神规则 - 编译失败

时间:2015-10-13 19:30:33

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

我想解析以下字符串:id=1;entry1=[A,B,D];entry2=[bla,blubb];factor=[1,5]!

我的解析器:

struct Entry
{
  uint32_t id;
  std::vector< std::string > entry1;
  std::vector< std::string > entry2;

  bool useFactor;
  std::pair<int, int> factor;
};

BOOST_FUSION_ADAPT_STRUCT( Entry, id, entry1, entry2, useFactor, factor)

template<typename It>
struct testParser : qi::grammar<It, Entry()>
{
   testParser : testParser::base_type(start)
   {
     using namespace qi;
     id_ %= lit("id=") >> int_ ;
     entry1_ %= lit("entry1=") >> char_('[') >> +(char_ -char_(']') % ',') >> char_(']');
     entry2_ %= lit("entry1=") >> char_('[') >> +(char_ -char_(']') % ',') >> char_(']');
    factor %= lit("factor=") >> char_('[') >> int_ >> char_(',') >> int_ >> char_(']');

  start = id >> ';' >> entry1 >> ';' >> entry2 >> (( ';' >> factor[ phx::bind(&Entry::useFactor,_1) = true;] ) >> '!') | '!';

   qi::rule<It, Entry()> start;
   qi::rule<It, int()> id;
   qi::rule<It, std::vector<std::string>()> entry1_, entry2_;
   qi::rule<It, std::pair<int,int>()> factor;
}
};

我收到了极大的编译错误消息。我认为这是因为entry1和entry2规则(字符串插入的向量)

1 个答案:

答案 0 :(得分:2)

正如你可能在直播中看到的那样,我已经逐步修正了语法。

那里有很多“你喝醉了”的时刻,所以我不确定我能否在这里捕捉散文的基本步骤。无论如何,请 a look at the recorded stream¹

一些重要的注释(忽略随机错别字和明显混淆的代码):

  • 使用attr(v)简单地公开属性(在本例中为attr(true)
  • 使用lit('c')lit("abc")或仅'c'"abc" 匹配文字字符(字符串) 不用< / em> 捕获他们的内容
  • 仅在存在语义动作的情况下使用%=
  • 语义在之后运行它的主题解析器成功(并且只有 iff 它成功)。

    因此,即使您应该/应该在语义操作中设置useFactor成员,它也只会在factor部分存在的情况下运行(否则将保留不确定的值)。

  • 格式很重要。

  • 调试很重要。

任选地:

  • 使用BOOST_SPIRIT_DEBUG*调试规则
  • 使用as_vector破解打印结果的快捷方式
  • 我已展示了使用inherited arguments的技巧,因此您可以重复entryentry1
  • entry2规则

未显示:

  • 使用船长进行空白不敏感
  • 使用no_case表示不区分大小写
  • 与船长:谨防lexeme以避免在跳过的输入字符中匹配关键字

工作代码, SSCCE

<强> Live On Coliru

#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <vector>

namespace std {
    template <typename T>
    static ostream& operator<<(ostream& os, vector<T> const& v) {
        os << "vector{ ";
        for(auto& e : v)
            os << "'" << e << "', ";
        return os << "}";
    }
    template <typename T, typename U>
    static ostream& operator<<(ostream& os, pair<T,U> const& p) {
        return os << "pair{ '" << p.first << "', '" << p.second << "' }";
    }
}

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

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

struct Entry
{
    uint32_t id;
    std::vector<std::string> entry1;
    std::vector<std::string> entry2;

    bool useFactor;
    std::pair<int, int> factor;
};

BOOST_FUSION_ADAPT_STRUCT(Entry, id, entry1, entry2, useFactor, factor)

template<typename It>
struct testParser : qi::grammar<It, Entry()>
{
    testParser() : testParser::base_type(start)
    {
        using namespace qi;

        id      = "id=" >> int_;
        entry   = lit(_r1) >> ('[' >> +~char_("],") % ',' >> ']');
        factor  = "factor=" >> ('[' >> int_ >> ',' >> int_ >> ']');

        start = 
                id                >> ';' 
             >> entry(+"entry1=") >> ';' 
             >> entry(+"entry2=") >> ';' 
             >> attr(true)  
             >> (factor | attr(std::pair<int,int>{1,1}))
             >> '!';

        BOOST_SPIRIT_DEBUG_NODES((start)(entry)(id)(factor))
#if 0
#endif
    }
  private:
    qi::rule<It, Entry()>                               start;
    qi::rule<It, int()>                                 id;
    qi::rule<It, std::vector<std::string>(std::string)> entry;
    qi::rule<It, std::pair<int,int>()>                  factor;
};

int main() {
    std::string const input = "id=1;entry1=[A,B,D];entry2=[bla,blubb];factor=[1,5]!";
    using It = std::string::const_iterator;

    testParser<It> g;
    It f = input.begin(), l = input.end();

    Entry entry;
    bool ok = qi::parse(f, l, g, entry);

    std::cout << std::boolalpha;
    if (ok) {
        std::cout << "Parsed: " << boost::fusion::as_vector(entry) << "\n";
    } else {
        std::cout << "Parse failed\n";
    }

    if (f!=l)
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

打印:

<start>
<try>id=1;entry1=[A,B,D];</try>
<id>
    <try>id=1;entry1=[A,B,D];</try>
    <success>;entry1=[A,B,D];entr</success>
    <attributes>[1]</attributes>
</id>
<entry>
    <try>entry1=[A,B,D];entry</try>
    <success>;entry2=[bla,blubb];</success>
    <attributes>[[[A], [B], [D]], [e, n, t, r, y, 1, =]]</attributes>
</entry>
<entry>
    <try>entry2=[bla,blubb];f</try>
    <success>;factor=[1,5]!</success>
    <attributes>[[[b, l, a], [b, l, u, b, b]], [e, n, t, r, y, 2, =]]</attributes>
</entry>
<factor>
    <try>factor=[1,5]!</try>
    <success>!</success>
    <attributes>[[1, 5]]</attributes>
</factor>
<success></success>
<attributes>[[1, [[A], [B], [D]], [[b, l, a], [b, l, u, b, b]], 1, [1, 5]]]</attributes>
</start>
Parsed: (1 vector{ 'A', 'B', 'D', } vector{ 'bla', 'blubb', } true pair{ '1', '5' })

¹(我错过了第一部分,我正在修理标题,平衡括号并为构造函数添加parens等... o.O)。