2012-03-15 10 views
8

Ho utilizzato con successo boost::spirit::qi per analizzare un flusso costituito dai parser incorporati (ad esempio byte_, little_word, ecc.). Tuttavia, ora devo analizzare i dati che non rientrano ordinatamente in una di queste categorie. Per esempio, mi piacerebbe convertire un numero binario a 16,16 punti fissi in un doppio; per esempio. quindi little_word << little_16p16 analizzerebbe uno uint16_t seguito da uno double (analizza da un numero a virgola fissa).Modifica il tipo di attributo durante l'analisi di binario con boost :: spirit

Prima ho considerato le azioni semantiche, ma (penso ...) che non sono appropriate perché non cambiano il tipo di attributo associato a un parser. Non riesco nemmeno a capire come adattare lo employee struct-parsing example a questa situazione perché si basa su trasmissioni implicite fornite da boost::fusion. Questo approccio non funzionerà qui perché ovviamente non è possibile definire un cast implicito da uint32_t a double senza causare problemi importanti.

La mia inclinazione è che ho bisogno di aggiungere non-terminali per avvolgere i parser binari primitivi built-in o scrivere un parser terminale da zero. Anche dopo aver visto la fonte di qi_binary.hpp, non sono sicuro di come fare. Qualcuno potrebbe fornire qualche codice di esempio e/o indirizzarmi ai riferimenti pertinenti per iniziare?

risposta

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

Grazie! Sono riuscito a far sì che il codice di esempio eseguisse esattamente ciò che volevo rimuovendo il parametro del template 'ascii :: space_type' e sostituendo la funzione' operator() 'appropriata. –

Problemi correlati