Opened 9 years ago
Closed 5 years ago
#8577 closed Bugs (invalid)
Multiple qi::match calls on the same stream corrupt input data
| Reported by: | Owned by: | Joel de Guzman | |
|---|---|---|---|
| Milestone: | To Be Determined | Component: | spirit |
| Version: | Boost Development Trunk | Severity: | Problem |
| Keywords: | Cc: |
Description
qi::match cannot be reliably called multiple times on the same input stream. Probably it consumes some characters from the stream to do look-ahead but doesn't return them back to the stream on destruction. So it only works reliably if it's the last extraction operator for a given stream.
I know there may be problems to return more than one character to a stream, so if it's the expected qi::match behavior, it's worth to be mentioned in the documentation.
The following code illustrates the problem:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_match.hpp>
#include <iostream>
#include <sstream>
namespace qi = boost::spirit::qi;
int main() {
std::istringstream is("11 22 33 44 55 ");
is >> std::noskipws;
int n = 0;
for (int i = 0; i < 5; ++i) {
is >> qi::match(qi::int_ >> +qi::lit(' '), n);
assert(is);
std::cout << n << ' ';
}
}
Expected output: 11 22 33 44 55 Actual output: 11 2 3 4 5
Change History (3)
comment:1 by , 5 years ago
comment:2 by , 5 years ago
Probably it consumes some characters from the stream to do look-ahead
It will consume data even if your parser is LL(1).
but doesn't return them back to the stream on destruction
You cannot return read data back to input stream (read about InputIterator concept).
so if it's the expected qi::match behavior, it's worth to be mentioned in the documentation.
It should be clear to everyone that to parse data from an input stream you must pull data from the stream and you cannot place the read data back to it, even a single character.
All qi::match is doing is wrapping your iterators with spirit::basic_istream_iterator, calling qi::parse and setting failbit if parsing failed. You should not use qi::match in loop on the same stream at least because it is slow (spirit::basic_istream_iterator lots of heap allocations). Only use qi::match to match all of your input.
Hint: Replace +qi::lit(' ') with a skipper (i.e. use qi::phrase_match)
comment:3 by , 5 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |

It will consume data even if your parser is LL(1).
You cannot return read data back to input stream (read about InputIterator concept).
It should be clear to everyone that to parse data from an input stream you must pull data from the stream and you cannot place the read data back to it, even a single character.
All
qi::matchis doing is wrapping your iterators withspirit::basic_istream_iterator, callingqi::parseand settingfailbitif parsing failed. You should not useqi::matchin loop on the same stream at least because it is slow (spirit::basic_istream_iteratorlots of heap allocations). Only useqi::matchto match all of your input.Hint: Replace
+qi::lit(' ')with a skipper (i.e. useqi::phrase_match)