Last active
December 30, 2015 11:39
-
-
Save kwk/7823603 to your computer and use it in GitHub Desktop.
This parses a Person in the form "Some Name" 123 into a simple struct. `123` is the person's age. I know that his is overly complicated but I want to utilize the setter methods on the `Person` object to have more fine-grained control over the way my `Person` object is being modified. Here, this is just for showing how it can be done. Oh yeah, I …
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <string> | |
| #include <iostream> | |
| #include <utility> | |
| #include <boost/config/warning_disable.hpp> // Disable deprecated warnings on VC and Intel | |
| #include <boost/spirit/include/qi.hpp> // Parsing | |
| #include <boost/spirit/include/phoenix.hpp> // Semantic action | |
| #include <boost/fusion/adapted.hpp> // for BOOST_FUSION_ADAPT_STRUCT etc. | |
| #include <boost/fusion/container.hpp> | |
| struct Person; | |
| std::ostream & operator<<(std::ostream & out, const Person & person); | |
| struct Person { | |
| Person() | |
| : name() | |
| , age(0) | |
| { | |
| } | |
| void setName(const std::string & n) { name = n; } | |
| void setAge(const int & a) { age = a; } | |
| std::string name; | |
| int age; | |
| }; | |
| namespace fusion = boost::fusion; | |
| namespace phoenix = boost::phoenix; | |
| namespace qi = boost::spirit::qi; | |
| namespace ascii = boost::spirit::ascii; | |
| BOOST_FUSION_ADAPT_STRUCT( | |
| Person, | |
| (std::string, name) | |
| (int, age) | |
| ) | |
| template <typename Iterator> | |
| struct PersonSkipper : boost::spirit::qi::grammar<Iterator> | |
| { | |
| PersonSkipper() | |
| : PersonSkipper::base_type(start) | |
| , start() | |
| { | |
| namespace qi = boost::spirit::qi; | |
| namespace ascii = boost::spirit::ascii; | |
| ascii::space_type space; | |
| start = space; | |
| } | |
| boost::spirit::qi::rule<Iterator> start; | |
| }; | |
| template <typename Iterator> | |
| struct PersonGrammar : qi::grammar<Iterator, Person(), PersonSkipper<Iterator> > | |
| { | |
| PersonGrammar() | |
| : PersonGrammar::base_type(start_rule, "person") | |
| { | |
| using namespace qi::labels; | |
| start_rule = qi::eps[qi::_val = Person()] // initialize | |
| > name_rule(qi::_val) | |
| > age_rule(qi::_val); | |
| name_rule = quoted_string[phoenix::bind(&Person::setName, qi::_r1, qi::_1)]; | |
| age_rule = qi::int_[phoenix::bind(&Person::setAge, qi::_r1, qi::_1)]; | |
| quoted_string %= qi::lexeme['"' >> +(qi::char_ - '"') >> '"']; | |
| } | |
| qi::rule<Iterator, Person(), PersonSkipper<Iterator> > start_rule; | |
| qi::rule<Iterator, void(Person&), PersonSkipper<Iterator> > age_rule; | |
| qi::rule<Iterator, void(Person&), PersonSkipper<Iterator> > name_rule; | |
| qi::rule<Iterator, std::string(), PersonSkipper<Iterator> > quoted_string; | |
| }; | |
| //---------------------------------------------------------- | |
| // These functions are borrowed from boost itself | |
| //---------------------------------------------------------- | |
| template <typename Char, typename Parser> | |
| bool test(Char const* in, Parser const& p, bool full_match = true) | |
| { | |
| // we don't care about the result of the "what" function. | |
| // we only care that all parsers have it: | |
| boost::spirit::qi::what(p); | |
| Char const* last = in; | |
| while (*last) | |
| last++; | |
| return boost::spirit::qi::parse(in, last, p) | |
| && (!full_match || (in == last)); | |
| } | |
| template <typename Char, typename Parser, typename Skipper> | |
| bool test(Char const* in, Parser const& p | |
| , Skipper const& s, bool full_match = true) | |
| { | |
| // we don't care about the result of the "what" function. | |
| // we only care that all parsers have it: | |
| boost::spirit::qi::what(p); | |
| Char const* last = in; | |
| while (*last) | |
| last++; | |
| return boost::spirit::qi::phrase_parse(in, last, p, s) | |
| && (!full_match || (in == last)); | |
| } | |
| template <typename Char, typename Parser, typename Attr> | |
| bool test_attr(Char const* in, Parser const& p | |
| , Attr& attr, bool full_match = true) | |
| { | |
| // we don't care about the result of the "what" function. | |
| // we only care that all parsers have it: | |
| boost::spirit::qi::what(p); | |
| Char const* last = in; | |
| while (*last) | |
| last++; | |
| return boost::spirit::qi::parse(in, last, p, attr) | |
| && (!full_match || (in == last)); | |
| } | |
| template <typename Char, typename Parser, typename Attr, typename Skipper> | |
| bool test_attr(Char const* in, Parser const& p | |
| , Attr& attr, Skipper const& s, bool full_match = true) | |
| { | |
| // we don't care about the result of the "what" function. | |
| // we only care that all parsers have it: | |
| boost::spirit::qi::what(p); | |
| Char const* last = in; | |
| while (*last) | |
| last++; | |
| return boost::spirit::qi::phrase_parse(in, last, p, s, attr) | |
| && (!full_match || (in == last)); | |
| } | |
| //---------------------------------------------------------- | |
| //---------------------------------------------------------- | |
| /** | |
| * The main program tries to use the \a Person grammar as | |
| * a whole as well as each of its rules individually. | |
| * | |
| * Expect this output: | |
| * The person named "John Doe" is 66 years old. | |
| * The person named "" is 66 years old. | |
| * The person named "Some name nomatter how long" is 66 years old. | |
| */ | |
| int main(int argc, char **argv) | |
| { | |
| { // Test parsing a whole person object | |
| Person person; | |
| PersonGrammar<const char*> parser; | |
| PersonSkipper<const char*> skipper; | |
| test_attr("\"John Doe\" 66", parser, person, skipper); | |
| std::cout << person << std::endl; | |
| } | |
| { // Test parsing the age | |
| Person person; | |
| PersonGrammar<const char*> parser; | |
| PersonSkipper<const char*> skipper; | |
| test("66", parser.age_rule(phoenix::ref(person)), skipper); | |
| std::cout << person << std::endl; | |
| } | |
| { // Test parsing the name | |
| Person person; | |
| PersonGrammar<const char*> parser; | |
| PersonSkipper<const char*> skipper; | |
| test("\"Some name nomatter how long\"", parser.name_rule(phoenix::ref(person)), skipper); | |
| std::cout << person << std::endl; | |
| } | |
| return 0; | |
| } | |
| std::ostream & operator<<(std::ostream & out, const Person & person) | |
| { | |
| out << "The person named \"" << person.name << "\" is " << person.age << " years old." << std::endl; | |
| return out; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| project(inherited_attribute) | |
| cmake_minimum_required(VERSION 2.8) | |
| add_executable(inherited_attribute boost-spirit-inherited-attribute.cpp) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment