Re: Parse succeeds, but doesn't propagate to first attribute with extra actions.

Dan Bloomquist <[email protected]> Fri, 22 Nov 2019 09:58:45 -0800
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
Henri Menke wrote:
> Dear Dan,
>
> However, I think your code is not as concise as it could be.  I suggest
> you keep using the `set' lambda in all the places and complement it with
> a `set_or' lambda which either sets the member to the attribute of the
> parser or a default value.
>
Hi Henri,
Yes, I like what you did there. Much better.

> I also don't see why you reverted to `words[face]' instead of
> `set(&font::face_name, words)' which I find much cleaner.

I had done that, but you've made it easier with your contribution.

>
> Probably you could also use the expectation operator `>' in more places
> to minimize backtracking for faster parsing and earlier error reporting.

I have more to learn. At that, I've re-watched Joel's talk.
<https://www.youtube.com/watch?v=XZKZZy_v7hE>
A while back, I actually added some attribute handling to the toy parser 
as an exercise. But I've slept since then!
Below is where I'm at now, I've cleaned up the testing stuff. Using a 
qualified main parser may be over kill now, but I think it will make my 
life easier as this thing evolves and more disjointed attributes are 
added. If you have any thoughts, I would love to hear them.
Thank you, Dan.

#include <iostream>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>

struct font {
     std::string face_name;
     size_t point = 0;
     bool bold = false;
     bool italic = false;
     bool strike = false;
     size_t id = 0;
};

struct rpt_header_item {
     std::string text;
     size_t tab_pos;
     bool angle = false;
};
BOOST_FUSION_ADAPT_STRUCT(rpt_header_item, text, angle)
using rpt_header_set_type = std::vector<rpt_header_item>;

struct rpt_headers_set {
     using iterator = rpt_header_set_type::iterator;
     using value_type = rpt_header_item;//for x3
     rpt_header_set_type set;
     //Tabs tabs;
     size_t size() { return set.size(); }
     void insert(iterator, const rpt_header_item& hdr) { 
set.push_back(hdr); }
     void push_back(const rpt_header_item& hdr) { set.push_back(hdr); }
     iterator begin() { return set.begin(); }
     iterator end() { return set.end(); }
     //void set_metric(LPRECT rect, CDC* pDC) { tabs.set_metric(rect, 
pDC); }
};

//for one attribute criterion
struct composition {
     composition(font& af, rpt_headers_set& hs) :afont(af), hset(hs) {}
     font& afont;
     rpt_headers_set& hset;
};


namespace parsers {
     using namespace boost::spirit::x3;

     auto set_bool = [](auto at) {
         auto propagate = [at](auto ctx) {
             traits::move_to(_attr(ctx), _val(ctx).*(at)); };
         return (('=' >> bool_[propagate]) | attr(true)[propagate]);
     };
     auto set_val = [](auto member, auto p) {
         auto propagate = [member](auto& ctx) {
             traits::move_to(_attr(ctx), _val(ctx).*(member));
         };
         return as_parser(-lit('=') >> p)[propagate];
     };
     auto const words = lexeme[+char_("a-zA-Z ")];
     auto const quoted_words = '"' >> words >> '"';

     auto const htext = [](auto& ctx) { _val(ctx).text += '\t' + 
_attr(ctx); };
     auto const header_parser = boost::spirit::x3::rule<class _, 
rpt_header_item>{ "header" } = [] {
         return *(quoted_words[htext] % ',')
             >> *(',' >> (
                 lit("tab") >> set_val(&rpt_header_item::tab_pos, int_)
                 | lit("angle") >> set_bool(&rpt_header_item::angle)
                 )
                 ) >> ')';
     }();
     auto const font_parser = boost::spirit::x3::rule<class _, font>{ 
"font" } = [] {
         return set_val(&font::face_name, words)
             >> *(',' >> (
                 lit("size") >> set_val(&font::point, int_)
                 | lit("bold") >> set_bool(&font::bold)
                 | lit("italic") >> set_bool(&font::italic)
                 | lit("strike") >> set_bool(&font::strike)
                 )
                 ) >> ')';
     }();

     struct comp_parser : parser<comp_parser> {
         comp_parser() {}

         template<typename Iterator, typename Context, typename 
RContext, typename Attribute>
         bool parse(Iterator& first, Iterator const& last, Context 
const& context,
             RContext const& rcontext, Attribute& attr) const
         {
             skip_over(first, last, context);
             Iterator save = first;
             auto parse = [&first,last](auto& parser, auto& attr) 
{return phrase_parse(first, last, parser, space, attr); };

             auto const tp = lit("headers") >>
                 *(lit("item") >> lit('(') >> header_parser);
             return parse(tp, attr.hset);
         }
     };
     auto const the_parse = parsers::comp_parser{};
}

//test and print............
std::ostream& operator << (std::ostream& os, /*const*/ font& afont) {
     return os << '\n' << std::boolalpha
         << "face_name = " << afont.face_name << '\n'
         << "point     = " << afont.point << '\n'
         << "bold      = " << afont.bold << '\n'
         << "italic    = " << afont.italic << '\n'
         << "strike    = " << afont.strike << '\n';
}
std::ostream& operator << (std::ostream& os, /*const*/ rpt_header_item& 
hdr) {
     std::replace(hdr.text.begin(), hdr.text.end(), '\t', '*');
     return os << '\n' << std::boolalpha
         << "text    = " << hdr.text << '\n'
         << "tab     = " << hdr.tab_pos << '\n'
         << "angle   = " << hdr.angle << '\n';
}
std::ostream& operator << (std::ostream& os, /*const*/ rpt_headers_set& 
hdrs) {
     for (auto& item : hdrs)
         os << item;
     return os;
}
std::ostream& operator << (std::ostream& os, /*const*/ composition& comp) {
     return os << comp.afont << comp.hset << std::endl;
}
template<typename P, typename A>
bool test_parse(std::string in, P parser, A& attr) {
     std::cout << "testing:\n" << in << std::endl;
     auto begin(in.begin());
     bool r = phrase_parse(begin, in.end(), parser, 
boost::spirit::x3::space, attr);
     std::cout << attr << std::endl;
     return r;
}
// .............
const char* some_section = R";;(
headers
     item("Description","an other", tab=1000)
     item("the next one",tab=2000,angle)
     font(Times New Roman, italic, size=12, bold=false, strike=true)
body
);;";

int main() {
     using namespace parsers;

     rpt_header_item hitem;
     test_parse("text(\"A Single\", \"Header\", tab = 500)", "text(" >> 
header_parser, hitem);

     rpt_headers_set headers;
     test_parse(some_section, "headers" >> *("text(" >> header_parser), 
headers);

     font afont;
     test_parse("font(Times New Roman, italic, size=12, bold=false, 
strike=true)", "font(" >> font_parser, afont);

     {
         std::cout << "*****************testing the big 
one!********************\n";
         rpt_headers_set hs;
         font bfont;
         composition comp(bfont, hs);
         test_parse(some_section, the_parse, comp);
     }

     return 0;
}



_______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general