I try to implement a Lexer for a little programming language with Boost Spirit.
I have to get the value of a token and I get a bad_get exception :
You can always use the 'default' token data (which is iterator_range of the source iterator type).
std::string tokenvalue(iter->value().begin(), iter->value().end());
After studying the test cases in the boost repository, I found out a number of things:
The cinch is that the token data is variant, which starts out as the raw input iterator range. Only after 'a' forced assignment, the converted attribute is cached in the variant. You can witness the transition:
lexer_type::iterator_type iter = lexer.begin(first, last);
lexer_type::iterator_type end = lexer.end();
assert(0 == iter->value().which());
std::cout << "Value = " << boost::get >(iter->value()) << std::endl;
std::string s;
boost::spirit::traits::assign_to(*iter, s);
assert(1 == iter->value().which());
std::cout << "Value = " << s << std::endl;
As you can see, the attribute assignment is forced here, directly using the assign_to
trait implementation.
Full working demonstration:
#include
#include
#include
namespace lex = boost::spirit::lex;
typedef std::string::iterator base_iterator_type;
typedef boost::spirit::lex::lexertl::token> Tok;
typedef lex::lexertl::actor_lexer lexer_type;
template
class SimpleLexer : public lex::lexer {
private:
public:
SimpleLexer() {
word = "[a-zA-Z]+";
integer = "[0-9]+";
literal = "...";
this->self += integer | literal | word;
}
lex::token_def word, literal;
lex::token_def integer;
};
int main(int argc, const char* argv[]) {
SimpleLexer lexer;
std::string contents = "void";
base_iterator_type first = contents.begin();
base_iterator_type last = contents.end();
lexer_type::iterator_type iter = lexer.begin(first, last);
lexer_type::iterator_type end = lexer.end();
assert(0 == iter->value().which());
std::cout << "Value = " << boost::get >(iter->value()) << std::endl;
std::string s;
boost::spirit::traits::assign_to(*iter, s);
assert(2 == iter->value().which());
std::cout << "Value = " << s << std::endl;
return 0;
}