Skip to content

Instantly share code, notes, and snippets.

@jefftrull
Created April 11, 2015 21:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jefftrull/928eac7d47e61f5d9634 to your computer and use it in GitHub Desktop.
Save jefftrull/928eac7d47e61f5d9634 to your computer and use it in GitHub Desktop.
Demonstration of using a Qi symbol table with a Lex-based Spirit parser, case-insensitive
#include <string>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/lex_lexertl_position_token.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/algorithm/string/case_conv.hpp>
template<typename Lexer>
struct Tokens : boost::spirit::lex::lexer<Lexer>
{
Tokens() : kMode("set_mode"), modeName("[a-zA-Z][a-zA-Z]*")
{
using namespace boost::spirit::lex;
using namespace boost::phoenix;
using local_names::_a;
using boost::algorithm::to_lower;
this->self += kMode;
this->self +=
modeName[
let(_a = construct<std::string>(_start, _end)) [
bind(&to_lower<std::string>, ref(_a),
// must supply even defaulted arguments
construct<std::locale>()),
_val = _a
]
];
this->self += ':';
}
boost::spirit::lex::token_def<std::string> kMode, modeName;
};
using namespace boost::spirit;
typedef istream_iterator BaseIter;
typedef lex::lexertl::position_token<BaseIter,
boost::mpl::vector<std::string> > TokenType;
typedef lex::lexertl::actor_lexer<TokenType> Lexer;
int main() {
typedef qi::symbols<char, int> symtab_t;
// disambiguate call to symbols::find
typedef const symtab_t::value_type * (symtab_t::*findfn_t)(std::string const&) const;
symtab_t mode_table;
mode_table.add("normal", 0)("lighten", 1)("darken", 2);
typedef Tokens<Lexer> TokenDefType;
typedef TokenDefType::iterator_type Iterator;
TokenDefType tok;
using namespace boost::phoenix;
qi::rule<Iterator, locals<int const*>, int()> modename;
modename = tok.modeName[_a = bind(static_cast<findfn_t>(&symtab_t::find),
cref(mode_table), _1),
_pass = _a,
if_(_a)[_val = *_a]];
qi::rule<Iterator, int()> mode = omit[tok.kMode] >> ':' >> modename;
std::stringstream testinp("set_mode:Lighten");
testinp.unsetf(std::ios::skipws);
istream_iterator beg(testinp), end;
int i;
if (tokenize_and_parse(beg, end, tok, mode, i)) {
std::cout << "mode=" << i << std::endl;
} else {
std::cout << "parse failed" << std::endl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment