使用 Boost::Spirit (V2.4) 解析到容器中

发布于 2024-09-27 01:34:47 字数 1613 浏览 1 评论 0原文

我刚刚开始深入研究Boost::Spirit,目前最新版本——V2.4。 我的问题的本质如下:

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

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

规则的属性必须是“vector”。我正在将其读入容器中。

完整的代码:

#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_ 并将其存储在容器中
  • ,然后停在“a”处,而期望 lit(“b”)
  • 转到第二个替代方案
  • 读取另外两个双精度数

我的问题是——这是正确的行为吗?如果是的话——为什么?

I just started to dig into Boost::Spirit, latest version by now -- V2.4.
The essense of my problem is following:

I would like to parse strings like "1a2" or "3b4".
So the rule I use is:

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

The attribute of the rule must be "vector <double>". And I'm reading it into the container.

The complete code:

#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;
 }

I'm compiling it with g++ 4.4.3. And it returns "1 1 2". While I expect "1 2".

As far as I understand this happens because parser:

  • goes to the first alternative
  • reads a double_ and stores it in the container
  • then stops at "a", while expecting lit("b")
  • goes to the second alternative
  • reads two more doubles

My question is -- Is this a correct behavior, and if yes -- why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

弃爱 2024-10-04 01:34:47

这是预期的行为。在回溯期间,Spirit 不会“取消”对属性的更改。因此,您应该使用 hold[] 指令显式强制解析器保留属性的副本(允许回滚任何属性更改):

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

该指令需要应用于修改的所有替代项属性,除了最后一个。

That's expected behavior. During backtracking Spirit does not 'unmake' changes to attributes. Therefore, you should use the hold[] directive explicitly forcing the parser to hold on to a copy of the attribute (allowing to roll back any attribute change):

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

This directive needs to be applied to all alternatives modifying the attribute, except the last one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文