2012-12-13 12 views
5

mam tego bardzo prostego parsera przy użyciu boost :: Spirit:boost :: Duch :: qi powielać analizowania na wyjściu

rule<std::string::iterator, std::string()> zeroTo255 = (string("25") >> char_('0', '5')) 
    | (char_('2') >> char_('0', '4') >> digit) 
    | (char_('1') >> repeat[2](digit)) 
    | (char_('1', '9') >> digit) | digit; 

Kiedy próbuję analizować

std::string o{"1"}; 
std::string s; 
parse(o.begin(), o.end(), zeroTo255, s); 
std::cout << o << ": " << s << std::endl; 

mam jako wyjście

1: 111 

Oczywiście robię coś nie tak, ale co?

Odpowiedz

8

qi::hold jest jeden sposób, o tym, jak prawidłowo wymieniony przez @Andrzej

Chyba mam kilka uwag, które mogą pomóc, jak również lepsze rozwiązanie.


Chodzi o to, że Duch nie będzie wymagał przechowywania "temp" dla atrybutów według projektu. W rzeczywistości nie może tak naprawdę zakładać, że atrybut będzie mógł być kopiowany w pierwszej kolejności. To jest powód tutaj (wyobraź sobie analizowanie wszystkiego w jednym std :: vector <> i kopiowanie dla każdego kroku parsera?).

Na bardziej istotnego poziomu, to wygląda mi się, że nie jest to obsługa, która jest wstecznie tutaj atrybut, lecz wyrazem parser sama: To nie zgłasza intencję i ponosi wszystkie rodzaje złożoność czynienia z reprezentacje numeryczne kiedy ... naprawdę nie powinno.

My się na to byłoby

rule<std::string::iterator, std::string()> zeroTo255, alternatively; 

alternatively %= raw [ uint_ [ _pass = (_1 <= 255) ] ]; 

Zobaczysz: niech Duch analizować liczbę, a nawet po prostu zweryfikować zakres, który jest co chcieliśmy zrobić w pierwszej kolejności.

Drugą rzeczą, która wydaje mi się typowa, jest fakt, że reguła ujawnia atrybut std::string, zamiast unsigned char, np. Dlaczego?

Zakładając To była świadoma decyzja projektowa, można mieć to na swój sposób przez rozsądnego korzystania z

  • negatywnej uprzedzona (!parser) - który nie ma wpływu atrybutów
  • pozytywny uprzedzona (&parser) - co nie wpływa na atrybuty
  • Zapoznaj się z qi::as_string, qi::raw, qi::lexeme i qi::no_skip
  • działań semantycznych (nie polegać na automatycznych reguł)

Oto co minimalna zmiana pierwotnej reguły musiałby pracował:

zeroTo255 = raw [ 
      ("25" >> char_("0-5")) 
     | ('2' >> char_("0-4") >> digit) 
     | ('1' >> digit >> digit) 
     | (char_("1-9") >> digit) 
     | digit 
    ]; 

ta ma mniej więcej taki sam efekt jak kod za pomocą qi::hold ale nie wadę wydajności wartości atrybutów _hold_ing.

Mam nadzieję, że to pomoże.

Pełna próbka: Żyją na http://liveworkspace.org/code/4v4CQW$0:

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 

namespace qi = boost::spirit::qi; 

int main() 
{ 
    using namespace qi; 
    rule<std::string::iterator, std::string()> zeroTo255, alternatively; 

    zeroTo255 = raw [ 
       ("25" >> char_("0-5")) 
      | ('2' >> char_("0-4") >> digit) 
      | ('1' >> digit >> digit) 
      | (char_("1-9") >> digit) 
      | digit 
     ]; 

    alternatively %= raw [ uint_ [ _pass = (_1 <= 255) ] ]; 

    for (auto& input : std::vector<std::string> { "255", "249", "178", "30", "4" }) 
    { 
     std::string output; 
     std::cout << "zeroTo255:\t" << std::boolalpha 
        << parse(std::begin(input), std::end(input), zeroTo255, output) 
        << ": " << output << std::endl; 

     output.clear(); 
     std::cout << "alternatively:\t" << std::boolalpha 
        << parse(std::begin(input), std::end(input), alternatively, output) 
        << ": " << output << std::endl; 
    } 

} 

Wyjście

zeroTo255:  true: 255 
alternatively: true: 255 
zeroTo255:  true: 249 
alternatively: true: 249 
zeroTo255:  true: 178 
alternatively: true: 178 
zeroTo255:  true: 30 
alternatively: true: 30 
zeroTo255:  true: 4 
alternatively: true: 4 
5

Raz spotkałem się z podobnym problemem. Jest to szczególny sposób działania alternatywnego operatora w Spirit. Twój przykład powinien zadziałać, jeśli użyjesz dodatkowej dyrektywy "wstrzymaj".

rule<std::string::iterator, std::string()> zeroTo255 
= hold[string("25") >> char_('0', '5')] 
| hold[char_('2') >> char_('0', '4') >> digit] 
| hold[char_('1') >> repeat[2](digit)] 
| hold[char_('1', '9') >> digit] | digit; 

Aby uzyskać szczegółowe informacje na temat tego zachowania, patrz: this thread.

+0

Wydaje się do tyłu, ale i tak ... dziękuję za szybką odpowiedź! –

+0

@brunonery Widzę, co masz na myśli mówiąc o "dodatkowej pracy". Miałem wyjaśnić w tym komentarzu, ale zrobiło się trochę duże, więc zamiast tego napisałem to jako odpowiedź :) – sehe

+0

Przepraszam Andrzej - odpowiedź jest poprawna, ale sehe's jest bardziej kompletny. Przyznam mu to, ok? –