Semantic actions

View: New views
5 Messages — Rating Filter:   Alert me  

Semantic actions

by Dylan Klomparens :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello,

I'm attempting to write a some simple Spirit rules to parse a valid IP address. I want to place the (string) result of the parse into a variable, however I've been unable to do so. Why doesn't parse(...) fill the string "Ip" with the parsed text? When I run the program, Ip is always empty at the end.

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>

int main()
{
    using namespace boost::spirit::qi;
    rule<std::string::const_iterator, std::string()> octet = int_[_pass = (_1 >= 0 && _1 <= 255)];
    rule<std::string::const_iterator, std::string()> ip_address = octet >> '.' >> octet >> '.' >> octet >> '.' >> octet;
    std::string Line, Ip;
    std::getline(std::cin, Line);
    bool Result = parse(Line.begin(), Line.end(), ip_address, Ip);
    std::cout << Ip << std::endl;
    return 0;
}

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Spirit-general mailing list
Spirit-general@...
https://lists.sourceforge.net/lists/listinfo/spirit-general

Re: Semantic actions

by OvermindDL1 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, Nov 2, 2009 at 3:25 PM, Dylan Klomparens
<dylan.klomparens@...> wrote:

> Hello,
>
> I'm attempting to write a some simple Spirit rules to parse a valid IP
> address. I want to place the (string) result of the parse into a variable,
> however I've been unable to do so. Why doesn't parse(...) fill the string
> "Ip" with the parsed text? When I run the program, Ip is always empty at the
> end.
>
> #include <boost/spirit/include/qi.hpp>
> #include <boost/spirit/include/phoenix_core.hpp>
> #include <boost/spirit/include/phoenix_operator.hpp>
> #include <iostream>
> #include <string>
>
> int main()
> {
>     using namespace boost::spirit::qi;
>     rule<std::string::const_iterator, std::string()> octet = int_[_pass =
> (_1 >= 0 && _1 <= 255)];
>     rule<std::string::const_iterator, std::string()> ip_address = octet >>
> '.' >> octet >> '.' >> octet >> '.' >> octet;
>     std::string Line, Ip;
>     std::getline(std::cin, Line);
>     bool Result = parse(Line.begin(), Line.end(), ip_address, Ip);
>     std::cout << Ip << std::endl;
>     return 0;
> }

There are a couple of problems in this code, first:
    int_[_pass = (_1 >= 0 && _1 <= 255)];
Instead you should do something like this:
    uint_parser<unsigned char,10,1,3> uchar_; // not sure the template
is correct, close if not.
Then use uchar_ in place of that entire mess above as it will do the
proper 0<=x<=255 checking and will be all around a lot faster to
execute.

Second, your int_ pass= stuff returns an integer (or if you use my
uchar_ version it returns an unsigned char), and yet you are trying to
return an std::string, that does not work for obvious reasons.  You
either need to change your return type to int/unsigned char, or you
need to wrapp the int_/uchar_ with a raw (raw returns an iterator
range).

Third, same thing with ip_address, it returns a string, but your rule
returns a tuple<std::string,std::string,std::string,std::string>.
Again, wrap the whole thing in raw[].

Are you sure you want the IP return as a string directly?  Do you not
want it parsed into an integer like how it is often represented?

You can also check the iterators you pass in, if begin==end then it
parsed the whole thing successfully without you needing to return
anything.

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Spirit-general mailing list
Spirit-general@...
https://lists.sourceforge.net/lists/listinfo/spirit-general

Re: Semantic actions

by Hartmut Kaiser :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> I'm attempting to write a some simple Spirit rules to parse a valid IP
> address. I want to place the (string) result of the parse into a
> variable, however I've been unable to do so. Why doesn't parse(...)
> fill the string "Ip" with the parsed text? When I run the program, Ip
> is always empty at the end.
>
> #include <boost/spirit/include/qi.hpp>
> #include <boost/spirit/include/phoenix_core.hpp>
> #include <boost/spirit/include/phoenix_operator.hpp>
> #include <iostream>
> #include <string>
>
> int main()
> {
>     using namespace boost::spirit::qi;
>     rule<std::string::const_iterator, std::string()> octet = int_[_pass
> = (_1 >= 0 && _1 <= 255)];
>     rule<std::string::const_iterator, std::string()> ip_address = octet
> >> '.' >> octet >> '.' >> octet >> '.' >> octet;
>     std::string Line, Ip;
>     std::getline(std::cin, Line);
>     bool Result = parse(Line.begin(), Line.end(), ip_address, Ip);
>     std::cout << Ip << std::endl;
>     return 0;
> }

Simple code, tricky answer. Your problem is that the rule definition

    octet = int_[_pass = (_1 >= 0 && _1 <= 255)];

doesn't 'return' any attribute value. Even more, if it returned an
attribute, you would have gotten a compilation error as the rhs' attribute
is int, while the octet's attribute is string.

Generally, rule initialization auto-propagates the attribute value only if
no semantic actions are attached to any of the rhs code. If you have
semantic actions you either need to propagate your rhs attribute yourself,
or you need to enforce auto-propagation by using the operator%= for the
initialization of the rule:

    rule<std::string::const_iterator, int()> octet;
    octet %= int_[_pass = (_1 >= 0 && _1 <= 255)];

This would return the parsed int if the semantic action doesn't reject the
integer value. But now you need to change the attribute type of your other
rule as well:

    rule<std::string::const_iterator, std::vector<int>()> ip_address;

where any other (STL-) container type holding int's would do the trick as
well (such as boost::array<4, int>).

HTH
Regards Hartmut

-------------------
Meet me at BoostCon
http://boostcon.com




------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Spirit-general mailing list
Spirit-general@...
https://lists.sourceforge.net/lists/listinfo/spirit-general

Re: Semantic actions

by Dylan Klomparens :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hartmut and Overmind,

Thank you for the responses! Your suggestions formed a very nice solution.

For anyone who might search/read this in the future, here's the final version of my code to parse an IP address:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>

int main()
{
    using namespace boost::spirit::qi;
    uint_parser<unsigned char,10,1,3> uchar_;
    rule<std::string::const_iterator, std::string()> ip_address = raw[uchar_ >> '.' >> uchar_ >> '.' >> uchar_ >> '.' >> uchar_];
    std::string Line, Ip;
    std::getline(std::cin, Line);
    std::string::iterator It = Line.begin();
    bool Result = parse(It, Line.end(), ip_address, Ip);
    bool Full = It == Line.end();
    std::cout << "Result = " << Result << ", full parse = " << Full << ", Ip = " << Ip << std::endl;
    return 0;
}

-- Dylan

On Mon, Nov 2, 2009 at 9:14 PM, Hartmut Kaiser <hartmut.kaiser@...> wrote:
> I'm attempting to write a some simple Spirit rules to parse a valid IP
> address. I want to place the (string) result of the parse into a
> variable, however I've been unable to do so. Why doesn't parse(...)
> fill the string "Ip" with the parsed text? When I run the program, Ip
> is always empty at the end.
>
> #include <boost/spirit/include/qi.hpp>
> #include <boost/spirit/include/phoenix_core.hpp>
> #include <boost/spirit/include/phoenix_operator.hpp>
> #include <iostream>
> #include <string>
>
> int main()
> {
>     using namespace boost::spirit::qi;
>     rule<std::string::const_iterator, std::string()> octet = int_[_pass
> = (_1 >= 0 && _1 <= 255)];
>     rule<std::string::const_iterator, std::string()> ip_address = octet
> >> '.' >> octet >> '.' >> octet >> '.' >> octet;
>     std::string Line, Ip;
>     std::getline(std::cin, Line);
>     bool Result = parse(Line.begin(), Line.end(), ip_address, Ip);
>     std::cout << Ip << std::endl;
>     return 0;
> }

Simple code, tricky answer. Your problem is that the rule definition

   octet = int_[_pass = (_1 >= 0 && _1 <= 255)];

doesn't 'return' any attribute value. Even more, if it returned an
attribute, you would have gotten a compilation error as the rhs' attribute
is int, while the octet's attribute is string.

Generally, rule initialization auto-propagates the attribute value only if
no semantic actions are attached to any of the rhs code. If you have
semantic actions you either need to propagate your rhs attribute yourself,
or you need to enforce auto-propagation by using the operator%= for the
initialization of the rule:

   rule<std::string::const_iterator, int()> octet;
   octet %= int_[_pass = (_1 >= 0 && _1 <= 255)];

This would return the parsed int if the semantic action doesn't reject the
integer value. But now you need to change the attribute type of your other
rule as well:

   rule<std::string::const_iterator, std::vector<int>()> ip_address;

where any other (STL-) container type holding int's would do the trick as
well (such as boost::array<4, int>).

HTH
Regards Hartmut

-------------------
Meet me at BoostCon
http://boostcon.com




------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Spirit-general mailing list
Spirit-general@...
https://lists.sourceforge.net/lists/listinfo/spirit-general


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Spirit-general mailing list
Spirit-general@...
https://lists.sourceforge.net/lists/listinfo/spirit-general

Re: Semantic actions

by OvermindDL1 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tue, Nov 3, 2009 at 12:05 PM, Dylan Klomparens
<dylan.klomparens@...> wrote:

> Hartmut and Overmind,
>
> Thank you for the responses! Your suggestions formed a very nice solution.
>
> For anyone who might search/read this in the future, here's the final
> version of my code to parse an IP address:
>
> #include <boost/config/warning_disable.hpp>
> #include <boost/spirit/include/qi.hpp>
> #include <boost/spirit/include/phoenix_core.hpp>
> #include <boost/spirit/include/phoenix_operator.hpp>
> #include <iostream>
> #include <string>
>
> int main()
> {
>     using namespace boost::spirit::qi;
>     uint_parser<unsigned char,10,1,3> uchar_;
>     rule<std::string::const_iterator, std::string()> ip_address = raw[uchar_
>>> '.' >> uchar_ >> '.' >> uchar_ >> '.' >> uchar_];
>     std::string Line, Ip;
>     std::getline(std::cin, Line);
>     std::string::iterator It = Line.begin();
>     bool Result = parse(It, Line.end(), ip_address, Ip);
>     bool Full = It == Line.end();
>     std::cout << "Result = " << Result << ", full parse = " << Full << ", Ip
> = " << Ip << std::endl;
>     return 0;
> }

Most of us probably already have one that parses an IP address into
its proper unsigned form, a string is too heavyweight for that.  :)

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Spirit-general mailing list
Spirit-general@...
https://lists.sourceforge.net/lists/listinfo/spirit-general