Boost spirit parse integer for custom list template

I have a problem with boost spirit for parsing a file:

int [int, int, int] [ int, int] ... 

Nothing complicated, the following grammar works for this:

 template<typename Iterator> struct parser_expression : qi::grammar<Iterator,ascii::space_type> { parser_expression() : parser_expression::base_type(start) { using qi::double_; using qi::int_; using boost::spirit::qi::char_; using qi::alpha; using qi::alnum; using qi::digit; using qi::eps; using qi::_val; using boost::phoenix::bind; start = int_ >> list1 >> list2 >> char_('='); list1 = ('[' >> int_ >> *(char_(',') >> int_ ) >> char_(']')) | (char_('[') >> char_(']')); list2 = ('[' >> int_ >> *(char_(',') >> int_ ) >> char_(']')) | -(char_('[') >> char_(']')); } qi::rule<Iterator,ascii::space_type> start; qi::rule<Iterator,ascii::space_type> list1; qi::rule<Iterator,ascii::space_type> list2; }; 

My problem is that I need to save the result of the parsing. For example, I need to save list1 and list2 from int to a custom list template:

 template <typename T> class SimpleLinkList { private: ChainLink<T>* head; ... } 

where is chainlink:

 template<typename T> class ChainLink { private: T object; ChainLink* next; ... } 

I have a pushback method in SimpleLinkList as a vector, but I don’t understand how to parse an int, save it in ChainLink and add it to SimpleLinkList.

I already saw how to adapt the template structure to the merge sequence at http://boost-spirit.com/home/2010/02/08/how-to-adapt-templates-as-a-fusion-sequence/ .

I need a custom LinkList to be able to remove and add items during a loop.

I need help to understand how I can organize all this to successfully parse my file.

Thanks for your help.

+4
source share
1 answer

You are probably looking for container attribute settings points:

For your type, it will look like this:

 namespace boost { namespace spirit { namespace traits { template <typename T> struct container_value<SimpleLinkList<T>, void> { typedef T type; }; template <typename T> struct push_back_container<SimpleLinkList<T>, T, void> { static bool call(SimpleLinkList<T>& c, T const& val) { c.push_back(val); return true; } }; }}} 

Simple demo (using the dummy implementation of SimpleLinkList ):

 struct AbstractDataType { int number; SimpleLinkList<int> list1, list2; }; BOOST_FUSION_ADAPT_STRUCT(AbstractDataType, (int, number)(SimpleLinkList<int>, list1)(SimpleLinkList<int>, list2)) template<typename Iterator> struct parser_expression : qi::grammar<Iterator, AbstractDataType(), qi::space_type> { parser_expression() : parser_expression::base_type(start) { list = '[' >> -(qi::int_ % ',') >> ']'; start = qi::int_ >> list >> -list >> '='; BOOST_SPIRIT_DEBUG_NODES((list)(start)) } qi::rule<Iterator, AbstractDataType(), qi::space_type> start; qi::rule<Iterator, SimpleLinkList<int>(), qi::space_type> list; }; 

Note

  • I replaced qi::char_ with (implicit) qi::lit where possible, because you actually don't want to parse punctuation characters in an attribute (right?)
  • I used the list parser operator % instead of an extended alternative
  • I used the parser operator - to make the list of elements optional (allow null elements)
  • Similarly, list >> -list is used to make the second list optional together.

The following test files:

 void test(const std::string input) { static const parser_expression<std::string::const_iterator> p; AbstractDataType parsed; auto f(input.begin()), l(input.end()); bool ok = qi::phrase_parse(f, l, p, qi::space, parsed); if (ok) std::cout << "Result: " << parsed.number << " " << parsed.list1 << parsed.list2 << "\n"; else std::cout << "Parse failed\n"; if (f!=l) std::cout << "Unparsed: '" << std::string(f,l) << "'\n"; } int main() { test("1 [2, 3, 4] [5, 6] ="); test("2 [] [6, 7] ="); test("3 [4, 5, 6] [ ] ="); test("4 [5, 6, 7] ="); } 

Print the output:

 Result: 1 [2 3 4 ][5 6 ] Result: 2 [][6 7 ] Result: 3 [4 5 6 ][] Result: 4 [5 6 7 ][] 

See all integrated: http://ideone.com/odqhBz . Link Prevention:

 // #define BOOST_SPIRIT_DEBUG #include <boost/fusion/adapted.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp> namespace qi = boost::spirit::qi; template <typename T> struct ChainLink; template <typename T> class SimpleLinkList { public: void push_back(T const& v) { /* todo */ _for_debug.push_back(v); } std::list<int> _for_debug; friend std::ostream& operator<<(std::ostream& os, SimpleLinkList const& list) { os << "["; std::copy(list._for_debug.begin(), list._for_debug.end(), std::ostream_iterator<T>(os, " ")); return os << "]"; } private: ChainLink<T>* head; }; namespace boost { namespace spirit { namespace traits { template <typename T> struct container_value<SimpleLinkList<T>, void> { typedef T type; }; template <typename T> struct push_back_container<SimpleLinkList<T>, T, void> { static bool call(SimpleLinkList<T>& c, T const& val) { c.push_back(val); return true; } }; }}} struct AbstractDataType { int number; SimpleLinkList<int> list1, list2; }; BOOST_FUSION_ADAPT_STRUCT(AbstractDataType, (int, number)(SimpleLinkList<int>, list1)(SimpleLinkList<int>, list2)) template<typename Iterator> struct parser_expression : qi::grammar<Iterator, AbstractDataType(), qi::space_type> { parser_expression() : parser_expression::base_type(start) { list = '[' >> -(qi::int_ % ',') >> ']'; start = qi::int_ >> list >> -list >> '='; BOOST_SPIRIT_DEBUG_NODES((list)(start)) } qi::rule<Iterator, AbstractDataType(), qi::space_type> start; qi::rule<Iterator, SimpleLinkList<int>(), qi::space_type> list; }; void test(const std::string input) { static const parser_expression<std::string::const_iterator> p; AbstractDataType parsed; auto f(input.begin()), l(input.end()); bool ok = qi::phrase_parse(f, l, p, qi::space, parsed); if (ok) std::cout << "Result: " << parsed.number << " " << parsed.list1 << parsed.list2 << "\n"; else std::cout << "Parse failed\n"; if (f!=l) std::cout << "Unparsed: '" << std::string(f,l) << "'\n"; } int main() { test("1 [2, 3, 4] [5, 6] ="); test("2 [] [6, 7] ="); test("3 [4, 5, 6] [ ] ="); test("4 [5, 6, 7] ="); } 
+2
source

Source: https://habr.com/ru/post/951438/


All Articles