2012-12-13 29 views
5

我有一個非常簡單的解析器使用boost ::精神:的boost ::精神::氣重複解析的輸出

rule<std::string::iterator, std::string()> zeroTo255 = (string("25") >> char_('0', '5')) 
    | (char_('2') >> char_('0', '4') >> digit) 
    | (char_('1') >> repeat[2](digit)) 
    | (char_('1', '9') >> digit) | digit; 

當我嘗試解析

std::string o{"1"}; 
std::string s; 
parse(o.begin(), o.end(), zeroTo255, s); 
std::cout << o << ": " << s << std::endl; 

我作爲輸出

1: 111 

我明顯做錯了什麼,但是什麼?

回答

8

qi::hold是它的一種方式,如正確地@Andrzej

提到的我覺得我有一些看法,可能會幫助,以及更好的解決方案。


問題是Spirit不需要通過設計爲屬性設置'temp'存儲。事實上,它並不能真正假定該屬性是可複製的。這是此處的原因(設想將所有內容解析爲單個std :: vector <>並複製每個解析器步驟?)。

在更重要的層面上,它在我看來好像不是屬性處理,而是解析器表達式本身:它沒有聲明意圖,並且導致各種處理複雜性號碼錶示當...真的不應該。

我就帶它會

rule<std::string::iterator, std::string()> zeroTo255, alternatively; 

alternatively %= raw [ uint_ [ _pass = (_1 <= 255) ] ]; 

你看:你讓精神分析的數字,而事實上只是驗證的範圍,這是你想在第一時間做什麼。

第二件讓我覺得非常典型的事情是,該規則公開的是std::string屬性,而不是unsigned char。這是爲什麼?這不影響屬性

  • 正向前查找(&parser) - -

    假設這是一個有意識的設計決策,就可以通過明智地使用

    • 負先行(!parser)有它自己的方式,其不影響屬性
    • qi::as_stringqi::rawqi::lexemeqi::no_skip
    • 語義動作結識(不依靠自動規則

    這裏就是你原來的規則最小的變化將有工作:

    zeroTo255 = raw [ 
          ("25" >> char_("0-5")) 
         | ('2' >> char_("0-4") >> digit) 
         | ('1' >> digit >> digit) 
         | (char_("1-9") >> digit) 
         | digit 
        ]; 
    

    這與使用qi::hold作爲代碼大致相同的效果,但不是性能缺點_hold_ing屬性值。

    希望這會有所幫助。

    全樣本:住在http://liveworkspace.org/code/4v4CQW$0

    #include <boost/spirit/include/qi.hpp> 
    #include <boost/spirit/include/phoenix.hpp> 
    
    namespace qi = boost::spirit::qi; 
    
    int main() 
    { 
        using namespace qi; 
        rule<std::string::iterator, std::string()> zeroTo255, alternatively; 
    
        zeroTo255 = raw [ 
           ("25" >> char_("0-5")) 
          | ('2' >> char_("0-4") >> digit) 
          | ('1' >> digit >> digit) 
          | (char_("1-9") >> digit) 
          | digit 
         ]; 
    
        alternatively %= raw [ uint_ [ _pass = (_1 <= 255) ] ]; 
    
        for (auto& input : std::vector<std::string> { "255", "249", "178", "30", "4" }) 
        { 
         std::string output; 
         std::cout << "zeroTo255:\t" << std::boolalpha 
            << parse(std::begin(input), std::end(input), zeroTo255, output) 
            << ": " << output << std::endl; 
    
         output.clear(); 
         std::cout << "alternatively:\t" << std::boolalpha 
            << parse(std::begin(input), std::end(input), alternatively, output) 
            << ": " << output << std::endl; 
        } 
    
    } 
    

    輸出

    zeroTo255:  true: 255 
    alternatively: true: 255 
    zeroTo255:  true: 249 
    alternatively: true: 249 
    zeroTo255:  true: 178 
    alternatively: true: 178 
    zeroTo255:  true: 30 
    alternatively: true: 30 
    zeroTo255:  true: 4 
    alternatively: true: 4 
    
  • 5

    我曾經遇到過類似的問題。這是Spirit在Spirit中運作的特殊方式。如果您使用其他指令「hold」,您的示例應該可以工作。

    rule<std::string::iterator, std::string()> zeroTo255 
    = hold[string("25") >> char_('0', '5')] 
    | hold[char_('2') >> char_('0', '4') >> digit] 
    | hold[char_('1') >> repeat[2](digit)] 
    | hold[char_('1', '9') >> digit] | digit; 
    

    有關行爲的詳細信息,請參閱this thread

    +0

    這似乎倒退,但無論如何...感謝你的快速解答! –

    +0

    @brunonery我明白你對'額外工作'的含義。我會在這個評論中解釋,但是它有點大,所以我把它作爲答案來發布:) – sehe

    +0

    對不起Andrzej - 你的回答是正確的,但是sehe的更完整。我給他這個獎,好嗎? –