6

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.

jay1189947
  • 201
  • 1
  • 2
  • 9
  • 7
    lol @ "simple Boost::spirit grammars" – Lightness Races in Orbit May 27 '13 at 20:05
  • 2
    As you have discovered, there are no simple Boost Spirit grammars. Use ANTLR instead. – John Zwinck May 27 '13 at 23:31
  • 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 May 28 '13 at 01:44
  • 4
    @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 May 28 '13 at 07:30

1 Answers1

11

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;
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks for the reply! You are right, parse_phrase() must include a skipper, I was not aware of that. I changed my code to use parse() instead, but the same error persists. If you read the first error it says: "error: no matching function for call to ‘boost::spirit::qi::rule<..." maybe it has something to do with the only rule I have ? But I don't see anything wrong with it. I'm also aware that there are much more simpler ways to accomplish what I'm trying to do, but I simplified the grammar to be able to find my mistake. – jay1189947 May 28 '13 at 13:38
  • Finally solved it. The mistake was that I was using an iterator over a string and not a const string... I feel really dumb. Your piece of code made me realize this, thanks again for the reply! – jay1189947 May 28 '13 at 15:35