Created
April 6, 2012 03:09
-
-
Save jefftrull/2316495 to your computer and use it in GitHub Desktop.
Testcase for BOOST_SPIRIT_DEBUG changing lexer/parser behavior
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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