What is the correct way to use boost::qi::rule with BOOST_FUSION_ADAPT_STRUCT?

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-11 03:46:00

问题


I am attempting to get a qi::rule<> to emit a struct with BOOST_FUSION_ADAPT_STRUCT based on the boost employee example.

I have the following struct and its associated fusion macro:

struct LineOnCommand
{
   int lineNum;
   std::vector<char> humpType;
};

BOOST_FUSION_ADAPT_STRUCT(
   LineOnCommand,
   (int, lineNum)
   (std::vector<char>, humpType)
)

The associated parsing rules are:

qi::rule<Iterator, std::vector<char> ascii::space_type> humpIdentifer = qi::lit("BH") | qi::lit("DH");

qi::rule<Iterator, LineOnCommand(), ascii::space_type> Cmd_LNON = qi::int_ >> -humpIdentifier >> qi::lit("LNON");

I then have a compound rule, of which all others (including this simple test case) are a part which is passed to the parser:

qi::rule<Iterator, qi::unused_type, ascii::space_type> commands =
   +( /* other rules | */ Cmd_LNON /*| other rules */);

bool success = qi::phrase_parse(StartIterator, EndIterator, commands, ascii::space);

The problem comes when I attempt to compile, and I get the error:

<boostsource>/spirit/home/qi/detail/assign_to.hpp(152): error: no suitable constructor exists to convert form "const int" to "LineOnCommand"
    attr = static_cast<Attribute>(val);

Clearly I'm doing something wrong, but I'm not sure what. If I understand the way spirit works, the 2nd argument to the template of the rule represents the attribute (i.e. the data type emitted by the rule), and the BOOST_FUSION_ADAPT_STRUCT macro will adapt my struct so that boost knows how to convert a stream that is "int, std::vector" to it.

The only difference between what I'm doing here and the boost employee example is that I'm not using an explicit grammar to do the parsing. My understanding is this is not necessary, and that a rule by itself is sufficient.

What am I doing wrong?


回答1:


I'm not sure. I think I'm missing the problem. Perhaps, I "naturally" sidestep the problem because your sample is not self-contained.

So, here's my take on it: See it Live On Coliru, in the hope that just comparing things helps you:

  • I fixed the obvious typos in your rule declaration
  • I suggested something other than qi::unused_type; if there's no attribute, there's no need to state it; beyond the iterator type, the template arguments to qi::rule and qi::grammar are not positional. So

    qi::rule<It, qi::unused_type(), ascii::space_type> r;
    qi::rule<It, ascii::space_type, qi::unused_type()> r;
    qi::rule<It, ascii::space_type> r;
    

    are all /logically/ equivalent.

Full listing:

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>

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

struct LineOnCommand
{
   int lineNum;
   std::vector<char> humpType;
};

BOOST_FUSION_ADAPT_STRUCT(
   LineOnCommand,
   (int, lineNum)
   (std::vector<char>, humpType)
)

template <typename It, typename Skipper = ascii::space_type>
struct parser : qi::grammar<It, std::vector<LineOnCommand>(), Skipper>
{
    parser() : parser::base_type(commands)
    {
        using namespace qi;
        humpIdentifier = string("BH") | string("DH");
        Cmd_LNON       = int_ >> -humpIdentifier >> "LNON";

        commands       = +( /* other rules | */ Cmd_LNON /*| other rules */ );
    }
  private:
    qi::rule<It, std::vector<char>(),          Skipper> humpIdentifier;
    qi::rule<It, LineOnCommand(),              Skipper> Cmd_LNON;
    qi::rule<It, std::vector<LineOnCommand>(), Skipper> commands;
};

int main()
{
    typedef std::string::const_iterator Iterator;
    parser<Iterator> p;

    std::string const input = 
        "123 BH LNON\n"
        "124 LNON\t\t\t"
        "125 DH LNON\n"
        "126 INVALID LNON";

    auto f(input.begin()), l(input.end());

    std::vector<LineOnCommand> data;
    bool success = qi::phrase_parse(f, l, p, ascii::space, data);

    std::cout << "success:" << std::boolalpha << success << ", " 
              << "elements: " << data.size() << "\n";

    if (success)
    {
        for (auto& el : data)
        {
            std::cout << "Item: " << el.lineNum << ", humpType '" << std::string(el.humpType.begin(), el.humpType.end()) << "'\n";
        }
    }

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

    return success? 0 : 1;
}

Output:

success:true, elements: 3
Item: 123, humpType 'BH'
Item: 124, humpType ''
Item: 125, humpType 'DH'
Trailing unparsed: '126 INVALID LNON'


来源:https://stackoverflow.com/questions/23276879/what-is-the-correct-way-to-use-boostqirule-with-boost-fusion-adapt-struct

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