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

Henri Menke <[email protected]> Tue, 19 Nov 2019 20:17:15 +1300
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
Here is an alternative suggestion based on an answer by Seth on SO.
To this end I had to abandon the rule

    (('=' >> bool_[bold]) | attr(true)[bold])

and replaced it with just

    '=' >> bool_

together with setting those values to true in the default constructor.
This makes more sense to me and also keep the grammar much cleaner.

Cheers, Henri

---

#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 = true;
     bool italic = true;
     bool strike = true;
     size_t id = 0;
};

BOOST_FUSION_ADAPT_STRUCT(font, face_name, point, bold, italic, strike, id)

namespace parsers {

// Thanks to the ingenious Seth!
// https://stackoverflow.com/a/49269239
auto const font_parser = boost::spirit::x3::rule<class _, font>{"font"} = [] {
    using namespace boost::spirit::x3;

    auto set = [](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 ")];

    return lit("font(") >> set(&font::face_name, words)
    >> *(
        ';'
        >> (
              lit("size") >> set(&font::point, '=' >> int_)
            | lit("bold") >> set(&font::bold, '=' >> bool_)
            | lit("italic") >> set(&font::italic, '=' >> bool_)
            | lit("strike") >> set(&font::strike, '=' >> bool_)
        )
    );
}();

}

int main() {
     font afont;
     std::string target;
     std::string test_str("font(Times New Roman;size=12;bold=true;italic);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;
}

On 11/19/19 2:40 PM, Dan Bloomquist wrote:
> Dan Bloomquist wrote:
>> I started here. ...
> 
> I'm gathering, even if I could not find it, that any semantic action 
> will kill attribute propagation globally for the given target. At least, 
> that is what I'm seeing. So, I just did it all with SA. The part where I 
> make '= true/false' is verbose, I'm working on that. But this works.
> Best, 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;
> };
> namespace parsers {
>      using namespace boost::spirit::x3;
>      auto const face = [](auto& attr) { _val(attr).face_name = 
> _attr(attr); };
>      auto const point = [](auto& attr) { _val(attr).point = _attr(attr); };
>      auto const bold = [](auto& attr) { _val(attr).bold = _attr(attr); };
>      auto const italic = [](auto& attr) { _val(attr).italic = 
> _attr(attr); };
>      auto const strike = [](auto& attr) { _val(attr).strike = 
> _attr(attr); };
> 
>      auto word = lexeme[+char_("a-zA-Z")];
>      auto words = lexeme[+char_("a-zA-Z ")];
> 
>      auto font_parser = rule<struct _, font>() =
>          lit("font(") >> words[face] >>
>          *(
>              lit("size") >> '=' >> int_[point]
>              | lit("bold") >> (('=' >> bool_[bold]) | attr(true)[bold])
>              | lit("italic") >> (('=' >> bool_[italic]) | 
> attr(true)[italic])
>              | lit("strike") >> (('=' >> bool_[strike]) | 
> attr(true)[strike])
>              ) % ';';
> }
> int main() {
>      font afont;
>      std::string target;
>      std::string test_str("font(Times New 
> Roman;size=12;bold=true;italic);circle");
>      auto begin = test_str.begin();
>     phrase_parse(begin, test_str.end(), parsers::font_parser, 
> boost::spirit::x3::space, afont);
>      return 0;
> }
> 
> 
> _______________________________________________
> Spirit-general mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/spirit-general
> 


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