2

What did I mess up here? I'm getting 'start': undeclared identifier but I stuck pretty closely to the tutorial, so I'm not sure where I made a typo, or what I did wrong. Any hints? You all see the same thing, right?

#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <iostream>
#include <string>
#include <boost/array.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi_no_skip.hpp>
#include <boost/spirit/include/phoenix.hpp>


namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

using qi::lit;
using qi::int_;
using qi::double_;
using ascii::char_;
using boost::spirit::qi::phrase_parse;
using boost::spirit::qi::no_skip;
using qi::eoi;


struct LETTER
{
    char hi;
//  int fourtytwo;
//  char mom;
};

BOOST_FUSION_ADAPT_STRUCT(
    LETTER,
    (char, hi)
//  (int, fourtytwo)
//  (char, mom)
)


template <typename Iterator>
struct LETTERParser : qi::grammar<Iterator, LETTER(), ascii::space_type>
{
    LETTERParser(): LETTERParser::base_type(start)
    {
        start %= lit("LETTER") >> char_;
//          >> char_ 
//          >> int_ 
//          >> char_ 
//          >> eoi
//          ;
    }
};

const std::string wat("Z");
int main()
{
    LETTERParser<std::string::const_iterator> f;
    LETTER example;
    phrase_parse(wat.begin(), wat.end(), f, no_skip, example);
    return 0;
}
Carbon
  • 3,828
  • 3
  • 24
  • 51

1 Answers1

2

There are a number of issues, one of which is non obvious

  1. where's no_skip? Why are you passing it to a grammar that requires ascii::space_type?
  2. where is the start rule declared?
  3. don't pollute global namespace - it creates hard problems in generic code
  4. handle errors
  5. the grammar starts with a mandatory character sequence, which doesn't match the input
  6. the non-obvious one: single-element structs interfere in unfortunate ways in Spirit/Fusion land.

Simplify:

Fixing the above and modernizing (c++11) the fusion adaptation:

live On Coliru

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>

namespace qi = boost::spirit::qi;

struct LETTER {
    char hi;
    int fourtytwo;
    char mom;
};

BOOST_FUSION_ADAPT_STRUCT(LETTER, hi, fourtytwo, mom)

template <typename Iterator> struct LETTERParser : qi::grammar<Iterator, LETTER(), qi::ascii::space_type> {
    LETTERParser() : LETTERParser::base_type(start) {
        using qi::char_;
        using qi::int_;
        start = "LETTER" >> char_ >> int_ >> char_;
    }
  private:
    qi::rule<Iterator, LETTER(), qi::ascii::space_type> start;
};

int main() {
    const std::string input("LETTER Z 42m");
    using It = std::string::const_iterator;

    LETTERParser<It> parser;
    LETTER example;

    It f = input.begin(), l = input.end();

    if (phrase_parse(f, l, parser, qi::ascii::space, example)) {
        std::cout << "parsed: " << boost::fusion::as_vector(example) << "\n";
    } else {
        std::cout << "couldn't parse '" << input << "'\n";
    }

    if (f != l)
        std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}

Prints

parsed: (Z 42 m)

Single Element:

You're in, luck it doesn't bite in your case:

Live On Coliru

Prints

parsed: (Z)
Remaining unparsed input: '42m'

as expected. If it strikes in the future, refer here e.g. Size of struct with a single element


Bonus

Consider encapsulating the choice of skipper. The caller should probably never be able to override it Live On Coliru - see also Boost spirit skipper issues

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Bonus: encapsulate the choice of skipper, the caller shouldn't override it, 99.999% of the time: [Live On Coliru](http://coliru.stacked-crooked.com/a/0e0df29d2f00b1bb) – sehe Nov 27 '17 at 19:16