Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
508 views
in Technique[技术] by (71.8m points)

stl - Parsing with Boost::Spirit (V2.4) into container

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
";
    } else cout << "parse error
" << 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...