6
votes

I couldn't get a grammar to work so I simplified it till it only parses an integer. Still can't get it to work. It is the following grammar:

template<typename Iterator>
struct rangeGrammar : qi::grammar<Iterator, int()>
{
    rangeGrammar() :
    rangeGrammar::base_type(number)
    {
        using qi::int_;
        using qi::_1;
        using qi::_val;

        number = int_[_val = _1];
    }
    qi::rule<Iterator, int()> number;
};

It is supposed to just parse an integer (I know I could just tell the parse function to use int_ as the grammar, but I wan't to know what is wrong in this example).

My parse function is:

/* n is a std::string provided by the user */
rangeGrammar<std::string::const_iterator> grammar;
int num = 0;
qi::phrase_parse(n.start(), n.end(), grammar, num);
std::cout << "Number: " << num << std::endl;

I get the following compiler error:

/boost/spirit/home/qi/reference.hpp: In member function ‘bool boost::spirit::qi::reference::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator >, Context = boost::spirit::context, boost::spirit::locals<> >, Skipper = boost::spirit::unused_type, Attribute = int, Subject = const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator >, int(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>]’: /boost/spirit/home/qi/parse.hpp:89:82: instantiated from ‘bool boost::spirit::qi::parse(Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator >, Expr = rangeGrammar<__gnu_cxx::__normal_iterator > >, Attr = int]’ ../parameter_parser.h:95:46: instantiated from here boost/spirit/home/qi/reference.hpp:43:71: error: no matching function for call to ‘boost::spirit::qi::rule<__gnu_cxx::__normal_iterator >, int(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>::parse(__gnu_cxx::__normal_iterator >&, const __gnu_cxx::__normal_iterator >&, boost::spirit::context, boost::spirit::locals<> >&, const boost::spirit::unused_type&, int&) const’ cc1plus: warnings being treated as errors /boost/spirit/home/qi/reference.hpp:44:9: error: control reaches end of non-void function * exit status 1 *

Can't figure out what the problem is. Any help would be greatly appreciated.

1
lol @ "simple Boost::spirit grammars"Lightness Races in Orbit
As you have discovered, there are no simple Boost Spirit grammars. Use ANTLR instead.John Zwinck
I spoke to a kind chap from the boost "team" on IRC the other day and asked why Spirit has such low documentation coverage. He exclaimed that its actually very well documented... +1 for use ANTLR.Jesse Hallam
@Kivin What's your gripe with Spirit documentation? It is well documented. Being an eDSL, it's just not simple, neither are the diagnostics. If it's not for you, it's not for you. But I highly doubt the documentation is going be the definitive factor?sehe

1 Answers

11
votes

A: There's nothing little wrong with the grammar, but you're using qi::phrase_parse which requires a skipper. Use qi::parse and the problem goes away.

Note 1: Using [_val=_1] is completely redundant there; rules without semantic attributes enjoy automatic attribute propagation.

Note 2: You might want to use qi::match to do parsing like this:

#include <boost/spirit/include/qi_match.hpp>

const std::string input = "1234";
std::istringstream iss(input);
iss >> qi::match(qi::int_ [ std::cout << qi::_1 ]);

Finally For your interest, here's a skeleton 'doParse' function with running test that shows some more elements of good Qi practice:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi    = boost::spirit::qi;
namespace phx   = boost::phoenix;

template<typename Iterator>
struct rangeGrammar : qi::grammar<Iterator, int()>
{
    rangeGrammar() : rangeGrammar::base_type(number)
    {
        number = qi::int_;
    }
    qi::rule<Iterator, int()> number;
};

bool doParse(const std::string& input)
{
    typedef std::string::const_iterator It;
    It f(begin(input)), l(end(input));

    try
    {
        rangeGrammar<It> p;
        int data;

        bool ok = qi::parse(f,l,p,data);
        if (ok)   
        {
            std::cout << "parse success\n";
            std::cout << "data: " << data << "\n";
        }
        else      std::cerr << "parse failed: '" << std::string(f,l) << "'\n";

        if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
        return ok;
    } catch(const qi::expectation_failure<It>& e)
    {
        std::string frag(e.first, e.last);
        std::cerr << e.what() << "'" << frag << "'\n";
    }

    return false;
}

int main()
{
    bool ok = doParse("1234");
    return ok? 0 : 255;
}