2012-02-04 41 views
3

我有一個由混合變量($(name))和變量值對($(name:value))組成的簡單文法。我有一個手工編碼的遞歸解析器,但有興趣將它用作學習Spirit的練習,最終(/很快)我將需要它來使用更復雜的語法。使用Boost.Spirit解析混合值和鍵值對

總之,一套我與(簡化從完整的語法)工作可能的形式是:

$(variable)  // Uses simple look-up, recursion and inline replace 
$(name:value) // Inserts a new variable into the local lookup table 

我現在的規則是這樣:

typedef std::map<std::string, std::string> dictionary; 

template <typename Iterator> 
bool parse_vars(Iterator first, Iterator last, dictionary & vars, std::string & output) 
{ 
    using qi::phrase_parse; 
    using qi::_1; 
    using ascii::char_; 
    using ascii::string; 
    using ascii::space; 
    using phoenix::insert; 

    dictionary statevars; 

    typedef qi::rule<Iterator, std::string()> string_rule; 
    typedef qi::rule<Iterator, std::pair<std::string, std::string>()> pair_rule; 

    string_rule state = string >> ':' >> string; // Error 3 
    pair_rule variable = 
    (
     char_('$') >> '(' >> 
     (
      state[insert(phoenix::ref(statevars), _1)] | 
      string[output += vars[_1]] // Error 1, will eventually need to recurse 
     ) >> ')' 
    ); // Error 2 

    bool result = phrase_parse 
    (
     first, last, 
     (
      variable % ',' 
     ), 
     space 
    ); 

    return r; 
} 

如果:這不是什麼很明顯,我不知道Spirit是如何工作的,而且文檔除了實際的解釋之外都有其他的東西,所以這大概需要一個小時的時間。

零件在可變規則我特別問題是領先的char_('$'),但除去這會導致移位運算錯誤(編譯器解釋'$' >> '('作爲右移位)。

編譯時,我得到有關狀態規則,特別是創造了對錯誤,並查找:

  1. 錯誤C2679:二進制「[」:沒有操作員發現這需要右手類型'const boost :: spirit :: _ 1_type'的操作數(或者沒有可接受的轉換)
  2. 錯誤C2512:'boost :: spirit :: qi :: rule :: rule':沒有適當的默認構造函數可用

更改查找(vars[_1])以簡單的+=給出:

。錯誤C2665:「的boost ::精神:: char_class ::分類::是」:沒有15個重載可以轉換所有的參數類型

錯誤1似乎涉及到的類型(屬性?)的_1佔位符,但應該是一個字符串,並且在用於打印或連接到輸出字符串時是。 2似乎引起的噪音1.

錯誤3,向下挖掘模板的誤差的疊層,似乎涉及不能夠轉動狀態規則成一對,這似乎奇數,因爲它幾乎完全匹配其中一條規則從this example

如何修改變量規則以正確處理兩個輸入表單?

回答

2

有幾件事情需要注意:

  1. 適應std::pair(這樣你就可以用地圖中使用它),你應該包括(至少)

    #include <boost/fusion/adapted/std_pair.hpp> 
    
  2. 它看起來像你正試圖創建一個符號表。你可以使用qi::symbols

  3. 避免混合輸出生成與分析,過度

我沒有「固定」所有上述(由於缺乏上下文的),但我這事情複雜化我樂意幫助解決由此產生的任何其他問題。

這裏是一個固定的代碼版本,保持非常接近OP。 編輯現在也已經測試過,輸出如下:

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/fusion/adapted/std_pair.hpp> 
#include <map> 

namespace qi = boost::spirit::qi; 
namespace phx = boost::phoenix; 

typedef std::map<std::string, std::string> dictionary; 

template <typename Iterator, typename Skipper = qi::space_type> 
    struct parser : qi::grammar<Iterator, Skipper> 
{ 
    parser(dictionary& statevars, std::string& output) : parser::base_type(start) 
    { 
     using namespace qi; 
     using phx::insert; 

     with_initializer = +~char_(":)") >> ':' >> *~char_(")"); 

     simple   = +~char_(")"); 

     variable   = 
      "$(" >> (
        with_initializer [ insert(phx::ref(statevars), qi::_1) ] 
       | simple   [ phx::ref(output) += phx::ref(statevars)[_1] ] 
      ) >> ')'; 

     start = variable % ','; 

     BOOST_SPIRIT_DEBUG_NODE(start); 
     BOOST_SPIRIT_DEBUG_NODE(variable); 
     BOOST_SPIRIT_DEBUG_NODE(simple); 
     BOOST_SPIRIT_DEBUG_NODE(with_initializer); 
    } 

    private: 
    qi::rule<Iterator, std::pair<std::string, std::string>(), Skipper> with_initializer; 
    qi::rule<Iterator, std::string(), Skipper> simple; 
    qi::rule<Iterator, Skipper> variable; 
    qi::rule<Iterator, Skipper> start; 
}; 

template <typename Iterator> 
bool parse_vars(Iterator &first, Iterator last, dictionary & vars, std::string & output) 
{ 
    parser<Iterator> p(vars, output); 
    return qi::phrase_parse(first, last, p, qi::space); 
} 

int main() 
{ 
    const std::string input = "$(name:default),$(var),$(name)"; 
    std::string::const_iterator f(input.begin()); 
    std::string::const_iterator l(input.end()); 

    std::string output; 
    dictionary table; 

    if (!parse_vars(f,l,table,output)) 
     std::cerr << "oops\n"; 
    if (f!=l) 
     std::cerr << "Unparsed: '" << std::string(f,l) << "'\n"; 
    std::cout << "Output: '" << output << "'\n"; 
} 

輸出:

Output: 'default' 
+0

@peachykeen:我已經修復了我的代碼示例(我一直在用我的鼻子閱讀,因爲我完全錯過了'parse_vars' _template function_甚至沒有實例化的事實:)現在它運行並且測試對我來說確定。 – sehe 2012-02-05 16:48:15

+0

我打算說,我試過了,它給了類似的錯誤;將在今天晚些時候再次測試,並讓你知道發生了什麼。 :) – ssube 2012-02-07 14:23:09

+0

對於子集文法,更新實際上工作得很好。現在我必須補充其餘的... – ssube 2012-02-09 00:17:03

-2

你必須有char _('$'),否則>>兩邊都是'char' - 你需要至少有一種精神類型來獲得重載操作符>>。

您可能還需要使用phoenix中的_1。

也看看: http://boost-spirit.com/home/articles/qi-example/parsing-a-list-of-key-value-pairs-using-spirit-qi/

+0

這是不好的建議的事實,不需要在非技術位? – sehe 2012-02-05 13:11:41

+0

第一點很明顯,問題是'char _('$')'是否是那裏正確的精神構造。其餘部分是無關緊要的,儘管爲複雜文法手動編寫解析器並不是一個好的或可行的想法。 – ssube 2012-02-05 16:06:54

+0

我已經刪除了可能回答的爭議部分。是的,char _('$')是我的答案所暗示的正確結構。不是手動解析鍵值對列表特別困難。 – Pete 2013-07-25 11:37:39