2012-12-13 7 views
5

Ich habe diesen sehr einfachen Parser Boost :: Geist:boost :: spirit :: Qi Duplikat auf dem Ausgabe Parsen

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; 

Wenn ich versuche,

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

ich als Ausgabe haben zu analysieren

1: 111 

Ich mache offensichtlich etwas falsch, aber was?

Antwort

8

qi::hold ist ein Weg, um darüber, wie richtig von @Andrzej erwähnt

Ich glaube, ich ein paar Beobachtungen, die, ebenso wie eine bessere Lösung könnte helfen.


Der Punkt ist, dass Spirit nicht 'Temp' Speicher für Attribute von Design erfordern wird. Tatsächlich kann das Attribut nicht wirklich als kopierbar angesehen werden. Dies ist der Grund hier (stellen Sie sich vor, alles in einen einzigen std :: vector <> zu kopieren und für jeden Parser-Schritt zu kopieren?).

Auf einem wesentlicheren Ebene sieht es mir, als ob es nicht das Attribut Umgang dass rückwärts hier ist, aber der Parser Ausdruck selbst: Es schlägt fehl, die Absicht zu erklären, und verursacht alle Arten von Komplexität Umgang mit Zahlendarstellungen wenn ... wirklich sollte es nicht.

Mein nehmen auf, es wäre

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

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

Sie sehen: Sie lassen Geist eine Reihe analysieren, und zwar nur den Bereich verifizieren, das ist, was Sie in erster Linie tun wollte.

Die zweite Sache, die mich als typisches trifft, ist die Tatsache, dass die Regel ein std::string Attribut aussetzt, statt unsigned char z.B. Warum das?

Angenommen, dies war eine bewusste Design-Entscheidung, können Sie es Ihren Weg durch gezielten Einsatz von

  • negativer Vorschau (!parser) haben -, die keine Attribute beeinflussen
  • positive Vorschau (&parser) - die hat keinen Einfluss auf Attribute
  • machen Sie sich mit qi::as_string, qi::raw, qi::lexeme und qi::no_skip
  • semantischen Aktionen (nicht vertrauen auf automatische Regeln ist)

Hier ist, was zu Ihrer ursprünglichen Regel minimale Änderung gearbeitet haben würde:

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

Dies hat in etwa die gleiche Wirkung wie der Code qi::hold verwenden, aber nicht die Leistung Nachteil von _hold_ing Attributwerten.

Hoffe, das hilft.

Voll Beispiel: Live on 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; 
    } 

} 

Ausgabe

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

Ich konfrontiert einmal ein ähnliches Problem. Dies ist die besondere Art, wie der alternative Operator in Spirit arbeitet. Ihr Beispiel sollte funktionieren, wenn Sie die zusätzliche Anweisung "hold" verwenden.

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; 

Einzelheiten zu diesem Verhalten finden Sie unter this thread.

+0

Es scheint, rückwärts, aber trotzdem ... Danke für die schnelle Antwort! –

+0

@brunonery Ich sehe, was du mit der "Extraarbeit" meinst. Ich wollte das in diesem Kommentar erklären, aber es wurde ein bisschen groß, also habe ich es als Antwort geschrieben :) – sehe

+0

Tut mir leid Andrzej - deine Antwort ist richtig, aber die ist vollständiger. Ich vergebe ihm diesen, ok? –

Verwandte Themen