Unable to define a rule in Spirit:: Qi
I am trying to parse a Unix file path into pairs of folders(key/value pairs - as needed by my application). The problem is I am unable to define parsers using qi::rule correctly. I get pages of compiler errors which I am unable to understand completely (Sorry if the question sounds simple but I am really stuck and unable to proceed)
The below is the program snippet.
UPDATE: I have modified the program as per Nicol and ildjarn's suggestions, but the problem still persists.
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
template <typename Iterator>
bool parse_data(Iterator first, Iterator last, std::vector< std::pair<std::string, std::string> >& v)
{
using qi::double_;
using qi::char_;
using qi::phrase_parse;
using qi::_1;
using ascii::space_type;
using phoenix::ref;
using phoenix::push_back;
std::pair<std::string, std::string> p;
qi::rule<Iterator, std::string()> key = '/' >> *char_("a-zA-Z0-9");
qi::rule<Iterator, std::string()> val = '/' >> *char_("a-zA-Z0-9");
qi::rule<Iterator, std::pair<std::string, std::string>()> ppair = key >> val ;
//bool r = phrase_parse(
bool r = parse(
first,
last,
(
+ppair[push_back(ref(v), _1)]
)
);
if (first != last)
return fal开发者_开发知识库se;
return r;
}
}
int
main()
{
std::string str;
while (getline(std::cin, str))
{
if (str.empty())
break;
std::vector< std::pair<std::string, std::string> > vec_pair;
if(client::parse_data(str.begin(), str.end(), vec_pair))
{
std::cout << std::endl << "Parsing done" << std::endl;
std::cout << "Strings are " ;
std::pair<std::string, std::string> temp;
for(std::vector< std::pair<std::string, std::string> >::iterator i = vec_pair.begin(); i < vec_pair.end(); i++)
{
temp = *i;
std::cout << temp.first <<"|" << temp.second;
}
std::cout << std::endl;
}
else
{
std::cout << "Parsing Failed" << std::endl;
}
}
return 0;
}
Errors:
/usr/local/include/boost_1_46_1/boost/spirit/home/qi/detail/assign_to.hpp:109: error: no matching function for call to
‘std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::pair(const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)’
/usr/lib/gcc/x86_64-redhat-linux/4.3.2/../../../../include/c++/4.3.2/bits/stl_pair.h:88: note: candidates are:
std::pair<_T1, _T2>::pair(const _T1&, const _T2&) [with _T1 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _T2 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]
/usr/lib/gcc/x86_64-redhat-linux/4.3.2/../../../../include/c++/4.3.2/bits/stl_pair.h:84: note: std::pair<_T1, _T2>::pair() [with _T1 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _T2 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]
/usr/lib/gcc/x86_64-redhat-linux/4.3.2/../../../../include/c++/4.3.2/bits/stl_pair.h:73: note: std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::pair(const std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&)
Can you please help me fix this problem ?
Thanks
In order for Spirit to parse data into a user-defined data structure, you must provide an adapter. This is done with Boost.Fusion, as shown in the documentation. You would need to do this:
BOOST_FUSION_ADAPT_STRUCT(
client::pair,
(std::string, key)
(std::string, val)
Note that this must be defined a global scope (you must exit your client
namespace, define this, then re-enter the client
namespace).
But for this narrow case, you'd be better off parsing into a std::pair<std::string, std::string>
. Spirit knows how to work with that sort of thing.
Also, note that this is in addition to the parse
vs. parse_phrase
issue that ildjarn pointed out. Both must be fixed.
One more thing. You should redefine the rule you are parsing. This:
ppair >> *(ppair)
Has a raw attribute type of boost.tuple<client::pair, std::vector<client::pair> >
. If you do this:
+ppair
Then you get a clean std::vector<client::pair>
.
After adding these #include's your program above compiles fine for me (Boost V1.47):
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/std_pair.hpp>
Please note that there have been quite some implementation changes to Spirit in this (newest) version, which might explain why it compiles here, but not for you (if you're using an older version).
精彩评论