boost::spirit::qi and boost::phoenix::push_back

boost::spirit::qi and boost::phoenix::push_back

本文关键字:boost back push and spirit qi phoenix      更新时间:2023-10-16

基于使用boost :: spirit :: qi and boost :: phoenix :: phoenix :: push_back,以下代码正常工作 - 使用C 14。

#include <string>
#include <vector>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace qi = boost::spirit::qi;
typedef std::vector<unsigned int> uint_vector_t;
std::ostream& operator<<(std::ostream& out, const uint_vector_t &data)
{
    for (unsigned int i(0); i < data.size(); i++)
    {
        out << data[i] << 'n';
    }
    return out;
}
struct MyStruct
{
    uint_vector_t m_aList;
    uint_vector_t m_bList;
};

template<typename Iterator, typename Skipper>
struct MyParser : public boost::spirit::qi::grammar<Iterator,
        MyStruct(),Skipper>
{
    MyParser() :
        MyParser::base_type(Parser, "Parser")
    {
        using boost::spirit::qi::uint_;
        using boost::spirit::qi::_val;
        using boost::spirit::qi::_1;
        using boost::phoenix::at_c;
        using boost::phoenix::push_back;
        using boost::phoenix::bind;
        aParser = "a=" >> uint_;
        bParser = "b=" >> uint_;
        Parser =
           *(  aParser [push_back(bind(&MyStruct::m_aList, _val), _1)]
            |  bParser [push_back(bind(&MyStruct::m_bList, _val), _1)]
            );
    }
    boost::spirit::qi::rule<Iterator, MyStruct(), Skipper> Parser;
    boost::spirit::qi::rule<Iterator, unsigned int(), Skipper> aParser, bParser;
};
int main()
{
    using boost::spirit::qi::phrase_parse;
    std::string input("a=0nb=7531na=2na=3nb=246n");
    std::string::const_iterator begin = input.begin();
    std::string::const_iterator end = input.end();
    MyParser<std::string::const_iterator, qi::space_type> parser;
    MyStruct result;
    bool succes = qi::phrase_parse(begin, end, parser,qi::space,result);
    assert(succes);
    std::cout << "===A===n" <<result.m_aList << "===B===n" << result.m_bList << std::endl;
    return 0;
}

结果是:

===A===
0
2
3
===B===
7531
246

将另一个Qi ::符号元素添加到结构中,预计新添加的元素将被解析为水果:: Apple(0),但实际上是不确定的(出现随机)。<<<<<<<<<</p>

#include <string>
#include <vector>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace qi = boost::spirit::qi;
typedef std::vector<unsigned int> uint_vector_t;
std::ostream& operator<<(std::ostream& out, const uint_vector_t &data)
{
    for (unsigned int i(0); i < data.size(); i++)
    {
        out << data[i] << 'n';
    }
    return out;
}
struct MyStruct
{
    enum class  FRUIT
    {
        APPLE,
        BANANA,
        PEAR,
    } fruit;
    uint_vector_t m_aList;
    uint_vector_t m_bList;
};
BOOST_FUSION_ADAPT_STRUCT
(
    MyStruct,
    (MyStruct::FRUIT, fruit)
    (uint_vector_t, m_aList)
    (uint_vector_t, m_bList)
)

template<typename Iterator, typename Skipper>
struct MyParser : public boost::spirit::qi::grammar<Iterator,
        MyStruct(),Skipper>
{
    MyParser() :
        MyParser::base_type(Parser, "Parser")
    {
        using boost::spirit::qi::uint_;
        using boost::spirit::qi::_val;
            using boost::spirit::qi::_1;
        using boost::phoenix::at_c;
        using boost::phoenix::push_back;
        using boost::phoenix::bind;
        fruiter.add
                ("apple",   MyStruct::FRUIT::APPLE)
                ("banana",  MyStruct::FRUIT::BANANA)
                ("pear",    MyStruct::FRUIT::PEAR)
                ;
        aParser = "a=" >> uint_;
        bParser = "b=" >> uint_;
        Parser = fruiter >>
           *(  aParser [push_back(bind(&MyStruct::m_aList, _val), _1)]
            |  bParser [push_back(bind(&MyStruct::m_bList, _val), _1)]
            );
    }
    boost::spirit::qi::rule<Iterator, MyStruct(), Skipper> Parser;
    boost::spirit::qi::rule<Iterator, unsigned int(), Skipper> aParser, bParser;
    boost::spirit::qi::symbols<char, MyStruct::FRUIT>                   fruiter;
};
int main()
{
    using boost::spirit::qi::phrase_parse;
    std::string input("applena=0nb=7531na=2na=3nb=246n");
    std::string::const_iterator begin = input.begin();
    std::string::const_iterator end = input.end();
    MyParser<std::string::const_iterator, qi::space_type> parser;
    MyStruct result;
    bool succes = qi::phrase_parse(begin, end, parser,qi::space,result);
    assert(succes);
    std::cout << "Fruit: " << int(result.fruit) << "n===A===n" <<result.m_aList << "===B===n" << result.m_bList << std::endl;
    return 0;
}

生成的Qi ::符号元素是随机的。一个示例输出看起来像

Fruit: 29899839
===A===
0
2
3
===B===
7531
246

但是Qi ::符号元素本身也可以正常工作。

#include <string>
#include <vector>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace qi = boost::spirit::qi;

struct MyStruct
{
    enum class  FRUIT
    {
        APPLE,
        BANANA,
        PEAR,
    } fruit;
};
BOOST_FUSION_ADAPT_STRUCT
(
    MyStruct,
    (MyStruct::FRUIT, fruit)
)

template<typename Iterator, typename Skipper>
struct MyParser : public boost::spirit::qi::grammar<Iterator,
        MyStruct(),Skipper>
{
    MyParser() :
        MyParser::base_type(Parser, "Parser")
    {
        using boost::spirit::qi::uint_;
        using boost::spirit::qi::_val;
            using boost::spirit::qi::_1;
        using boost::phoenix::at_c;
        using boost::phoenix::push_back;
        using boost::phoenix::bind;
        fruiter.add
                ("apple",   MyStruct::FRUIT::APPLE)
                ("banana",  MyStruct::FRUIT::BANANA)
                ("pear",    MyStruct::FRUIT::PEAR)
                ;
        Parser = fruiter;
    }
    boost::spirit::qi::rule<Iterator, MyStruct(), Skipper> Parser;
    boost::spirit::qi::symbols<char, MyStruct::FRUIT>                   fruiter;
};
int main()
{
    using boost::spirit::qi::phrase_parse;
    std::string input("apple");
    std::string::const_iterator begin = input.begin();
    std::string::const_iterator end = input.end();
    MyParser<std::string::const_iterator, qi::space_type> parser;
    MyStruct result;
    bool succes = qi::phrase_parse(begin, end, parser,qi::space,result);
    assert(succes);
    std::cout << "Fruit: " << int(result.fruit) << "n";
    return 0;
}

结果看起来像:

Fruit: 0

我做错了什么?预先感谢。

语义动作抑制属性的自动传播。这显然也是该程序的第一个版本没有针对MyResult结构进行改编的原因。

所以

  1. 坚持语义动作¹(删除适应性结构)

    活在coliru

        Parser = fruiter[bind(&MyStruct::fruit, _val) = _1] >> 
            *( aParser [push_back(bind(&MyStruct::m_aList, _val), _1)] 
            |  bParser [push_back(bind(&MyStruct::m_bList, _val), _1)]
            );
    
  2. 或使用operator%=重新启用自动属性传播语义。

    // NOTE c++11+ syntax:
    BOOST_FUSION_ADAPT_STRUCT(MyStruct, fruit, m_aList, m_bList)
    Parser %= fruiter >> 
        *( aParser [push_back(bind(&MyStruct::m_aList, _val), _1)] 
        |  bParser [push_back(bind(&MyStruct::m_bList, _val), _1)]
        );
    

    请注意,如果fruit不是第一个改编的序列元素,则很容易分解。实际上,只适应预期元素要干净很多:

    BOOST_FUSION_ADAPT_STRUCT(MyStruct, fruit)
    

    甚至清洁器以明确说明哪些属性有望传播:

    Parser %= fruiter >> 
        omit [
           *( aParser [push_back(bind(&MyStruct::m_aList, _val), _1)] 
            | bParser [push_back(bind(&MyStruct::m_bList, _val), _1)]
            )
        ];
    

    活在Coliru

完整列表

活在coliru

#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
typedef std::vector<unsigned int> Uints;
namespace std {
    std::ostream& operator<<(std::ostream& out, const Uints &data) {
        for (auto i : data) out << i << " ";
        return out << "n";
    }
}
struct MyStruct {
    enum class FRUIT {
        APPLE,
        BANANA,
        PEAR,
    } fruit;
    friend std::ostream& operator<<(std::ostream& out, FRUIT f) {
        switch(f) {
            case FRUIT::APPLE:  return out << "APPLE";
            case FRUIT::BANANA: return out << "BANANA";
            case FRUIT::PEAR:   return out << "PEAR";
        }
        return out << "FRUIT[?" << static_cast<int>(f) << "]";
    }
    Uints m_aList;
    Uints m_bList;
};
BOOST_FUSION_ADAPT_STRUCT(MyStruct, fruit)
template <typename Iterator, typename Skipper>
struct MyParser : public qi::grammar<Iterator, MyStruct(), Skipper> {
    MyParser() : MyParser::base_type(Parser, "Parser") {
        using namespace qi;
        using boost::phoenix::push_back;
        using boost::phoenix::bind;
        fruiter.add("apple", MyStruct::FRUIT::APPLE)("banana", MyStruct::FRUIT::BANANA)("pear", MyStruct::FRUIT::PEAR);
        aParser = "a=" >> uint_;
        bParser = "b=" >> uint_;
        Parser %= fruiter >> 
            omit [
               *( aParser [push_back(bind(&MyStruct::m_aList, _val), _1)] 
                | bParser [push_back(bind(&MyStruct::m_bList, _val), _1)]
                )
            ];
    }
  private:
    qi::rule<Iterator, MyStruct(), Skipper> Parser;
    qi::rule<Iterator, unsigned int(), Skipper> aParser, bParser;
    qi::symbols<char, MyStruct::FRUIT> fruiter;
};
int main() {
    std::string input("bananana=0nb=7531na=2na=3nb=246n");
    using It = std::string::const_iterator;
    It begin = input.begin(), end = input.end();
    MyParser<It, qi::space_type> parser;
    MyStruct result;
    bool succes = qi::phrase_parse(begin, end, parser, qi::space, result);
    if (succes) {
        std::cout 
            << "Fruit: " << result.fruit 
            << "n===A===n" <<result.m_aList << "===B===n" << result.m_bList << std::endl;
    } else {
        std::cout << "Parse failedn";
    }
}

打印

Fruit: BANANA
===A===
0 2 3 
===B===
7531 246 

Å重复我的口头禅:增强精神:"语义动作是邪恶的"?