chinu
chinu

Reputation: 239

Not able to compile a simple parser written in Boost::Spirit library

following is a minimal size program which I am not able to compile in Boost::spirit library.

    #include <iostream>
    #include <string>
    #include <boost/spirit/include/qi.hpp>
    #include <boost/lexical_cast.hpp>
    using namespace boost::spirit;

    template <typename Iterator>
    struct z3_exp_grammars : qi::grammar<Iterator, std::string(), ascii::space_type>
    {
        z3_exp_grammars() : z3_exp_grammars::base_type(text)
        {


            text = qi::int_[qi::_val = boost::lexical_cast<std::string>(qi::_1)];
         }

        qi::rule<Iterator, std::string(), ascii::space_type> text;

    };


    int main(){

        std::string test("3");
            std::string result;
            std::string::const_iterator beg = test.begin();
            std::string::const_iterator end = test.end();
            typedef z3_exp_grammars<std::string::const_iterator> z3_exp_grammars;
            z3_exp_grammars par;
            qi::phrase_parse(beg,end,par,result);
            std::cout<<"Result is "<<result<<std::endl;
}

I am expecting to see the string 3 in variable result but the code is not compiling. Rather than looking at error log (which is very threatening because of templates) it will be great if someone can spot my error in the code. Thanks for your help.

Updating the question with the compilation errors that I get after compiling the same code as given by T.C.

Test.cpp:9:11: error: expected nested-name-specifier before ‘result_type’
Test.cpp:9:11: error: using-declaration for non-member at class scope
Test.cpp:9:23: error: expected ‘;’ before ‘=’ token
Test.cpp:9:23: error: expected unqualified-id before ‘=’ token
In file included from /home/jaganmohini/Downloads/boost_1_58_0/boost/proto/proto_fwd.hpp:28:0,
                 from /home/jaganmohini/Downloads/boost_1_58_0/boost/phoenix/core/limits.hpp:26,
                 from /home/jaganmohini/Downloads/boost_1_58_0/boost/spirit/include/phoenix_limits.hpp:11,
                 from /home/jaganmohini/Downloads/boost_1_58_0/boost/spirit/home/support/meta_compiler.hpp:16,
                 from /home/jaganmohini/Downloads/boost_1_58_0/boost/spirit/home/qi/meta_compiler.hpp:14,
                 from /home/jaganmohini/Downloads/boost_1_58_0/boost/spirit/home/qi/action/action.hpp:14,
                 from /home/jaganmohini/Downloads/boost_1_58_0/boost/spirit/home/qi/action.hpp:14,
                 from /home/jaganmohini/Downloads/boost_1_58_0/boost/spirit/home/qi.hpp:14,
                 from /home/jaganmohini/Downloads/boost_1_58_0/boost/spirit/include/qi.hpp:16,
                 from Test.cpp:3:
/home/jaganmohini/Downloads/boost_1_58_0/boost/utility/result_of.hpp: In instantiation of ‘boost::detail::result_of_nested_result<const to_string_, const to_string_(int&)>’:
/home/jaganmohini/Downloads/boost_1_58_0/boost/utility/result_of.hpp:197:1:   instantiated from ‘boost::detail::tr1_result_of_impl<const to_string_, const to_string_(int&), false>’

Upvotes: 1

Views: 173

Answers (2)

sehe
sehe

Reputation: 392833

You cannot perform "eager" functions on "lazy" actors like qi::_1.

The type of qi::_1 is simply qi::_1_type: it's a placeholder.

Either you have to

  • adapt the function
  • create/wrap a lazy functor (boost::phoenix::function<> or BOOST_PHOENIX_ADAPT_FUNCTION etc)
  • use phx::bind e.g. with a lambda
  • pass a raw semantic action calleable (see docs)

In this case I would do neither of the above, because it's fishy to use lexical_cast when implementing a parser (that's like putting the receipt of you bank account in a sock under the bed. Or like driving to the bike-shed by car).

I'd parse to an int, here (because that's exactly what qi::int_ is designed to match and expose).

If you want the input string that was matched as an int, use

    text = qi::raw [ qi::int_ ];

If you insist on "reformatting", I'd do:

Live On Coliru

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

namespace qi = boost::spirit::qi;

int main()
{
    using It = std::string::const_iterator;
    std::string const test("3");

    It beg = test.begin(), end = test.end();

    int result;
    if (qi::phrase_parse(beg, end, qi::int_, qi::space, result))
        std::cout << "Result is " << boost::lexical_cast<std::string>(result) << std::endl;
}

Notes:

  • separate concerns (parsing vs. presentation)
  • pass the skipper in phrase_parse :)

Upvotes: 1

T.C.
T.C.

Reputation: 137301

Two separate issues:

  1. phrase_parse expects a Skipper as its fourth argument. Hence, you should use qi::phrase_parse(beg, end, par, ascii::space, result);

  2. You can't use boost::lexical_cast on a phoenix placeholder like that. It's eagerly evaluated. You need to create a lazy function:

    struct to_string_ {
        using result_type = std::string;
        template<class T>
        std::string operator()(const T& arg) const {
            return boost::lexical_cast<std::string>(arg); 
        }
    };
    
    boost::phoenix::function<to_string_> to_string;
    

    and do

    text = qi::int_[qi::_val = to_string(qi::_1)];
    

Demo.

Upvotes: 2

Related Questions