Reputation: 11696
I'm a Boost.Qi beginner, so I'm trying some simple examples to try to get my mind around it. I'm trying to parse a string that looks like:
A:1 B:2 C:3
There is an arbitrary amount of whitespace between each component in the string. The A:
, etc. portions are fixed, and I'd like to parse the integer values. The third component of the string, C:3
in the above example, is optional. I came up with the following simple example to test Boost.Qi for this application:
#include <boost/optional.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
int main()
{
std::string s = "A:1 B:2 C:3";
int a, b;
boost::optional<int> c;
if (!qi::parse(s.begin(), s.end(),
qi::lit("A:") >> qi::int_ >> +qi::space >> "B:" >> qi::int_ >>
-(+qi::space >> "C:" >> qi::int_), a, b, c))
{
std::cout << "failed to parse" << std::endl;
}
std::cout << a << ' ' << b << ' ' << c.value_or(-1) << std::endl;
}
However, this fails to compile (using Boost v1.58 and g++ 5.4.0 in C++11 mode). In the typical sea of C++ template error messages, I find the following:
spirit.cc:15:55: required from here
/usr/include/boost/spirit/home/support/container.hpp:130:12: error: ‘int’ is not a class, struct, or union type
struct container_value
and
spirit.cc:15:55: required from here
/usr/include/boost/spirit/home/qi/detail/pass_container.hpp:316:66: error: no type named ‘type’ in ‘struct boost::spirit::traits::container_value<int, void>’
typedef typename traits::container_value<Attr>::type value_type;
^
/usr/include/boost/spirit/home/qi/detail/pass_container.hpp:329:15: error: no type named ‘type’ in ‘struct boost::spirit::traits::container_value<int, void>’
Is it obvious to anyone what I'm doing wrong here?
Upvotes: 2
Views: 174
Reputation: 19041
Your original grammar looks like this (with some formatting):
qi::lit("A:")
>> qi::int_
>> +qi::space
>> qi::lit("B:")
>> qi::int_
>> -( +qi::space
>> qi::lit("C:")
>> qi::int_
)
It's important to note the attribute types each of the terminals generates:
Furthermore, note the relevant rules for compound attributes.
Based on that, you actually have:
+
)-
) tuple (due to the >>
) of
+
)This does not match what you call parse
with.
The key is to use the omit
directive to suppress the attributes you don't care about.
The correct grammar in that case would be:
qi::lit("A:")
>> qi::int_
>> qi::omit[+qi::space]
>> qi::lit("B:")
>> qi::int_
>> -( qi::omit[+qi::space]
>> qi::lit("C:")
>> qi::int_
)
Upvotes: 3
Reputation: 8484
A way to fix this could be by using phrase_parse
and qi::space
skipper:
if (!qi::phrase_parse(s.begin(), s.end(),
qi::lit("A:") >> qi::int_ >> "B:" >> qi::int_ >> -("C:" >> qi::int_), qi::space, a, b, c))
Upvotes: 4