2012-03-15 11 views
8

he estado utilizando con éxito a boost::spirit::qi para analizar una corriente que consiste en los analizadores integrados (por ejemplo byte_, little_word, etc). Sin embargo, ahora necesito analizar datos que no caigan en una de estas categorías. Por ejemplo, me gustaría convertir un 16.16 número binario de punto fijo en un doble; p.ej. entonces little_word << little_16p16 analizaría un uint16_t seguido por un double (analiza desde un número de punto fijo).Cambiar tipo de atributo al analizar binario con impulso :: espíritu

Primero consideré acciones semánticas, pero (creo ...) que no son apropiadas porque no cambian el tipo del atributo asociado con un analizador. Tampoco puedo encontrar la manera de adaptar el employee struct-parsing example a esta situación porque se basa en conversiones implícitas proporcionadas por boost::fusion. Ese enfoque no funcionará aquí porque obviamente no puedo definir un elenco implícito de uint32_t a double sin causar problemas importantes.

Mi inclinación es que necesito agregar no terminales para envolver los analizadores primitivos binarios integrados o escribir un analizador de terminales desde cero. Incluso después de ver la fuente de qi_binary.hpp, no estoy seguro de cómo hacerlo. ¿Podría alguien proporcionar algún código de muestra y/o dirigirme a las referencias relevantes para comenzar?

Respuesta

7
template < typename Iterator > 
    struct parser : boost::spirit::qi::grammar < Iterator, double(), boost::spirit::ascii::space_type > 
    { 
     struct cast_impl 
     { 
      template < typename A > 
      struct result { typedef double type; }; 

      double operator()(boost::fusion::vector < boost::uint16_t, boost::uint16_t > arg) const 
      { 
       // cast here 
       return 0; 
      } 
     }; 

     parser() : parser::base_type(main) 
     { 
      pair = boost::spirit::qi::little_word >> '.' >> boost::spirit::qi::little_word; 
      main = pair[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)]; 
     } 

     boost::spirit::qi::rule < Iterator, boost::fusion::vector < boost::uint16_t, boost::uint16_t >(), boost::spirit::ascii::space_type > pair; 
     boost::spirit::qi::rule < Iterator, double(), boost::spirit::ascii::space_type > main; 

     boost::phoenix::function<cast_impl> cast; 
    }; 

    int _tmain(int argc, _TCHAR* argv[]) 
    { 
     typedef std::string container; 

     container data_ = "\x01\x02.\x01\x02"; 

     container::iterator iterator_ = data_.begin(); 

     double value_; 

     bool result_ = 
      boost::spirit::qi::phrase_parse(iterator_, data_.end(), 
      parser <container::iterator>(), 
      boost::spirit::ascii::space, 
      value_); 

     return 0; 
    } 
+0

Gracias! Pude obtener su código de muestra para hacer exactamente lo que quería eliminando el parámetro de plantilla 'ascii :: space_type' y sustituyendo la función' operator() 'apropiada. –

Cuestiones relacionadas