2

I'm basing my app off this example and getting the exact same results. For some reason, the contents of the input string are all parsed into the fusion struct 'comments', and nothing is parsed into the fusion struct 'numbers'. So not sure where I'm going wrong here.

namespace client { 
    namespace ast {

        struct number {
            int num1;
            int num2;  
        };

        struct comment {
            std::string text;
            bool dummy;
        };

        struct input {
            std::vector<comment> comments;  
            std::vector<number> numbers;
        };
    } 
}

BOOST_FUSION_ADAPT_STRUCT(client::ast::comment, text, dummy)
BOOST_FUSION_ADAPT_STRUCT(client::ast::number, num1, num2)
BOOST_FUSION_ADAPT_STRUCT(client::ast::input, comments, numbers)

namespace client {      
    namespace parser {

        namespace x3 = boost::spirit::x3;
        using namespace x3;

        x3::attr_gen dummy;

        typedef std::string::const_iterator It;

        using namespace x3;

        auto const comment = *(char_ - eol) >> dummy(false);
        auto const number = int_ >> int_;

        auto lines = [](auto p) { return *(p >> eol); };

        auto const input = 
            lines(comment) >> 
            lines(number);
   }
}

int main()
{
    namespace x3 = boost::spirit::x3;

    std::string const iss("any char string here\n1 2\n");

    auto iter = iss.begin(), eof = iss.end();

    client::ast::input types;

    bool ok = parse(iter, eof, client::parser::input, types);

    if (iter != eof) {
        std::cout << "Remaining unparsed: '" << std::string(iter, eof) << "'\n";
    }
    std::cout << "Parsed: " << (100.0 * std::distance(iss.begin(), iter) / iss.size()) << "%\n";
    std::cout << "ok = " << ok << std::endl;

    // This range loop prints all contents if input.
    for (auto& item : types.comments)    { std::cout << "comment: " << boost::fusion::as_deque(item) << "\n"; }

    // This loop prints nothing.
    for (auto& item : types.numbers)    { std::cout << "number: " << boost::fusion::as_deque(item) << "\n"; }
}  

My larger application does the same with a large input file and several more AST's, yet it would seem all my examples are consumed by the comment parser.

Here's the complete running example.

http://coliru.stacked-crooked.com/a/f983b26d673305a0

Thoughts?

Ender
  • 1,652
  • 2
  • 25
  • 50
  • What does `lines(parser)` do? – llonesmiz Aug 11 '17 at 04:40
  • lines(parser)? lines makes sure each parser (i.e., lines(comment), lines(number) is followed by an eol. – Ender Aug 11 '17 at 04:56
  • It does more than that... – llonesmiz Aug 11 '17 at 04:56
  • Note that the lambda is called `lines`, not `line`. – llonesmiz Aug 11 '17 at 05:16
  • Ok, I think I can see that lines(comment), and hence, *(char_ - eol), is consuming each and every line. I tried to remove the * from (p >> eol) thinking it would be one instead of any number of, but that didn't work. – Ender Aug 11 '17 at 05:23
  • I replaced lines "{ return *(p >> eol); };" with "{ return -(p >> eol); };" which I thought would make it match zero or one times. Instead I'm getting 'attribute does not have expected size." compile errors. Still not able to get this to work. – Ender Aug 15 '17 at 02:39

1 Answers1

1

You took the grammar idea from my answer here: X3, how to populate a more complex AST?

There it worked because the line formats are not ambiguous. In fact the "variant" approach you had required special attention, and I noted that in this bullet:

  • departments need to be ordered before teams, or you get "team" matched instead of departments

The same kind of ambiguity exists in your grammar. *(char_ - eol) matches "1 2" just fine, so obviously it is added as a comment. You will have to disambiguate the grammar or somehow force the switch to "parse number lines now" mode.

If you wholly don't care what precedes the number lines, just use x3::seek [ lines(number) ].

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Can you clarify on the part about "force the switch to 'parse number lines now' mode?" – Ender Aug 15 '17 at 01:20
  • Disambiguate the grammar, e.g. [`repeat(1)[comment]`](https://wandbox.org/permlink/yKd9mTOlBtKTVAB4). _[note the added skipper using `phrase_parse` which you apparently forgot]._ Otherwise, you can _assert_ it: [`lines(!number >> comment]`](https://wandbox.org/permlink/sAlUOItRihTmnOSv), which, as you can see, is less efficient – sehe Aug 15 '17 at 10:24
  • What does `x3::seek`? [Docs](https://www.boost.org/doc/libs/1_69_0/libs/spirit/doc/x3/html/spirit_x3/quick_reference/directive.html) for spirit X3 as of boost 1.69 have no such thing. – Xeverous Jan 16 '19 at 23:05
  • @Ender It's the same as `boost::spirit:: repository::qi::seek` from the Qi repository. I think the X3 docs are indeed missing though I currently don't have the opportunity to check – sehe Jan 16 '19 at 23:08