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