// A parser for a comma separated list of numbers, // with positional error reporting #include #include #include #include "boost/spirit/include/classic_multi_pass.hpp" #include #include #include #include using namespace std; using namespace BOOST_SPIRIT_CLASSIC_NS; std::ostream & operator<<(std::ostream & out, file_position const & lc) { return out << "\nFile:\t" << lc.file << "\nLine:\t" << lc.line << "\nCol:\t" << lc.column << endl; } struct error_report_parser { char const * eol_msg; char const * msg; error_report_parser(char const * eol_msg_, char const * msg_) : eol_msg(eol_msg_), msg (msg_) { } typedef nil_t result_t; template int operator()(ScannerT const& scan, result_t& /*result*/) const { if (scan.at_end()) { if (eol_msg) { file_position fpos = scan.first.get_position(); cerr << fpos << eol_msg << endl; } } else { if (msg) { file_position fpos = scan.first.get_position(); cerr << fpos << msg << endl; } } return -1; // Fail. } }; typedef functor_parser error_report_p; error_report_p error_badnumber_or_eol = error_report_parser( "Expecting a number, but found the end of the file\n", "Expecting a number, but found something else\n" ); error_report_p error_badnumber = error_report_parser( 0, "Expecting a number, but found something else\n" ); error_report_p error_comma = error_report_parser( 0, "Expecting a comma, but found something else\n" ); bool parse_numbers(istream & istr, vector & v) { typedef multi_pass > multi_pass_stream_iterator; typedef position_iterator position_stream_iterator; multi_pass_stream_iterator multi_begin( make_multi_pass(istreambuf_iterator(istr))); multi_pass_stream_iterator multi_end( make_multi_pass(istreambuf_iterator())); position_stream_iterator pos_begin(multi_begin, multi_end, "internal string"); position_stream_iterator pos_end; pos_begin.set_tabchars(8); return parse(pos_begin, pos_end, // Begin grammar ( (real_p[push_back_a(v)] | error_badnumber) >> *( (',' | error_comma) >> (real_p[push_back_a(v)] | error_badnumber_or_eol) ) ) , // End grammar space_p).full; } int main(int argc, char **argv) { istringstream itest("0, 1, 2"); vector v; if (parse_numbers(itest, v)) { cout << "Parsing:\n"; cout << itest.str() << "\nParses OK: " << endl; for (vector::size_type i = 0; i < v.size(); ++i) cout << i << ": " << v[i] << endl; } else { cout << "Parsing failed\n"; } return 0; }