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

Dan Bloomquist <[email protected]> Tue, 19 Nov 2019 12:56:29 -0800
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
Henri Menke wrote:
...
Hi Henri,
Thank you very much for setting me on the way. I'm now much more 
comfortable with 'as_parser' and putting a parser in a lambda. Note that 
'true_parser' just parses. And yes, Seth is brilliant, I've learned very 
much from his posts.

//https://stackoverflow.com/a/49269239
It seems I had already voted that one up in the past. I just missed the treasure there on this endeavor. I just don't use spirit often enough to keep it all in my head. At that, I'm 68 so don't know how much mind is left. :)

The objective is that the user, as not a programmer, should get as much latitude as possible. Like in the case of fonts, the defaults are false and they can:
bold;
bold=true;
bold=false; //this is redundant as is the case for no bold defined.
size=12; //a value is required.

And, of course, they can put them in any order they would like. They just must lead with a font face or 'Default' for the globally used font.
This:
https://github.com/lakeweb/stuff/blob/master/void_method2.cpp

I've already plugged into my app and it is working nicely. This kind of parser is part of the support so a user has control over how their reports look without my hard-coding.

Best, Dan.

New code: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#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;
};

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

	auto true_parser = [](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('=' >> p)[propagate];
	};
	auto const words = lexeme[+char_("a-zA-Z ")];
	auto const face = [](auto& attr) { _val(attr).face_name = _attr(attr); };

	auto const font_parser = boost::spirit::x3::rule<class _, font>{ "font" } = [] {
		return lit("font(") >> words[face]
			>> *(
				';'
				>> (
					lit("size") >> set_val(&font::point, int_)
					| lit("bold") >> true_parser(&font::bold)
					| lit("italic") >> true_parser(&font::italic)
					| lit("strike") >> true_parser(&font::strike)
					)
				);
	}();
}

int main() {
	font afont;
	std::string target;
	std::string test_str("font(Times New Roman;italic;size=12;bold=false;strike=true);circle");
	auto begin = test_str.begin();
	phrase_parse(begin, test_str.end(), parsers::font_parser, boost::spirit::x3::space, afont);
	std::cout << std::boolalpha
		<< "face_name = " << afont.face_name << '\n'
		<< "point     = " << afont.point << '\n'
		<< "bold      = " << afont.bold << '\n'
		<< "italic    = " << afont.italic << '\n'
		<< "strike    = " << afont.strike << '\n';
	return 0;
}