Search code examples
c++boostboost-spiritqi

Spirit Qi : rule for char [5]


I have the following structure

struct MyStruct 
{
    char CODE;
    char NAME[5];
};

I make it a fusion struct

BOOST_FUSION_ADAPT_STRUCT
(
MyStruct,
(char, MARKET_CODE)
(char, NAME[5])
)

My grammar is implemented as follow:

MyStruct_parser() : ticker_parser::base_type(start)
    {
        using qi::lexeme;
        using ascii::char_;

        a_word %= lexeme[+(char_)];
        start %=  a_word >> a_word;
    }
    qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
    qi::rule<Iterator, Ticker(), ascii::space_type> start;

Unfortunately it does not compile. Now I use std::string instead of char[5] I have no problem. Can you please tell me how to tell Spirit to read char[5]?

Thank you


Solution

  • You can supply custom attribute transformations using boost::spirit::traits::transform_attribute<>:

    See it Live On Coliru or indeed Live for C++03

    #include <boost/spirit/include/qi.hpp>
    #include <boost/array.hpp>
    
    namespace qi = boost::spirit::qi;
    
    typedef char name_t[5];
    // typedef boost::array<char, 5> name_t;
    
    struct MyStruct {
        char   code;
        name_t name;
    };
    
    namespace boost { namespace spirit { namespace traits {
    
        template <>
            struct transform_attribute<name_t, std::vector<char>, qi::domain> {
                typedef std::vector<char> type;
    
                static type pre(name_t&) { return {}; }
    
                static void post(name_t& val, type const& attr) {
                    static_assert(sizeof(val)==5, "");
                    assert(attr.size() == sizeof(val));
    
                    using boost::begin;
                    using boost::end;
                    std::copy(attr.begin(), attr.end(), begin(val));
                }
                static void fail(name_t&) { }
            };
    
    } } }
    
    int main()
    {
        std::string const input("123456");
    
        using It = std::string::const_iterator;
        It f(input.begin()), l(input.end());
    
        MyStruct data;
        qi::rule<It, std::vector<char>()> c5 = qi::repeat(5) [ qi::char_ ];
        bool ok = qi::parse(f,l, qi::char_ >> c5, data.code, data.name);
    
        if (ok)
        {
            std::cout << "Parse success: " << data.code << ", '" << std::string(std::begin(data.name), std::end(data.name)) << "'\n";
        } else
        {
            std::cout << "Parse failed\n";
        }
    
        if (f!=l)
        {
            std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
        }
    }
    

    Prints

    Parse success: 1, '23456'
    

    in both the c++11 and c++03 versions