2012-03-24 51 views
4

我有以下語法,它按預期工作。Boost中的複合語法:: Spirit

struct query_term { 
    std::string term; 
    bool is_tag; 

    query_term(const std::string &a, bool tag = false): term(a), is_tag(tag) { } }; 

template<typename Iterator> struct query_grammar: grammar<Iterator, std::vector<query_term>(), space_type> { 
    query_grammar(): 
     query_grammar::base_type(query) { 

     word %= +alnum; 
     tag = (omit[word >> ':'] >> word[_val = phoenix::construct<query_term>(_1, true)]); 
     non_tag = word[_val = phoenix::construct<query_term>(_1, false)]; 
     query = (
        (omit[word >> ':'] >> word[push_back(_val, phoenix::construct<query_term>(_1, true))]) 
       | 
        word[push_back(_val, 
          phoenix::construct<query_term>(_1)) 
        ] 
       ) % space; 
    }; 

    qi::rule<Iterator, std::string(), space_type> word; 
    qi::rule<Iterator, query_term, space_type> tag; 
    qi::rule<Iterator, query_term, space_type> non_tag; 
    qi::rule<Iterator, std::vector<query_term>(), space_type> query; }; 

但是,當我與

query = (
      tag[phoenix::push_back(_val, _1)] 
     | 
      word[push_back(_val, 
        phoenix::construct<query_term>(_1)) 
      ] 
     ) % space; 

代碼不編譯替代查詢。基本上我試圖將語法分解成可以在更大的語法中重用的組件。當解析單詞或標籤時,創建一個帶有適當標誌的query_term對象,其標籤爲標籤單詞規則。在查詢規則中重用這些屬性。

在以前的版本中,標記和單詞規則在查詢語法中內聯。

我不知道我在這裏錯過了什麼。任何幫助將不勝感激。

供參考:這不是最終的代碼。在生產代碼中使用它之前,我正在嘗試使用這些規則。

感謝名單, - baliga

+0

IMO,代碼不漂亮。嘗試整理它,你可能會看到問題出在哪裏。 – 2012-03-24 09:57:44

+4

代碼本身很漂亮,Boost :: Spirit有這個運算符超負荷的語法,你必須忍受。 – buc 2012-03-24 11:23:12

+0

@AshBurlaczenko Thanx建議。有些提示會對此有所幫助。 – 2012-03-24 19:42:59

回答

4

真正的問題是,你定義爲query_term(而不是query_term())爲標記/ non_tag規則的屬性。

一些小問題似乎是:

  • 使用word代替non_tag(公開爲std :: string不轉換爲query_type)使用% space用空格船長不
  • 真的很有道理
  • 你可能想在word規則lexeme規則,因爲否則,它將只是保持'吃'字符無論空格

其他建議:

  • 避免using namespace過量範圍(或完全避免的話)。你遇到難以發現或難以修復的衝突(例如boost :: cref與std :: cref,std :: string與qi :: string等)。

  • 儘量保持低鳳凰使用率。在這種情況下,我認爲使用qi::attr來修改結構會更容易。

  • 使用BOOST_SPIRIT_DEBUG_ *宏來獲得洞察力解析器

下面是完整的語法,我建議的方式:

template<typename Iterator> struct query_grammar: qi::grammar<Iterator, std::vector<query_term>(), qi::space_type> 
{ 
    query_grammar() : query_grammar::base_type(query) 
    { 
     using namespace qi; 

     word = lexeme[ +alnum ]; 

     tag  = omit[word >> ':'] >> word >> attr(true); 

     non_tag = word >> attr(false); 

     query = *(tag | non_tag); 
    }; 

    qi::rule<Iterator, std::string()   , qi::space_type> word; 
    qi::rule<Iterator, query_term()    , qi::space_type> tag, non_tag; 
    qi::rule<Iterator, std::vector<query_term>(), qi::space_type> query; 
}; 

與輸出工作的完整示例(使用業力普通onelined):

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

namespace qi = boost::spirit::qi; 
namespace karma = boost::spirit::karma; 

struct query_term { 
    std::string term; 
    bool is_tag; 
}; 

BOOST_FUSION_ADAPT_STRUCT(query_term, (std::string,term)(bool,is_tag)); 

template<typename Iterator> struct query_grammar: qi::grammar<Iterator, std::vector<query_term>(), qi::space_type> 
{ 
    query_grammar() : query_grammar::base_type(query) 
    { 
     using namespace qi; 

     word = lexeme[ +alnum ]; 

     tag  = omit[word >> ':'] >> word >> attr(true); 

     non_tag = word >> attr(false); 

     query = *(tag | non_tag); 

     BOOST_SPIRIT_DEBUG_NODE(word); 
     BOOST_SPIRIT_DEBUG_NODE(tag); 
     BOOST_SPIRIT_DEBUG_NODE(non_tag); 
     BOOST_SPIRIT_DEBUG_NODE(query); 
    }; 

    qi::rule<Iterator, std::string()   , qi::space_type> word; 
    qi::rule<Iterator, query_term()    , qi::space_type> tag, non_tag; 
    qi::rule<Iterator, std::vector<query_term>(), qi::space_type> query; 
}; 


int main() 
{ 
    const std::string input = "apple tag:beer banana grape"; 
    typedef std::string::const_iterator It; 

    query_grammar<It> parser; 
    std::vector<query_term> data; 

    It f(input.begin()), l(input.end()); 
    bool ok = qi::phrase_parse(f, l, parser, qi::space, data); 

    if (ok) 
     std::cout << karma::format(karma::delimit [ karma::auto_ ] % karma::eol, data) << '\n'; 
    if (f!=l) 
     std::cerr << "Unparsed: '" << std::string(f,l) << "'\n"; 

    return ok? 0 : 255; 
} 

輸出:

apple false 
beer true 
banana false 
grape false 
+0

你搖滾! Thanx用於指出query_type與query_type()。這完全是一個錯字,應該避免。 – 2012-03-26 16:57:54

+0

@DudeFromManaglore哈哈,隨時! – sehe 2012-03-26 16:59:02