2012-07-05 45 views
2

我的解析器用Spirit :: Qi 2.4寫了一些問題。 我有一系列的鍵值對來解析以下格式<key name>=<value>Spirit Qi序列解析問題

鍵名可以[a-zA-Z0-9]並且總是跟着=標誌鍵名=符號之間沒有空格。 密鑰名稱也總是在前面至少有一個空格。

幾乎可以是任何C的表達(空格也是可能的),用含炭=表達和代碼塊{ }除外。

在鍵值對序列的末尾有一個{符號。

我爲寫這個表達式的解析器掙扎了很多。由於密鑰名字總是由至少一個空間之前和之後=,並且不包含空格我把它定義爲

KeyName %= [+char_("a-zA-Z0-9_") >> lit("=")] ; 

值幾乎可以是任何東西,但它不能包含=也不{字符,所以我定義它爲:

Value %= +(char_ - char_("{=")) ; 

我想過用前瞻的這樣搭上值:

ValueExpression 
    %= ( 
     Value 
     >> *space 
     >> &(KeyName | lit("{")) 
    ) 
    ; 

但它不會工作,出於某種原因(似乎ValueExpression貪婪地上升到=標誌,並且「不知道」從那裏做什麼)。我對LL解析器的知識有限,所以我不確定這裏做什麼。有沒有其他辦法可以解決這種問題?

這裏的例子系列:

EXP1=FunctionCall(A, B, C) TEST="Example String" \ 
AnotherArg=__FILENAME__ - 'BlahBlah' EXP2= a+ b+* { 

附加信息:,因爲這是一個更大的語法的一部分,我不能真正解決這個問題的任何其他方式比通過Spirit.Qi解析器(如按'='分割並執行一些自定義分析或類似的操作)。

編輯:

我已經在這裏創造最低工作例如:http://ideone.com/kgYD8
(VS 2012下編譯提升1.50,而應該是對舊的設置罰款以及)。

+0

如果你改變+(char_-char_(」 {=「))to +〜char _(」{=「)? –

+1

我可以給你一個在你的示例代碼中讓我感到奇怪的東西,但是我擔心它可能與你的_real code_沒有關係(因爲這是最小化的)。如果你關心,我可以回答你可能有的更多問題,[超出我發佈的答案](http://stackoverflow.com/a/11353205/85371),如果你發佈一個新問題/你的真實代碼。 – sehe

+0

當然,請分享您的見解! – kurczak

回答

3

我建議你看看文章Parsing a List of Key-Value Pairs Using Spirit.Qi

我已經大大簡化你的代碼,而

  • 添加屬性處理
  • 去除鳳凰語義動作的規則

這是

  • 調試,事不宜遲:

    #define BOOST_SPIRIT_DEBUG 
    
    #include <boost/fusion/adapted.hpp> 
    #include <boost/spirit/include/qi.hpp> 
    #include <map> 
    
    namespace qi = boost::spirit::qi; 
    namespace fusion = boost::fusion; 
    
    typedef std::map<std::string, std::string> data_t; 
    
    template <typename It, typename Skipper> 
    struct grammar : qi::grammar<It, data_t(), Skipper> 
    { 
        grammar() : grammar::base_type(Sequence) 
        { 
         using namespace qi; 
    
         KeyName = +char_("a-zA-Z0-9_") >> '='; 
         Value = qi::no_skip [+(~char_("={") - KeyName)]; 
         Sequence = +(KeyName > Value); 
    
         BOOST_SPIRIT_DEBUG_NODE(KeyName); 
         BOOST_SPIRIT_DEBUG_NODE(Value); 
         BOOST_SPIRIT_DEBUG_NODE(Sequence); 
        } 
        private: 
        qi::rule<It, data_t(), Skipper>  Sequence; 
        qi::rule<It, std::string()>   KeyName; // no skipper, removes need for qi::lexeme 
        qi::rule<It, std::string(), Skipper> Value; 
    }; 
    
    template <typename Iterator> 
    data_t parse (Iterator begin, Iterator end) 
    { 
        grammar<Iterator, qi::space_type> p; 
    
        data_t data; 
    
        if (qi::phrase_parse(begin, end, p, qi::space, data)) { 
         std::cout << "parse ok\n"; 
         if (begin!=end) { 
          std::cout << "remaining: " << std::string(begin,end) << '\n'; 
         } 
        } else { 
         std::cout << "failed: " << std::string(begin,end) << '\n'; 
        } 
    
        return data; 
    } 
    
    int main() 
    { 
        std::string test(" ARG=Test still in first ARG ARG2=Zombie cat EXP2=FunctionCall(A, B C) {"); 
        auto data = parse(test.begin(), test.end()); 
    
        for (auto& e : data) 
         std::cout << e.first << "=" << e.second << '\n'; 
    } 
    

    輸出將是:

    parse ok 
    remaining: { 
    ARG=Test still in first ARG 
    ARG2=Zombie cat 
    EXP2=FunctionCall(A, B C) 
    

    如果你真的想要 '{' 是最後的價值的一部分,改變這一行:

    Value = qi::no_skip [+(char_ - KeyName)]; 
    
  • +2

    真棒回答,謝謝。我不知道規則調試,並且仍然對船長有點困惑。儘管我很喜歡Spirit的想法,但我發現缺乏適當的一體化文檔(一切似乎都散佈在數百篇文章中),最佳實踐和更復雜的例子使得它很難做對了。我不知道你可以調試這樣的規則,我也喜歡你的樣本的編譯時間是我的1/5。 – kurczak

    +2

    @kurczak精神不是一個簡單的圖書館:它有利於權力和靈活性,犧牲簡單性。對我而言,文檔非常棒。你似乎在尋找的是經驗。通過這樣的非簡單框架,獲得它的唯一方法是:重複應用程序。如果你缺乏正確的玩具項目,文章/樣品/測試是_inspiration_的一個很好的來源。 – sehe