boost::qi::parse似乎会导致编译错误

3

我正在尝试使用Boost::Spirit编写解析器,我已经编写了解析器并进行了编译。问题是,当我尝试编译解析函数时,编译器会抛出一堆模板错误。这是Qi语法:

template<typename Iterator>
struct etf_parser : qi::grammar<Iterator, std::map<std::string, etfnode>(), ascii::space_type> {
    etf_parser() : etf_parser::base_type(start) {
            using qi::int_;
            using qi::lit;
            using qi::double_;
            using qi::bool_;
            using qi::lexeme;
            using ascii::char_;

            quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];

            dataVal %= (quoted_string | double_ | int_ | bool_ | listObj | pairObj | mapObj);

            pairObj %= ('<' >> dataVal >> ',' >> dataVal >> '>');

            listObj %= '{' >> dataVal % ',' >> '}';

            mapKey %= +qi::char_("a-zA-Z_-0-9.");
            mapPair %= mapKey >> lit('=') >> dataVal;
            mapObj %= '(' >> mapPair % ',' >> ')';
            start %= mapPair >> ';';
    }

    qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;

    // Data value parsers
    qi::rule<Iterator, etfnode(), ascii::space_type> dataVal;
    qi::rule<Iterator, std::vector<etfnode>(), ascii::space_type> listObj;
    qi::rule<Iterator, std::pair<etfnode, etfnode>(), ascii::space_type> pairObj;
    qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> mapObj;

    qi::rule<Iterator, std::pair<std::string, etfnode>(), ascii::space_type> mapPair;
    qi::rule<Iterator, std::string(), ascii::space_type> mapKey;

    qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> start;
};

这是解析函数。当我注释掉qi::parse调用时,代码可以编译通过:

ETFDocument::ETFDocument(std::string content) {
    etf_parser<std::string::const_iterator> parser;
    std::map<std::string, rwnode> results;
    std::string::const_iterator begin = content.begin();
    std::string::const_iterator end = content.end();
    bool result = qi::parse(begin, end, parser, results);
    if(result) printf("Parsing succeeded\n"); else printf("Parsing failed\n");

    m_root = etfnode(results);
}

当我尝试编译时,编译器会输出以下错误:
In file included from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14:0,
             from /usr/include/boost/spirit/home/qi.hpp:20,
             from /usr/include/boost/spirit/include/qi.hpp:16,
             from libmcg/etf.cpp:8:
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp: In instantiation of ‘bool boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Context = boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::spirit::locals<> >; Skipper = boost::spirit::unused_type; Attribute = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >; Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; T1 = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >(); T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’:
/usr/include/boost/spirit/home/qi/reference.hpp:43:71:   required from ‘bool boost::spirit::qi::reference<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; Context = boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::spirit::locals<> >; Skipper = boost::spirit::unused_type; Attribute = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >; Subject = const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>]’
/usr/include/boost/spirit/home/qi/parse.hpp:86:82:   required from ‘bool boost::spirit::qi::parse(Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; Expr = etf_parser<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> > >; Attr = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >]’
libmcg/etf.cpp:113:53:   required from here
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:303:17: error: no match for call to ‘(const function_type {aka const boost::function<bool(__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::fusion::vector0<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&)>}) (__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>::context_type&, const boost::spirit::unused_type&)’
In file included from /usr/include/boost/function/detail/maybe_include.hpp:33:0,
             from /usr/include/boost/function/detail/function_iterate.hpp:14,
             from /usr/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:67,
             from /usr/include/boost/function.hpp:64,
             from /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:16,
             from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
             from /usr/include/boost/spirit/home/qi.hpp:20,
             from /usr/include/boost/spirit/include/qi.hpp:16,
             from libmcg/etf.cpp:8:
/usr/include/boost/function/function_template.hpp:1021:7: note: candidate is:
/usr/include/boost/function/function_template.hpp:754:17: note: boost::function4<R, T1, T2, T3, T4>::result_type boost::function4<R, T1, T2, T3, T4>::operator()(T0, T1, T2, T3) const [with R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::fusion::vector0<> >&; T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&; boost::function4<R, T1, T2, T3, T4>::result_type = bool]
/usr/include/boost/function/function_template.hpp:754:17: note:   no known conversion for argument 4 from ‘const boost::spirit::unused_type’ to ‘const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&’

据我所知,它正在寻找Skipper,但实际上返回的是boost::spirit::unused_type。由于我在解析器定义中指定了Skipper,因此我不确定为什么会出现这种情况。我使用的是gcc 4.7.1上的boost v1.49.0。
编辑:这里是etfnode的定义。在cpp文件(包含其他代码片段)的开头有一个typedef,将“etfnode”别名为“rwnode”。
enum DataType {
    DT_INT,
    DT_STRING,
    DT_FLOAT,
    DT_BOOL,
    DT_LIST,
    DT_PAIR,
    DT_MAP
};

struct etfnode;
typedef boost::recursive_wrapper<etfnode> rwnode;
typedef boost::variant<
        int,
        std::string,
        double,
        bool,
        std::vector<rwnode>,
        std::pair<rwnode, rwnode>,
        std::map<std::string, rwnode> > etfvalue;

struct etfnode {
    DataType type;
    etfvalue value;

    etfnode(const std::string& s);
    etfnode(const int i);
    etfnode(const double d);
    etfnode(const bool b);
    etfnode(const std::vector<rwnode>& n);
    etfnode(const std::pair<rwnode, rwnode>& p);
    etfnode(const std::map<std::string, rwnode>& p);
    etfnode();
};

并且有一个测试字符串:

foo = 6;
bar = <"bar", 16.5>;
baz = {
    (
        foobar = "foo",
        bar = 12
    ),
    "foobar"
};

你的错误似乎在具有 std::map<std::string,etfnode>() 属性的规则中之一。你的 start 规则应该是 start %= mapObj >> ';' 吗? - user1252091
谢谢你指出来,但实际上应该是start %= mapPair % ';'。我已经更改了,但问题仍然存在。 - nonpolynomial237
你能否添加etfnode的定义和一个待解析的测试字符串? - user1252091
完成。此外,etfnode 构造函数非常简单 - 基本上是从每个变体类型初始化值和类型成员。 - nonpolynomial237
1
下次为什么不把它变成一个SSCCE呢? - sehe
1个回答

5
我认为最重要的罪魁祸首是您使用了qi::parse而不是qi::phrase_parse,而您的语法明确使用了跳过器。
我还重写了etfvalue递归变量的定义。我不确定您的版本是否应该工作,但现在,您只需在预期所有位置使用etfnode即可。对我来说,这样看起来更一致。
下面是对我编译正常的代码。它解析了示例输入(请参见main())并显示以下输出:
Parsing succeeded
Unparsed remaining: ';'

如果你实际上希望接受分号 ;,请将主要规则修复为以下更适合的形式。
start   = *(mapPair >> ';'); // or  *(mapPair >> (';'|qi::eoi))

祝好运!

//add streaming operators for etfnode and etfvalue if you want to debug this:
//#define BOOST_SPIRIT_DEBUG
#include <map>
#include <string>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>

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

enum DataType {
    DT_INT,
    DT_STRING,
    DT_FLOAT,
    DT_BOOL,
    DT_LIST,
    DT_PAIR,
    DT_MAP
};

struct etfnode;
typedef boost::variant<
        int,
        std::string,
        double,
        bool, 
        boost::recursive_wrapper<std::vector<etfnode> >,
        boost::recursive_wrapper<std::pair<etfnode, etfnode> >,
        boost::recursive_wrapper<std::map<std::string, etfnode> > 
        > etfvalue;

struct etfnode {
    DataType type;
    etfvalue value;

    etfnode(const std::string& s)                       { value = s; type = DT_STRING; }
    etfnode(const int i)                                { value = i; type = DT_INT; }
    etfnode(const double d)                             { value = d; type = DT_FLOAT; }
    etfnode(const bool b)                               { value = b; type = DT_BOOL; }
    etfnode(const std::vector<etfnode>& n)              { value = n; type = DT_LIST; }
    etfnode(const std::pair<etfnode, etfnode>& p)       { value = p; type = DT_PAIR; }
    etfnode(const std::map<std::string, etfnode>& p)    { value = p; type = DT_MAP; }
    etfnode() { }
};

template<typename Iterator>
struct etf_parser : qi::grammar<Iterator, std::map<std::string, etfnode>(), ascii::space_type> {
    etf_parser() : etf_parser::base_type(start) {
            using qi::int_;
            using qi::lit;
            using qi::double_;
            using qi::bool_;
            using qi::lexeme;
            using ascii::char_;

            quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];

            dataVal = (quoted_string | double_ | int_ | bool_ 
                    | listObj    | pairObj 
                    | mapObj
                    );

            listObj = '{' >> dataVal % ',' >> '}';

            pairObj = lit('<') >> dataVal >> ',' >> dataVal >> '>';

            mapKey  = +qi::char_("a-zA-Z_-0-9.");
            mapPair = mapKey >> lit('=') >> dataVal;
            mapObj  = '(' >> mapPair % ',' >> ')';

            start   = mapPair % ';';

            BOOST_SPIRIT_DEBUG_NODE(quoted_string);
            BOOST_SPIRIT_DEBUG_NODE(dataVal);
            BOOST_SPIRIT_DEBUG_NODE(listObj);
            //BOOST_SPIRIT_DEBUG_NODE(pairObj);
            BOOST_SPIRIT_DEBUG_NODE(mapObj);
            BOOST_SPIRIT_DEBUG_NODE(mapKey);
            BOOST_SPIRIT_DEBUG_NODE(mapPair);
            BOOST_SPIRIT_DEBUG_NODE(start);
    }

    qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;

    // Data value parsers
    qi::rule<Iterator, etfnode(),                           ascii::space_type> dataVal;
    qi::rule<Iterator, std::vector<etfnode>(),              ascii::space_type> listObj;
    qi::rule<Iterator, std::pair<etfnode, etfnode>(),       ascii::space_type> pairObj;
    qi::rule<Iterator, std::map<std::string, etfnode>(),    ascii::space_type> mapObj;

    qi::rule<Iterator, std::pair<std::string, etfnode>(),   ascii::space_type> mapPair;
    qi::rule<Iterator, std::string(),                       ascii::space_type> mapKey;

    qi::rule<Iterator, std::map<std::string, etfnode>(),    ascii::space_type> start;
};

int main()
{
    etf_parser<std::string::const_iterator> parser;
    std::map<std::string, etfnode> results;

    std::string content = "foo = 6;\n"
        "bar = <\"bar\", 16.5>;\n"
        "baz = {\n"
        "       (\n"
        "                foobar = \"foo\",\n"
        "                bar = 12\n"
        "   ),\n"
        "   \"foobar\"\n"
        "};";

    std::string::const_iterator begin = content.begin();
    std::string::const_iterator end = content.end();
    bool result = qi::phrase_parse(begin, end, parser, ascii::space, results);
    if(result) printf("Parsing succeeded\n"); else printf("Parsing failed\n");

    if (begin!=end)
        std::cout << "Unparsed remaining: '" << std::string(begin,end) << "'\n";

    //m_root = etfnode(results);
}

谢谢您的帮助。我想我误解了解析(parse)和解析短语(parse_phrase)之间的区别。 - nonpolynomial237

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接