2010-10-12 74 views
2

我刚开始深入研究Boost :: Spirit,现在是最新版本 - V2.4。 我的问题的本质如下:用Boost :: Spirit(V2.4)解析为容器

我想解析字符串像“1a2”“3b4”。 所以我用的规则是:

(double_ >> lit('b') >> double_) 
| (double_ >> lit('a') >> double_); 

规则的属性必须是“矢量<双>”。我正在将它读入容器中。

的完整代码:

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

#include <iostream> 
#include <algorithm> 
#include <string> 
#include <vector> 
#include <cstring> 

int main(int argc, char * argv[]) 
{ 
    using namespace std; 
    using namespace boost::spirit; 
    using namespace boost::spirit::qi; 
    using boost::phoenix::arg_names::arg1; 

    char const * first = "1a2"; 
    char const * last = first + std::strlen(first); 
    vector<double> h; 

    rule<char const *, vector<double>()> or_test; 
    or_test %= (double_ >> lit('b') >> double_) 
      | (double_ >> lit('a') >> double_); 

    if (parse(first, last, or_test,h)) { 
      cout << "parse success: "; 
      for_each(h.begin(), h.end(), (cout << arg1 << " ")); 
      cout << "end\n"; 
    } else cout << "parse error\n" << endl; 
    return 0; 
} 

我使用g ++ 4.4.3编译它。它返回“1 1 2”。虽然我期望“1 2”。

据我理解这是因为解析器:

  • 进入第一个替代
  • 读取容器
  • 接着停留于“一”一double_并将其存储,同时期待点燃( “b”)
  • 前进到第二替代
  • 读取两个更多双打

我的问题是 - 这是一个正确的行为,如果是的话 - 为什么?

回答

4

这是预期的行为。在回溯过程中,Spirit不会“改变”属性。因此,你应该使用hold[]指令,明确强制解析器扶住属性的副本(允许回滚任何属性的变化):

or_test =  
     hold[double_ >> lit('b') >> double_)] 
    | (double_ >> lit('a') >> double_) 
    ; 

这个指令需要被应用到修改属性的所有替代方案,除了最后一个。

+0

谢谢你的回答。对不起,愚蠢的问题 - 但我真的仔细阅读文档,并没有发现这种事情。我可以问一个跟进 - 有没有更好的方法来做同样的/类似的事情? – Kostya 2010-10-12 15:22:44

+0

这是你可以做的最好的,我不认为有不同的理由。由于'hold []'是显式的,因此您可以完全控制引发的开销,从而使其最小化。 – hkaiser 2010-10-12 22:18:36

相关问题