Boost logo

Boost Users :

Subject: Re: [Boost-users] boost-spirit: need help with simple parser
From: Thomas Heller (thom.heller_at_[hidden])
Date: 2012-07-03 08:24:08


On 07/03/2012 02:02 PM, Allan Nielsen wrote:
> Hi,
>
> Sorry for not providing the simplest possible code to reproduce my
> problem, but I'm still new to spirit, I think I will miss some details
> in the conversion.
>
> I tried add the inclusion you suggested, but it did not help. In the
> mean while, I found this page:
> http://boost-spirit.com/home/2010/01/19/how-to-access-attributes-from-semantic-actions/
> which is a very good match on what I would like to do.
>
> The only problem is that I can not make it work...
>
> Here is my second attempt (simper that the first, but not as simple as
> you suggested... sorry)
>
> #include<string>
> #include<string.h>
> #include<iostream>
> #include<boost/spirit/include/qi.hpp>
> #include<boost/spirit/include/phoenix_core.hpp>
> #include<boost/spirit/include/phoenix_operator.hpp>
>
> struct Ipv4 { union { uint32_t as_int; uint8_t as_char[4]; } raw; };
>
> Ipv4 make_ipv4(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) {
> Ipv4 ip;
> ip.raw.as_char[0] = i1; ip.raw.as_char[1] = i2;
> ip.raw.as_char[2] = i3; ip.raw.as_char[3] = i4;
> return ip;
> }
>
> namespace qi = boost::spirit::qi;
> qi::uint_parser<uint8_t, 10, 1, 3> octet;
>
> struct Ipv4Address : qi::grammar<const char *, Ipv4()> {
> Ipv4Address() : Ipv4Address::base_type(start) {
> start = ( octet>> qi::lit('.')>> octet>> qi::lit('.')>>
> octet>> qi::lit('.')>> octet
> ) [
> //qi::_val = make_ipv4(1, 2, 3, 4) // working
> qi::_val = make_ipv4(qi::_1, qi::_2, qi::_3,
> qi::_4) // compile error
> ]
> ;
> }
> qi::rule<const char *, Ipv4()> start;
> } ipv4_address;
>
> int main() {
> Ipv4 ip;
> const char * s = "1.2.3.4";
> bool r = qi::parse(s, s+strlen(s), ipv4_address, ip);
> std::cout<< r<< " "<< (int)ip.raw.as_char[0]<< "."<<
> (int)ip.raw.as_char[1]<< "."<<
> (int)ip.raw.as_char[2]<< "."<<
> (int)ip.raw.as_char[3]<< std::endl;
> }
>
>
> When compiling this I get the following compile error:
>
> /tmp/ip.cxx: In constructor 'Ipv4Address::Ipv4Address()':
> /tmp/ip.cxx:26:72: error: cannot convert 'const _1_type {aka const
> boost::phoenix::actor<boost::spirit::argument<0> >}' to 'uint8_t {aka
> unsigned char}' for argument '1' to 'Ipv4 make_ipv4(uint8_t, uint8_t,
> uint8_t, uint8_t)'
>
> Any hints?

make_ipv4 is an eager function, you need a lazy function, that is only
executed when the parsing succeeds. Your commented line works as
expected because everything involved in the eager function call has the
right type.
look into phoenix::bind to make the function call lazy

>
> Best regards
> Allan W. Nielsen
>
>
> On Tue, Jul 3, 2012 at 1:10 PM, Igor R<boost.lists_at_[hidden]> wrote:
>>> or even simpler:
>>> boost::tuple<uint8_t, uint8_t, uint8_t, uint8_t> v;
>>> bool r = qi::parse(s.begin(), s.end(), octet>> '.'>> octet>> '.'
>>>>> octet>> '.'>> octet, v);
>>> while the following works correctly:
>>> boost::fusion::vector<uint8_t, uint8_t, uint8_t, uint8_t> v;
>>> bool r = qi::parse(s.begin(), s.end(), octet>> '.'>> octet>> '.'
>>>>> octet>> '.'>> octet, v);
>>> So, the attribute gets converted to boost::tuple is some strange way...
>>
>> Well, finally got it.
>> You have to #include<boost/fusion/include/boost_tuple.hpp> to get
>> boost::tuple adapted correctly.
>> _______________________________________________
>> Boost-users mailing list
>> Boost-users_at_[hidden]
>> http://lists.boost.org/mailman/listinfo.cgi/boost-users
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net