This is a followup question to Using boost::spirit::qi to parse numbers with separators.
Following sehe's very good suggestions, I managed to get number parsing to work. I then attempted to update it to have a secondary parser which handled numbers with an optional sign. This second attempt failed. I suspect I have dome something incorrect with respect to how to handle a sub-grammar. Code is as follows:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
template <typename Iterator, typename Num>
struct unsigned_parser : qi::grammar<Iterator, Num()> {
unsigned_parser() : unsigned_parser::base_type(start) {
using qi::_val;
using qi::_1;
using qi::eps;
using qi::debug;
using ascii::char_;
bin = eps[_val=0] >> *(char_("01")[_val = _val * 2 + dval(_1)] | '_');
oct = eps[_val=0] >> *(char_("0-7")[_val = _val * 8 + dval(_1)] | '_');
dec = eps[_val=0]
>> *(char_("0-9")[_val = _val * 10 + dval(_1)] | '_');
hex = eps[_val=0]
>> *(char_("0-9a-fA-F")[_val = _val * 16 + dval(_1)] | '_');
start = (char_('0') >>
((char_("xXhH") >> hex[_val=_1])
| (char_("bByY") >> bin[_val=_1])
| (char_("oOqQ") >> oct[_val=_1])
| (char_("dDtT") >> dec[_val=_1])))
| (hex[_val=_1] >> char_("xXhH"))
| (bin[_val=_1] >> char_("bByY"))
| (oct[_val=_1] >> char_("oOqQ"))
| (dec[_val=_1] >> -char_("dDtT"));
start.name("unum");
hex.name("hex");
oct.name("oct");
dec.name("dec");
bin.name("bin");
debug(start);
debug(hex);
debug(oct);
debug(dec);
debug(bin);
}
qi::rule<Iterator, Num()> start;
qi::rule<Iterator, Num()> hex;
qi::rule<Iterator, Num()> oct;
qi::rule<Iterator, Num()> dec;
qi::rule<Iterator, Num()> bin;
struct _dval {
template <typename> struct result { typedef uint8_t type; };
template <typename T> uint8_t operator()(T ch) const {
if (ch >= '0' || ch <= '9') {
return ch - '0';
}
ch = std::tolower(ch);
if (ch >= 'a' || ch <= 'f') {
return ch - 'a' + 10;
}
assert(false);
}
};
boost::phoenix::function<_dval> dval;
};
template <typename Iterator, typename Num>
struct signed_parser : qi::grammar<Iterator, Num()> {
signed_parser() : signed_parser::base_type(start) {
using qi::eps;
using qi::_val;
using qi::_1;
using ascii::char_;
using phoenix::static_cast_;
unum = unsigned_parser<Iterator, Num>();
start = (char_('-') >> unum[_val=-_1])
| (-char_('+') >> unum[_val=_1]);
unum.name("unum");
start.name("snum");
debug(start);
/* debug(unum); */
}
qi::rule<Iterator, Num()> start;
qi::rule<Iterator, Num()> unum;
};
int main(int argv, const char *argc[]) {
using phoenix::ref;
using qi::eoi;
using qi::_1;
typedef std::string::const_iterator iter;
signed_parser<iter, int64_t> sp;
int64_t val;
if (argv != 2) {
std::cerr << "Usage: " << argc[0] << " <input>" << std::endl;
return 1;
}
std::string test(argc[1]);
iter i = test.begin();
iter end = test.end();
bool rv = phrase_parse(i, end, sp[ref(val)=_1] >> eoi, ascii::space);
if (rv) {
assert(i == end);
std::cout << "Succeeded: " << val << std::endl;
return 0;
}
std::cout << "Failed." << std::endl;
return 1;
}
With the signed_parser, every parse fails. Moreover, if I uncomment the commented-out debug(), the program segfaults.
I feel as if I am close to beginning to understand how to use this, so any help would be appreciated.