X3, what is attr_gen?

我与影子孤独终老i 提交于 2019-12-11 03:01:45

问题


I end up getting these move errors a lot and am not quite sure why other than having something to do with the way I'm parsing strings. Remove everything having to do with 'dummy' and the errors come back.

Someone mentioned using attr_gen (couldn't find this in the docs) and by doing so, I can get past these "traits::move_to" compile errors, but the parser still fails. I've marked the lines that I've added to get it to compile, but don't think are necessary with "<---".

#define BOOST_SPIRIT_X3_DEBUG

#include <complex>
#include <iostream>
#include <string>
#include <vector>

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

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;
        namespace ascii = boost::spirit::x3::ascii;

        using namespace x3;
        x3::attr_gen dummy;   // <---                   

        auto const comment = char_ % ' ' >> dummy(false);       // <---
        //auto const comment = lexeme[+graph] >> dummy(false);
        auto const number = int_ >> int_;

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

        auto const input = skip(blank) [
            lines(comment) >> 
            lines(number)
        ];
    }
}

int main()
{
    namespace x3 = boost::spirit::x3;
    using boost::spirit::x3::ascii::blank;
    using x3::char_;

    std::string const iss(R"(this is a test
    1 2)");

    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;

    for (auto& item : types.comments)    { std::cout << boost::fusion::as_deque(item) << "\n"; }
    for (auto& item : types.numbers)    { std::cout << boost::fusion::as_deque(item) << "\n"; }
}

回答1:


x3::attr() is perfectly well documented (the generator type behind it is an implementation detail, much like you'd use x3::int_, not x3::int_gen).

The fact that you need it has been answered before. The key is having single-element fusion sequences.

  • Spirit Qi attribute propagation issue with single-member struct
  • Boost spirit compile error for trivial grammar



回答2:


comment = char_ % ' ';

This parses 1 or more arbitrary characters separated by single space literals. In your case it may match only 't' because what follows is 'h', not a ' '.

I'd naturally spell that

comment = *(char_ - eol);

So it would match anything until eol. If you insist on matching "wordy" things, by all means

comment = skip(blank) [ *lexeme[+graph_] ];

To synthesize the matched input into a string attribute, wrap it in raw[]:

comment = raw [ skip(blank) [ *graph_ ] ];

Or if, indeed you want no other whitespace than ' ', make it so

comment = raw[ skip(' ') [ *graph_ ] ];

It's slightly weird to spell it like

comment = raw[ (+graph_) % ' ' ];

Because

  • it doesn't match an empty line
  • it doesn't match "hello world" or `"hello\tworld"'


来源:https://stackoverflow.com/questions/45157367/x3-what-is-attr-gen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!