2012-07-09 60 views
3

我正在尝试使用Boost :: Spirit编写解析器,并且我已经编写了解析器并编译。问题是,当我尝试编译解析函数时,编译器会抛出一堆模板错误。这里是Qi语法:boost :: qi :: parse似乎会导致编译错误

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; 
}; 

这里是解析函数。当我注释掉齐::解析调用,代码编译好:

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" 
}; 
+0

您的错误似乎位于具有'std :: map ()'属性的规则之一中。你的'start'规则不应该是'start%= mapObj >>';';'? – 2012-07-09 07:50:18

+0

感谢您指出,尽管它实际上应该是'start%= mapPair%';';'。我改变了它,但问题仍然存在。 – computergeek6 2012-07-09 07:54:04

+0

您可以添加etfnode的定义和要解析的测试字符串吗? – 2012-07-09 08:00:35

回答

5

我认为最重要的罪魁祸首是,你正在使用的不是qi::parseqi::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); 
} 
+0

感谢您的帮助。我想我误解了parse和parse_phrase之间的区别。 – computergeek6 2012-07-09 22:04:41

相关问题