Part of a simple skeleton utility I’m hacking on I have a grammar for triggering substitutions in text. I thought it a wonderful way to get comfortable with Boost.Spirit, but the template errors are a joy of a unique kind.
Here is the code in its entirety:
#include <iostream>
#include <iterator>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace bsq = boost::spirit::qi;
namespace {
template<typename Iterator>
struct skel_grammar : public bsq::grammar<Iterator> {
skel_grammar();
private:
bsq::rule<Iterator> macro_b;
bsq::rule<Iterator> macro_e;
bsq::rule<Iterator, bsq::ascii::space_type> id;
bsq::rule<Iterator> macro;
bsq::rule<Iterator> text;
bsq::rule<Iterator> start;
};
template<typename Iterator>
skel_grammar<Iterator>::skel_grammar() : skel_grammar::base_type(start)
{
text = bsq::no_skip[+(bsq::char_ - macro_b)[bsq::_val += bsq::_1]];
macro_b = bsq::lit("<<");
macro_e = bsq::lit(">>");
macro %= macro_b >> id >> macro_e;
id %= -(bsq::ascii::alpha | bsq::char_('_'))
>> +(bsq::ascii::alnum | bsq::char_('_'));
start = *(text | macro);
}
} // namespace
int main(int argc, char* argv[])
{
std::string input((std::istreambuf_iterator<char>(std::cin)),
std::istreambuf_iterator<char>());
skel_grammar<std::string::iterator> grammar;
bool r = bsq::parse(input.begin(), input.end(), grammar);
std::cout << std::boolalpha << r << '\n';
return 0;
}
What’s wrong with this code?
Mmm. I feel that we have discussed a few more details in chat than have been reflected in the question as it is.
Let me entertain you with my ‘toy’ implementation, complete with test cases, of a grammar that will recognize
<<macros>>like this, including nested expansion of the same.Notable features:
process()), giving you maximum flexibility (you could use a look up table, cause parsing to fail depending on the macro content, or even have sideeffects independent of the outputspirit::istream_iteratoron how to parse input in streaming mode (Stream-based Parsing Made Easy). This has the obvious benefits if your input stream is 10 GB, and contains only 4 macros – it is the difference between crawling performance (or running out of memory) and just scaling.oss). You could, however, easily, hook the output directly tostd::coutor, say, anstd::ofstreaminstance<<or>>delimiters (#define SUPPORT_ESCAPES)Without further ado:
The Code
Note due to laziness, I require
-std==c++0x, but only whenSUPPORT_ESCAPESis definedThe Test Output
There is quite a lot of functionality hidden there to grok. I suggest you look at the test cases and the
process()callback alongside each other to see what is going on.Cheers & HTH 🙂