Skip to content

Instantly share code, notes, and snippets.

@jefftrull
Created April 6, 2012 03:09
Show Gist options
  • Save jefftrull/2316495 to your computer and use it in GitHub Desktop.
Save jefftrull/2316495 to your computer and use it in GitHub Desktop.
Testcase for BOOST_SPIRIT_DEBUG changing lexer/parser behavior
#include <sstream>
#include <iostream>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/lex_lexertl_position_token.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
// if this gets defined, my parse passes and all input is consumed
// #define BOOST_SPIRIT_DEBUG
// if it is not defined, my parse passes but not all input is consumed
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/lexical_cast.hpp>
// typedef for stream iterator we will use
typedef boost::spirit::istream_iterator LefDefIter;
// lexer needs the iterator type and a list of token attribute types
typedef boost::spirit::lex::lexertl::position_token<LefDefIter,
boost::mpl::vector<int, double, std::string> > LefDefToken;
typedef boost::spirit::lex::lexertl::actor_lexer<LefDefToken> LefDefLexer;
enum TokenIds {
T_NAMESCASESENSITIVE = 1000, T_ON, T_OFF, T_END,
T_ANY
};
template <typename Lexer>
struct LefTokens : boost::spirit::lex::lexer<Lexer>
{
LefTokens()
: double_("-?[0-9]+(\\.[0-9]+)?")
{
namespace lex = boost::spirit::lex;
using boost::phoenix::ref;
ident = "[a-zA-Z][a-zA-Z0-9_]+";
this->self =
lex::string("NAMESCASESENSITIVE", T_NAMESCASESENSITIVE)
| lex::string("ON", T_ON)
| lex::string("OFF", T_OFF)
| lex::string("END", T_END)
| ident
| double_
| '+' | '-' | '(' | ')' | ';'
;
// whitespace
this->self += lex::string("([ \\t\\n]+)")
[
lex::_pass = lex::pass_flags::pass_ignore
];
// catchall (mostly for error processing)
this->self += lex::string(".", T_ANY);
}
// identifiers have a string attribute
boost::spirit::lex::token_def<std::string> ident;
// numbers
boost::spirit::lex::token_def<double> double_;
};
// for error handling
struct error_info_impl
{
// required by phoenix::function; gives signature
template <typename, typename>
struct result
{
typedef std::string type;
};
template<typename Iterator, typename What>
std::string operator()(Iterator const& actual_token_iter,
What const& what) const
{
return "Error! Expecting: " + boost::lexical_cast<std::string>(what) +
" but saw: " + std::string(actual_token_iter->matched().begin(),
actual_token_iter->matched().end());
}
};
template <typename Iterator, typename Lexer>
struct lefparser : boost::spirit::qi::grammar<Iterator>
{
template <typename TokenDef>
lefparser(TokenDef const& tok) : lefparser::base_type(lef_file)
{
namespace qi = boost::spirit::qi;
using boost::phoenix::ref; // for storing parsing info into parser var (instead of attributes)
// here's MY bug: ">" binds more tightly than "|"
// the ON/OFF options need parens
// it's in trying to debug this that I noticed the BOOST_SPIRIT_DEBUG problem
casesens = qi::raw_token(T_NAMESCASESENSITIVE) >
qi::raw_token(T_ON)[ref(case_on) = true] |
qi::raw_token(T_OFF)[ref(case_on) = false] > ';' ;
lef_file = -casesens >> -qi::raw_token(T_END) ;
BOOST_SPIRIT_DEBUG_NODE(casesens);
BOOST_SPIRIT_DEBUG_NODE(lef_file);
}
bool case_on;
boost::spirit::qi::rule<Iterator> lef_file;
boost::spirit::qi::rule<Iterator> casesens;
};
int main() {
LefTokens<LefDefLexer> lefTokens;
lefparser<LefTokens<LefDefLexer>::iterator_type, LefTokens<LefDefLexer>::lexer_def > lefParser(lefTokens);
std::stringstream testlef("NAMESCASESENSITIVE ON ;\nEND\n");
testlef.unsetf(std::ios::skipws);
LefDefIter beg(testlef), end;
LefTokens<LefDefLexer>::iterator_type it = lefTokens.begin(beg, LefDefIter());
LefTokens<LefDefLexer>::iterator_type lex_end = lefTokens.end();
if (!parse(it, lex_end, lefParser)) {
std::cerr << "parse failed\n";
return 1;
} else if (beg != end) {
std::cerr << "Not all input consumed. Remaining input:|";
std::copy(beg, end, std::ostream_iterator<char>(std::cerr));
std::cerr << "|\n";
return 1;
}
std::cerr << "parse passed\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment