How do I capture the original input into the synthesized output from a spirit grammar?

后端 未结 3 1425
日久生厌
日久生厌 2021-01-06 22:14

I\'m working on a boost::spirit::qi::grammar and would like to copy a portion of the original text into the synthesized output structure of the grammar (more specifically, t

3条回答
  •  刺人心
    刺人心 (楼主)
    2021-01-06 22:56

    Something similar to what you asked without using semantic actions:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    namespace qi = boost::spirit::qi;
    using boost::spirit::repository::qi::iter_pos;
    
    struct ints_type
    {
       std::vector data;
       std::string::const_iterator begin;
       std::string::const_iterator end;   
    };
    
    struct A
    {
        std::string header;
        ints_type ints;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(
        ints_type,
        (std::string::const_iterator, begin)
        (std::vector, data)
        (std::string::const_iterator, end)
    )
    
    BOOST_FUSION_ADAPT_STRUCT(
         A,
         (std::string, header)
         (ints_type, ints)
    )
    
    template 
    struct parser : qi::grammar< Iterator, A() >
    {
        parser() : parser::base_type(start)
        {
            header %= qi::lexeme[ +qi::alpha ];
            ints %= qi::lexeme[ iter_pos >> qi::int_ % qi::char_(",_") >> iter_pos ]; // <---- capture the original text that matches this into inttext
            start %= header >> ' ' >> ints;
        }
    
        qi::rule header;
        qi::rule ints;
        qi::rule start;
    };
    
    int main()
    {
        A output;
        std::string input("out 1,2_3");
        auto iter = input.begin();
        parser p;
        bool r = qi::parse(iter, input.end(), p, output);
        if( !r || iter != input.end() )
        {
            std::cout << "did not parse";
        }
        else
        {
            // would like output.inttext to be "1,2_3"
            std::cout << output.header << ": " << std::string(output.ints.begin,output.ints.end) << " -> [ ";
            for( auto & i: output.ints.data )
                std::cout << i << ' ';
            std::cout << ']' << std::endl;
        }
    }
    

    Using semantic actions:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    namespace qi = boost::spirit::qi;
    namespace phx = boost::phoenix;
    using boost::spirit::repository::qi::iter_pos;
    
    struct ints_type
    {
       std::vector data;
       std::string inttext; 
    };
    
    struct A
    {
        std::string header;
        ints_type ints;
    
    };
    
    BOOST_FUSION_ADAPT_STRUCT(
        ints_type,
        (std::vector, data)
        (std::string, inttext)
    )
    
    BOOST_FUSION_ADAPT_STRUCT(
         A,
         (std::string, header)
         (ints_type, ints)
    )
    
    template 
    struct parser : qi::grammar< Iterator, A() >
    {
        parser() : parser::base_type(start)
        {
            header %= qi::lexeme[ +qi::alpha ];
            ints = qi::lexeme[
                      (iter_pos >> qi::int_ % qi::char_(",_") >> iter_pos)
                         [phx::at_c<0>(qi::_val)=qi::_2,
                          phx::at_c<1>(qi::_val)=phx::construct(qi::_1,qi::_3)] 
                   ]; 
            start %= header >> ' ' >> ints;
        }
    
        qi::rule header;
        qi::rule ints;
        qi::rule start;
    };
    
    int main()
    {
        A output;
        std::string input("out 1,2_3");
        auto iter = input.begin();
        parser p;
        bool r = qi::parse(iter, input.end(), p, output);
        if( !r || iter != input.end() )
        {
            std::cout << "did not parse";
        }
        else
        {
            // would like output.inttext to be "1,2_3"
            std::cout << output.header << ": " << output.ints.inttext << " -> [ ";
            for( auto & i: output.ints.data )
                std::cout << i << ' ';
            std::cout << ']' << std::endl;
        }
    }
    

提交回复
热议问题