Исходя из моего более раннего ответа , где я показал подход, обмениваясь ссылками, я упростил этот ответ до следующего:
template <typename Iterator>
struct document_parser : qi::grammar<Iterator, document()> {
document_parser() : document_parser::base_type{start_}
{
using namespace qi;
line_ = 'L' >> auto_;
box_ = 'B' >> auto_;
circle_ = 'S' >> auto_;
// text = 'T' >> ...;
element_ = (line_ | box_ | circle_ | composite_element_) >> eol;
elements_ = -skip(space) [ '[' >> skip(blank) [*element_] >> ']' ];
composite_element_ = 'C' >> int_ >> int_ >> lexeme[+graph] >> elements_;
document_ = +element_ >> eoi;
start_ = skip(blank) [ document_ ];
BOOST_SPIRIT_DEBUG_NODES((document_)(element_)(composite_element_)(elements_)(line_));
}
private:
qi::rule<Iterator, document()> start_;
qi::rule<Iterator, document(), qi::blank_type> document_;
qi::rule<Iterator, element(), qi::blank_type> element_;
qi::rule<Iterator, line(), qi::blank_type> line_;
qi::rule<Iterator, box(), qi::blank_type> box_;
qi::rule<Iterator, circle(), qi::blank_type> circle_;
qi::rule<Iterator, composite_component(), qi::blank_type> composite_element_;
qi::rule<Iterator, std::vector<element>(), qi::blank_type> elements_;
};
Обратите внимание, что теперь он также разбирает прямоугольники и кружки.Вы можете прочитать о Автоматический парсер для этой магии.
Посмотреть Live On Wandbox
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct line { int x1, y1, x2, y2, color, width, capstyle, dashstyle, dashlength, dashspace; };
struct box { int x, y, width, height, color, line_width, capstyle, dashstyle, dashlength, dashspace, filltype, fillwidth, angle1, pitch1, angle2, pitch2; };
struct circle { int x, y, radius, color, line_width, capstyle, dashstyle, dashlength; };
struct text { int x, y, color, size, visibility, show_name_value, angle, alignment, num_lines;
std::vector<std::string> lines;
};
struct composite_component;
using element_t = boost::variant<line, box, circle, text, boost::recursive_wrapper<composite_component>>;
struct element {
// ...
element_t element;
};
struct composite_component {
int x;
int y;
std::string basename;
std::vector<element> elements;
};
struct document { std::vector<element> elements; };
BOOST_FUSION_ADAPT_STRUCT(line, x1, y1, x2, y2, color, width, capstyle, dashstyle, dashlength, dashspace)
BOOST_FUSION_ADAPT_STRUCT(box, x, y, width, height, color, line_width, capstyle, dashstyle, dashlength, dashspace, filltype, fillwidth, angle1, pitch1, angle2, pitch2)
BOOST_FUSION_ADAPT_STRUCT(circle, x, y, radius, color, line_width, capstyle, dashstyle, dashlength)
BOOST_FUSION_ADAPT_STRUCT(text, x, y, color, size, visibility, show_name_value, angle, alignment, num_lines, lines)
BOOST_FUSION_ADAPT_STRUCT(composite_component, x, y, basename, elements)
BOOST_FUSION_ADAPT_STRUCT(element, element)
BOOST_FUSION_ADAPT_STRUCT(document, elements)
template <typename Iterator>
struct document_parser : qi::grammar<Iterator, document()> {
document_parser() : document_parser::base_type{start_}
{
using namespace qi;
line_ = 'L' >> auto_;
box_ = 'B' >> auto_;
circle_ = 'S' >> auto_;
// text = 'T' >> ...;
element_ = (line_ | box_ | circle_ | composite_element_) >> eol;
elements_ = -skip(space) [ '[' >> skip(blank) [*element_] >> ']' ];
composite_element_ = 'C' >> int_ >> int_ >> lexeme[+graph] >> elements_;
document_ = +element_ >> eoi;
start_ = skip(blank) [ document_ ];
BOOST_SPIRIT_DEBUG_NODES((document_)(element_)(composite_element_)(elements_)(line_)(box_)(circle_));
}
private:
qi::rule<Iterator, document()> start_;
qi::rule<Iterator, document(), qi::blank_type> document_;
qi::rule<Iterator, element(), qi::blank_type> element_;
qi::rule<Iterator, line(), qi::blank_type> line_;
qi::rule<Iterator, box(), qi::blank_type> box_;
qi::rule<Iterator, circle(), qi::blank_type> circle_;
qi::rule<Iterator, composite_component(), qi::blank_type> composite_element_;
qi::rule<Iterator, std::vector<element>(), qi::blank_type> elements_;
};
int main(int , char **) {
document_parser<std::string::const_iterator> parser;
const std::string text = // "v 20180904 2\n"
"L 1 2 3 4 5 6 7 8 9 10\n"
"C 10 10 FOO\n"
"[ "
" L 10 20 30 40 50 60 70 80 90 100\n"
"]\n";
document doc;
bool r = qi::parse(text.cbegin(), text.cend(), parser, doc);
std::cout << (r ? "OK" : "FAIL") << std::endl;
}
Печать
OK
И отладочный вывод:
<document_>
<try>L 1 2 3 4 5 6 7 8 9 </try>
<element_>
<try>L 1 2 3 4 5 6 7 8 9 </try>
<line_>
<try>L 1 2 3 4 5 6 7 8 9 </try>
<success>\nC 10 10 FOO\n[ L</success>
<attributes>[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]</attributes>
</line_>
<success>C 10 10 FOO\n[ L </success>
<attributes>[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]]</attributes>
</element_>
<element_>
<try>C 10 10 FOO\n[ L </try>
<line_>
<try>C 10 10 FOO\n[ L </try>
<fail/>
</line_>
<box_>
<try>C 10 10 FOO\n[ L </try>
<fail/>
</box_>
<circle_>
<try>C 10 10 FOO\n[ L </try>
<fail/>
</circle_>
<composite_element_>
<try>C 10 10 FOO\n[ L </try>
<elements_>
<try>\n[ L 10 20 30 40</try>
<element_>
<try> L 10 20 30 40 5</try>
<line_>
<try> L 10 20 30 40 5</try>
<success>\n]\n</success>
<attributes>[[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]</attributes>
</line_>
<success>]\n</success>
<attributes>[[[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]]</attributes>
</element_>
<element_>
<try>]\n</try>
<line_>
<try>]\n</try>
<fail/>
</line_>
<box_>
<try>]\n</try>
<fail/>
</box_>
<circle_>
<try>]\n</try>
<fail/>
</circle_>
<composite_element_>
<try>]\n</try>
<fail/>
</composite_element_>
<fail/>
</element_>
<success>\n</success>
<attributes>[[[[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]]]</attributes>
</elements_>
<success>\n</success>
<attributes>[[10, 10, [F, O, O], [[[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]]]]</attributes>
</composite_element_>
<success></success>
<attributes>[[[10, 10, [F, O, O], [[[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]]]]]</attributes>
</element_>
<element_>
<try></try>
<line_>
<try></try>
<fail/>
</line_>
<box_>
<try></try>
<fail/>
</box_>
<circle_>
<try></try>
<fail/>
</circle_>
<composite_element_>
<try></try>
<fail/>
</composite_element_>
<fail/>
</element_>
<success></success>
<attributes>[[[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]], [[10, 10, [F, O, O], [[[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]]]]]]]</attributes>
</document_>