Based on a QA on Using boost::spirit::qi and boost::phoenix::push_back, the following code works fine - compiled with 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=0\nb=7531\na=2\na=3\nb=246\n");
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;
}
The result is:
===A===
0
2
3
===B===
7531
246
Adding another qi::symbols element into the structure, the newly added element is expected to be parsed as FRUIT::APPLE (0), but it is actually indeterminate (appearing random).
#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("apple\na=0\nb=7531\na=2\na=3\nb=246\n");
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;
}
The resulting qi::symbols element is random instead of 0. An example output looks like
Fruit: 29899839
===A===
0
2
3
===B===
7531
246
However the qi::symbols element itself only works fine, too.
#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;
}
The result looks like:
Fruit: 0
What did I do wrong? Thanks in advance.