//#define BOOST_SPIRIT_DEBUG #include #include #include #include #include #include #include namespace std { namespace chrono { // for debug std::ostream& operator<<(std::ostream& os, duration d) { return os << d.count() << "s"; } } } namespace AST { using clock = std::chrono::high_resolution_clock; struct TimeSample { enum Direction { up, down } direction; // + or - clock::duration value; // for debug: friend std::ostream& operator<<(std::ostream& os, Direction d) { char const* signs[] = {"+","-"}; return os << signs[d]; } friend std::ostream& operator<<(std::ostream& os, TimeSample const& sample) { return os << sample.direction << std::chrono::duration(sample.value).count() << "s"; } }; struct Record { std::string prefix; // "^+" std::string fqdn; // "line-17532.dyn.kponet.fi" int a, b, c, d; // 2, 7, 377, 1 TimeSample primary, braced; clock::duration tolerance; }; } BOOST_FUSION_ADAPT_STRUCT(AST::Record, prefix, fqdn, a, b, c, d, primary, braced, tolerance) BOOST_FUSION_ADAPT_STRUCT(AST::TimeSample, direction, value) namespace parsing { namespace x3 = boost::spirit::x3; using namespace x3; struct directions : x3::symbols { directions() { add("+", AST::TimeSample::up)("-", AST::TimeSample::down); } } direction_; struct units : x3::symbols { units() { using namespace std::literals::chrono_literals; add("s", 1s)("ms", 1ms)("us", 1us)("µs", 1us)("ns", 1ns); } } units_; auto const calc_duration = [](auto& ctx) { using boost::fusion::at_c; auto attr = x3::_attr(ctx); x3::_val(ctx) = at_c<0>(attr) * at_c<1>(attr); }; auto const duration_ = rule {} = (long_ >> units_) [calc_duration]; auto const tolerance_//= rule {} = "+/-" >> duration_; auto const sample_ = rule {} = direction_ >> duration_; auto const fqdn_ = lexeme[+graph]; // or whatever additional constraints you have auto const prefix_ = lexeme[string("^+")]; // or whatever you need to match here auto const record_ = prefix_ >> fqdn_ >> int_ >> int_ >> int_ >> int_ >> sample_ >> '[' >> sample_ >> ']' >> tolerance_; auto const start = skip(blank) [record_]; } int main() { std::istringstream iss(R"(^+ line-17532.dyn.kponet.fi 2 7 377 1 +1503us[+9103us] +/- 55ms )"); std::string line; while (getline(iss, line)) { auto f = line.cbegin(), l = line.cend(); AST::Record record; if (parse(f, l, parsing::start, record)) std::cout << "parsed: " << boost::fusion::as_vector(record) << "\n"; else std::cout << "parse error\n"; if (f!=l) std::cout << "remaining unparsed input: '" << std::string(f,l) << "'\n"; } }