Ticket #6770: debug_fail_testcase.cpp.corrected

File debug_fail_testcase.cpp.corrected, 3.9 KB (added by Jeff Trull <edaskel@…>, 10 years ago)

A revised example using the lexer token iterator instead, which produces the expected output (and does not vary with BOOST_SPIRIT_DEBUG)

Line 
1// test case for strange BOOST_SPIRIT_DEBUG interaction for qi+lexer combination
2// My grammar contains a non-fatal bug. In the course of debugging it I found that
3// the parser behavior changes when BOOST_SPIRIT_DEBUG is defined, making it difficult
4// to debug.
5// Jeff Trull <edaskel@att.net>
6
7#include <sstream>
8#include <iostream>
9
10#include <boost/spirit/include/lex_lexertl.hpp>
11#include <boost/spirit/include/lex_lexertl_position_token.hpp>
12#include <boost/spirit/include/support_istream_iterator.hpp>
13
14// if this gets defined, my parse passes and all input is consumed
15#define BOOST_SPIRIT_DEBUG
16// if it is not defined, my parse passes but not all input is consumed
17#include <boost/spirit/include/qi.hpp>
18#include <boost/spirit/include/phoenix.hpp>
19#include <boost/lexical_cast.hpp>
20
21
22// typedef for stream iterator we will use
23typedef boost::spirit::istream_iterator LefDefIter;
24// lexer needs the iterator type and a list of token attribute types
25typedef boost::spirit::lex::lexertl::position_token<LefDefIter,
26 boost::mpl::vector<int, double, std::string> > LefDefToken;
27typedef boost::spirit::lex::lexertl::actor_lexer<LefDefToken> LefDefLexer;
28
29
30enum TokenIds {
31 T_NAMESCASESENSITIVE = 1000, T_ON, T_OFF, T_END,
32 T_ANY
33};
34
35template <typename Lexer>
36struct LefTokens : boost::spirit::lex::lexer<Lexer>
37{
38 LefTokens()
39 : double_("-?[0-9]+(\\.[0-9]+)?")
40 {
41 namespace lex = boost::spirit::lex;
42 using boost::phoenix::ref;
43
44 ident = "[a-zA-Z][a-zA-Z0-9_]+";
45
46 this->self =
47 lex::string("NAMESCASESENSITIVE", T_NAMESCASESENSITIVE)
48 | lex::string("ON", T_ON)
49 | lex::string("OFF", T_OFF)
50 | lex::string("END", T_END)
51 | ident
52 | double_
53 | '+' | '-' | '(' | ')' | ';'
54 ;
55
56 // whitespace
57 this->self += lex::string("([ \\t\\n]+)")
58 [
59 lex::_pass = lex::pass_flags::pass_ignore
60 ];
61
62 // catchall (mostly for error processing)
63 this->self += lex::string(".", T_ANY);
64
65 }
66
67 // identifiers have a string attribute
68 boost::spirit::lex::token_def<std::string> ident;
69 // numbers
70 boost::spirit::lex::token_def<double> double_;
71};
72
73template <typename Iterator, typename Lexer>
74struct lefparser : boost::spirit::qi::grammar<Iterator>
75{
76
77 template <typename TokenDef>
78 lefparser(TokenDef const& tok) : lefparser::base_type(lef_file)
79 {
80 namespace qi = boost::spirit::qi;
81 using boost::phoenix::ref; // for storing parsing info into parser var (instead of attributes)
82
83 // here's MY bug: ">" binds more tightly than "|"
84 // the ON/OFF options need parens
85 // it's in trying to debug this that I noticed the BOOST_SPIRIT_DEBUG problem
86 casesens = qi::raw_token(T_NAMESCASESENSITIVE) >
87 qi::raw_token(T_ON)[ref(case_on) = true] |
88 qi::raw_token(T_OFF)[ref(case_on) = false] > ';' ;
89
90 lef_file = -casesens >> -qi::raw_token(T_END) ;
91
92 BOOST_SPIRIT_DEBUG_NODE(casesens);
93 BOOST_SPIRIT_DEBUG_NODE(lef_file);
94 }
95 bool case_on;
96 boost::spirit::qi::rule<Iterator> lef_file;
97 boost::spirit::qi::rule<Iterator> casesens;
98};
99
100int main() {
101 LefTokens<LefDefLexer> lefTokens;
102 lefparser<LefTokens<LefDefLexer>::iterator_type, LefTokens<LefDefLexer>::lexer_def > lefParser(lefTokens);
103 std::stringstream testlef("NAMESCASESENSITIVE ON ;\nEND\n");
104 testlef.unsetf(std::ios::skipws);
105 LefDefIter beg(testlef), end;
106 LefTokens<LefDefLexer>::iterator_type it = lefTokens.begin(beg, LefDefIter());
107 LefTokens<LefDefLexer>::iterator_type lex_end = lefTokens.end();
108 if (!parse(it, lex_end, lefParser)) {
109 std::cerr << "parse failed\n";
110 return 1;
111 } else if (it != lex_end) {
112 std::cerr << "Not all input consumed. " << std::distance(it, lex_end) << " tokens remain:" << std::endl;
113 for (auto tok_it = it; tok_it != lex_end; ++tok_it) {
114 std::cerr << "|" << boost::get<boost::iterator_range<LefDefIter> >(tok_it->value()) << "|" << std::endl;
115 }
116 return 1;
117 }
118 std::cerr << "parse passed\n";
119 return 0;
120}