The lexeme solution does work.
The no_skip
and lexeme
directive require that the contained parsers don't use a skipper, so you need to change Identifier
into
qi::rule<Iterator, std::string()> Identifier;
Incidentally, then lexeme
inside it becomes redundant:
qi::rule<It, std::string() > Identifier = qi::alpha >> *(qi::alnum | qi::char_("_"));
qi::rule<It, std::string(), qi::space_type> Label = qi::lexeme [ Identifier >> ':' ];
qi::rule<It, qi::space_type> Syntax = Label [ handle_label_(qi::_1) ];
In fact you can further reduce it (by relying on pre-skipping in the Syntax
rule):
static const rule<std::string::const_iterator, std::string()>
Identifier = alpha >> *(alnum | char_("_")),
Label = Identifier >> ':';
A full test program: See it Live on Coliru
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/phoenix/function/adapt_function.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
void handle_label(std::string const& s) { std::cout << "Parsed label '" << s << ":'\n"; }
BOOST_PHOENIX_ADAPT_FUNCTION(void, handle_label_, handle_label, 1)
bool using_lexeme(std::string const& input)
{
using namespace qi;
static const rule<std::string::const_iterator, std::string()>
Identifier = alpha >> *(alnum | char_("_")),
Label = Identifier >> ':';
auto f(input.begin()), l(input.end());
return phrase_parse(f, l, Label [ handle_label_(_1) ], space);
}
int main()
{
assert( using_lexeme("some_id:"));
assert( using_lexeme("some_id: "));
assert( using_lexeme(" some_id:"));
assert(!using_lexeme("some_id :"));
}
Two further notes:
no_skip
doesn't pre-skip either (lexeme
means more like "keep together"). Try the difference and see how the third test case would failYour use of
lit('_')
would prevent underscores from being appended to the string attribute.