2015-06-10 63 views
3

這是來自a previous question的後續問題。製作來自齊靈的共享指針矢量

我可以從我的語法解析字符串的向量,但我似乎無法解析到共享指針字符串的向量;即std::vector<std::shared_ptr<std::string> >,並需要一些幫助。

我的編譯頭:

#define BOOST_SPIRIT_USE_PHOENIX_V3 1 


#include <boost/spirit/include/qi_core.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <iostream> 
#include <string> 


#include <boost/spirit/include/phoenix_stl.hpp> 

#include <boost/phoenix/bind/bind_member_function.hpp> 
#include <boost/spirit/include/phoenix_fusion.hpp> 



// this solution for lazy make shared comes from the SO forum, user sehe. 
// https://stackoverflow.com/questions/21516201/how-to-create-boost-phoenix-make-shared 
// post found using google search terms `phoenix construct shared_ptr` 
// changed from boost::shared_ptr to std::shared_ptr 
namespace { 
    template <typename T> 
    struct make_shared_f 
    { 
     template <typename... A> struct result 
     { typedef std::shared_ptr<T> type; }; 

     template <typename... A> 
     typename result<A...>::type operator()(A&&... a) const { 
      return std::make_shared<T>(std::forward<A>(a)...); 
     } 
    }; 

    template <typename T> 
    using make_shared_ = boost::phoenix::function<make_shared_f<T> >; 
} 




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


template<typename Iterator, typename Skipper = ascii::space_type> 
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> 
{ 


    SystemParser() : SystemParser::base_type(variable_group_) 
    { 
     namespace phx = boost::phoenix; 
     using qi::_1; 
     using qi::_val; 
     using qi::eps; 
     using qi::lit; 


     var_counter = 0; 

     declarative_symbols.add("variable_group",0); 

     variable_group_ = "variable_group" > genericvargp_ > ';'; 
     genericvargp_ = new_variable_ % ','; // 
     new_variable_ = unencountered_symbol_ [_val = make_shared_<std::string>() (_1)]; 
     unencountered_symbol_ = valid_variable_name_ - (encountered_variables | declarative_symbols); 
     valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_")); 



//  debug(variable_group_); debug(unencountered_symbol_); debug(new_variable_); debug(genericvargp_); 
//  BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_)) 
    } 


    // rule declarations. these are member variables for the parser. 
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > variable_group_; 
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > genericvargp_; 
    qi::rule<Iterator, std::shared_ptr<std::string()> > new_variable_; 
    qi::rule<Iterator, std::string()> unencountered_symbol_; 
    qi::rule<Iterator, std::string()> valid_variable_name_; 


    unsigned var_counter; 
    qi::symbols<char,int> encountered_variables; 
    qi::symbols<char,int> declarative_symbols; 
}; 

與驅動程序代碼:

int main(int argc, char** argv) 
{ 

    std::vector<std::shared_ptr<std::string> > V; 
    std::string str = "variable_group x, y, z; "; 


    std::string::const_iterator iter = str.begin(); 
    std::string::const_iterator end = str.end(); 


    SystemParser<std::string::const_iterator> S; 


    bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V); 

    if (s) 
    { 
     std::cout << "Parse succeeded: " << V.size() << " variables\n"; 
     for (auto& s : V) 
      std::cout << " - '" << s << "'\n"; 
    } 
    else 
     std::cout << "Parse failed\n"; 

    if (iter!=end) 
     std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n"; 


    return 0; 
} 

的內容是正確分析,但所得到的矢量的長度爲0,而它應該是長度3的不知何故,std::shared_ptr<string>沒有被推到由規則genericvargp_產生的向量的背面。

我已經嘗試了很多事情,包括讀取測試解析中的所有調試信息,以及規則定義的%=符號的位置,這些符號應該用於存在未分配的語義操作的規則_val除非我錯了。我也玩了一整天,用phx::bind手動推到_val的背面,但沒有任何地方。我進一步證實了sehe在另一個答案中提供的make_shared_對於std :: shared_ptr實際上是懶惰的。

順便說一句,我也努力與得到一個unencountered_symbol_的結果添加到encountered_variables以強制變量名稱的唯一...

的問題似乎是的結果的傳播new_variable_規則到genericvargp_規則中的共享指針的期望向量上。

+0

我想補充一點,我故意留在氣的價值: :符號。現在,它是int,但後來我將放入shared_ptr < Node >,以便在解析函數時,可以將找到的符號與適當的節點相關聯。所以留下整數對我來說很重要。 – ofloveandhate

回答

4

這個聲明

qi::rule<Iterator, std::shared_ptr<std::string()> > new_variable_; 

不匹配所需的類型:

qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_; 

可悲的是,在老SpiritV2這個屬性被自動忽略,沒有屬性傳播完成。這也解釋了爲什麼在編譯時沒有錯誤。

Live On Coliru

#define BOOST_SPIRIT_USE_PHOENIX_V3 1 
#define BOOST_SPIRIT_DEBUG 1 

#include <boost/spirit/include/qi_core.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <iostream> 
#include <string> 

#include <boost/spirit/include/phoenix_stl.hpp> 

#include <boost/phoenix/bind/bind_member_function.hpp> 
#include <boost/spirit/include/phoenix_fusion.hpp> 

// this solution for lazy make shared comes from the SO forum, user sehe. 
// https://stackoverflow.com/questions/21516201/how-to-create-boost-phoenix-make-shared 
// post found using google search terms `phoenix construct shared_ptr` 
// changed from boost::shared_ptr to std::shared_ptr 
namespace { 
    template <typename T> struct make_shared_f { 
     template <typename... A> struct result { typedef std::shared_ptr<T> type; }; 

     template <typename... A> typename result<A...>::type operator()(A &&... a) const { 
      return std::make_shared<T>(std::forward<A>(a)...); 
     } 
    }; 

    template <typename T> using make_shared_ = boost::phoenix::function<make_shared_f<T> >; 
} 

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

template <typename Iterator, typename Skipper = ascii::space_type> 
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> { 

    SystemParser() : SystemParser::base_type(variable_group_) { 
     namespace phx = boost::phoenix; 
     using qi::_1; 
     using qi::_val; 
     using qi::eps; 
     using qi::lit; 

     var_counter = 0; 

     declarative_symbols.add("variable_group", 0); 

     variable_group_  = "variable_group" > genericvargp_ > ';'; 
     genericvargp_   = new_variable_ % ',';                      // 
     new_variable_   = unencountered_symbol_ [_val = make_shared_<std::string>()(_1)]; 
     unencountered_symbol_ = valid_variable_name_ - (encountered_variables | declarative_symbols); 
     valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_")); 

     BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_)) 
    } 

    // rule declarations. these are member variables for the parser. 
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> variable_group_; 
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> genericvargp_; 
    qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_; 
    qi::rule<Iterator, std::string()> unencountered_symbol_; 
    qi::rule<Iterator, std::string()> valid_variable_name_; 

    unsigned var_counter; 
    qi::symbols<char, qi::unused_type> encountered_variables; 
    qi::symbols<char, qi::unused_type> declarative_symbols; 
}; 

int main() 
{ 
    std::vector<std::shared_ptr<std::string> > V; 
    std::string str = "variable_group x, y, z; "; 

    std::string::const_iterator iter = str.begin(); 
    std::string::const_iterator end = str.end(); 

    SystemParser<std::string::const_iterator> S; 

    bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V); 

    if (s) 
    { 
     std::cout << "Parse succeeded: " << V.size() << " variables\n"; 
     for (auto& s : V) 
      std::cout << " - '" << *s << "'\n"; 
    } 
    else 
     std::cout << "Parse failed\n"; 

    if (iter!=end) 
     std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n"; 
} 

打印

Parse succeeded: 3 variables 
- 'x' 
- 'y' 
- 'z' 

除了大量的調試信息

+0

是,釘了它。我繼續享受我與齊的經歷,感謝你和所有幫助我們的新人如此自由的人。感謝您的快速回復。 – ofloveandhate

+0

我在Joel的博客上看到關於V3精靈的一些信息。期待它!我應該現在跳躍(2015.06.10)嗎? – ofloveandhate