Using Iterator parsing with Boost::Spirit Grammars
-
22-08-2019 - |
Question
When I attempt to use the iterator form of parsing for a Spirit grammar I get a argument passing conversion error from the iterator type to const char*. How do I fix this?
There are some restrictions. I'm using an iterator adapter on large inputs, so it is not feasible for me to convert to a C style string.
Here is sample code demonstrating the issue:
#include <boost/spirit/core.hpp>
#include <boost/spirit/iterator/file_iterator.hpp>
#include <vector>
#include <string>
using std;
using boost::spirit;
struct ex : public grammar<route_grammar> {
template <typename ScannerT> struct defintion {
definition(ex const& self) {
expression = real_p;
}
rule<ScannerT> expression;
rule<ScannerT> const& start() const { return expression; }
};
int main() {
file_iterator<char> first;
file_iterator<char> last = first.make_end();
ex ex_p;
parse_info<file_iterator<char> > info = parse(first, last, ex_p, space_p);
return 0;
}
This code breaks with: error: cannot convert const boost::spirit::file_iterator<char_t, boost::spirit::fileiter_impl::mmap_file_iterator<char_t> >
to const char*
in argument passing
Solution
Hard to tell from the code as posted, since it contains a few basic errors. After correction of these, it compiles fine on my machine (with MSVC++7.1):
#include <boost/spirit/core.hpp>
#include <vector>
#include <string>
using namespace std;
using namespace boost::spirit;
struct ex : public grammar<ex> {
template <typename ScannerT>
struct definition {
definition(ex const& self)
{
expression = real_p;
}
rule<ScannerT> expression;
rule<ScannerT> const& start() const { return expression; }
};
};
int main() {
vector<char> v;
v.push_back('3'); v.push_back('.'); v.push_back('2');
ex ex_p;
parse_info<vector<char>::iterator> info = parse(v.begin(), v.end(), ex_p, space_p);
return 0;
}
OTHER TIPS
Here is one way of getting the char *'s pointing at the same elements as the iterators:
&v.front() // v.begin()
&v.back() + 1 // v.end()
I'm not sure how you got this to compile though:
vector<char> v;
v.push_back("3.2");
The compilation error was not in the sample provided. In the grammar above I have no semantic actions, while in the code I was simplifying I did.
The callbacks for those actions used char* instead of the iterator type I was using.
You can try making sure that your semantic actions were polymorphic on the type of the argument. Precisely in code you'd want something like this:
struct my_action {
template <class ParamType>
void operator()(ParamType const & parameter) const {
// deal with parameter
}
};
You'd use a unary semantic action like this as shown below:
real_p[my_action()]
Or if you needed a binary semantic action, you'd do something like:
struct binary_action {
template <class ParamType>
void operator()(ParamType const & param1, ParamType const & param2) const {
// deal with either parameter
}
};
(*char_p)[binary_action()]