Boost Spirit Qi Custom Syntesized Attribute (Set a specific member of a struct attribute via a semantic action)

后端 未结 1 1179
北荒
北荒 2021-02-09 15:15

Suppose I have a structure that I want to parse into with Spirit Qi, that is defined as such:

struct data_
{
    bool export;
    std::wstring name;

    data_()         


        
相关标签:
1条回答
  • 2021-02-09 15:26

    How to set a struct member.

    Option 1 (phx::bind)

    Given a struct S

    struct S
    {
        int         field1;
        std::string field2;
        int         target_field;
        bool        field3;
    };
    

    You can assign to a field (e.g. target_field) like so:

    rule<It, S()> p = int_ [ phx::bind(&S::target_field, _val) = _1 ];
    

    Now, you can make the bind more readable, by doing something like:

    auto target_field_ = phx::bind(&S::target_field, _val);
    
    p = int_ [ target_field_ = _1 ];
    

    Proof of concept: live on Coliru

    #include "boost/spirit/include/qi.hpp"
    #include "boost/spirit/include/phoenix.hpp"
    
    namespace qi  = boost::spirit::qi;
    namespace phx = boost::phoenix;
    typedef std::string::const_iterator It;
    
    struct S
    {
        int         field1;
        std::string field2;
        int         target_field;
        bool        field3;
    };
    
    int main()
    {
        const std::string input("42");
        It f(begin(input)), l(end(input));
    
        S instance;
    
        using namespace qi;
        rule<It, S()> p = int_ [ phx::bind(&S::target_field, _val) = _1 ];
    
        // or, alternatively:
        auto target_field_ = phx::bind(&S::target_field, _val);
        p = int_ [ target_field_ = _1 ];
    
        if (parse(f, l, p, instance))
            std::cout << "Parsed: " << instance.target_field;
    }
    

    Option 2 (fusion sequences)

    You can treat a struct as a fusion sequence by using adaptation:

    #include "boost/fusion/adapted/struct.hpp"
    
    BOOST_FUSION_ADAPT_STRUCT(S, (int, field1)(std::string, field2)(int, target_field)(bool, field3))
    

    Now you can use phoenix lazy functions on these sequences in your semantic action:

    rule<It, S()> p = int_ [ phx::at_c<2>(_val) = _1 ];
    

    I don't prefer this style (because it 'degrades' an expressive struct to ... a tuple of sorts), but it might come in handy. Live on Coliru

    0 讨论(0)
提交回复
热议问题