2011-01-06 10 views
6

Wie viele dieser anderen Fragen versuche ich eine einfache Grammatik mit Boost.Spirit.Qi in einen Strukturbaum zu zerlegen.Boost.Spirit.Qi: Nimm das Attribut einer Regel und setze es als Feld des struct-Attributs einer umschließenden Regel?

Ich werde versuchen zu destillieren, was ich versuche, um den einfachsten Fall zu erreichen. Ich habe:

struct Integer { 
    int value; 
}; 
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value)) 

Später innerhalb einer Grammatik struct, ich folgende Membervariable haben:

qi::rule<Iterator, Integer> integer; 

, die ich mit

integer = qi::int_; 

bin definieren Wenn ich versuche, um tatsächlich zu analysieren eine ganze Zahl jedoch unter Verwendung von

qi::phrase_parse(iter, end, g, space, myInteger); 

myInteger.value ist nach einer erfolgreichen Analyse immer nicht initialisiert. In ähnlicher Weise habe ich die folgenden Definitionen versucht (natürlich diejenigen, die falsch sind nicht kompilieren):

integer = qi::int_[qi::_val = qi::_1]; //compiles, uninitialized value 
integer = qi::int_[qi::_r1 = qi::_1]; //doesn't compile 
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; //doesn't 
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; //doesn't 

Klar ich etwas über Geist, Phoenix bin Missverständnis, oder etwas anderes. Mein Verständnis ist, dass qi::_1 ist das erste Attribut von qi::int_, hier, und sollte die geparste Integer darstellen, wenn der Teil in den eckigen Klammern als Funktion Objekt ausgeführt wird. Ich gehe dann davon aus, dass das Funktionsobjekt das umgebende integer Attribut qi::_val annehmen und versuchen wird, ihm die geparste ganze Zahl zuzuweisen. Meine Vermutung war, dass aufgrund meines Anrufs BOOST_FUSION_ADAPT_STRUCT die beiden kompatibel wären, und das scheint aus statischer Analyse sicherlich der Fall zu sein, aber die Daten werden nicht beibehalten.

Gibt es eine Referenz (&) Bezeichnung Ich vermisse irgendwo oder etwas?

+0

Ich habe gerade eine andere Kombination, die kompiliert, obwohl es nicht in initialisierte Daten zur Folge hat: Ich habe einen Konstruktor 'Integer' hinzugefügt, die einen Wert für eine' value' nimmt , dann habe ich meinen 'integer' Parser definiert als 'integer = qi :: long_long [qi :: _ val = phx :: construct (qi :: _ 1)]; ' – jtolds

+0

oops, ich meine' qi :: int_' – jtolds

+0

mehr Debugging Anmerkungen. In meinem vollständigen Code habe ich tatsächlich 'qi :: rule integer;', was aussieht, als ob es bricht, wenn ich 'Integer' durch' Integer() 'ersetze, und alle Beispiele haben das nachlaufende '()', das ich vernachlässigt habe. Vielleicht wurden die Vorlagenargumente für die "Regel" also vermasselt. Graben. – jtolds

Antwort

13

Wenn Integer soll das Attribut von der Regel ausgesetzt sein, müssen Sie es als erklären:

qi::rule<Iterator, Integer()> integer; 

(beachten Sie die Klammern). Spirit muss die Syntax der Funktionsdeklaration verwenden, um die "Schnittstelle" der Regel zu beschreiben. Es wird nicht nur in Spirit verwendet, sondern auch in mehreren anderen Bibliotheken (siehe zB boost :: function).

Der Hauptgrund dafür ist, dass es eine nette und übersichtliche Art ist, eine Funktionsschnittstelle zu spezifizieren. Wenn Sie darüber nachdenken, was eine Regel ist, erkennen Sie schnell, dass es sich um eine Funktion handelt: Sie kann einen Wert zurückgeben (das analysierte Ergebnis, also das synthetisierte Attribut). Zusätzlich kann es ein oder mehrere Argumente (die geerbten Attribute) enthalten.

Ein zweiter, aber geringfügiger Grund ist, dass Spirit in der Lage sein muss, die verschiedenen Template-Parameter einer Regel zu unterscheiden. Die Template-Parameter können in beliebiger Reihenfolge angegeben werden (außer für den Iterator), also braucht es einige Mittel, um herauszufinden, was was ist. Die Syntax der Funktionsdeklaration unterscheidet sich ausreichend vom Skipper oder der Codierung (den anderen beiden möglichen Vorlagenparametern), damit sie zur Kompilierzeit erkannt werden kann.

Lassen Sie uns einen Blick auf Ihre verschiedenen Versuche haben:

Dies gemacht werden können arbeiten, wenn Sie die Regel-Definition ändern, wie oben beschrieben.

integer = qi::int_[qi::_val = qi::_1]; 

The _val bezieht sich auf Ihre Integer, während der _1 auf ein int bezieht. Daher müssen Sie einen Zuweisungsoperator von int definieren, um diese Arbeit zu machen:

struct Integer { 
    int value; 
    Integer& operator=(int) {...} 
};      

Sie brauchen nicht Ihre Art als Fusionssequenz in diesem Fall anzupassen.

Aber man kann es schreiben noch einfacher:

integer = qi::int_ >> qi::eps; 

, die 100% entspricht (die eps ist ein Trick verwendet, um die rechte Seite in einen Parser-Sequenz zu konvertieren, die das nutzen können Built-in attribute propagation mapping die Elemente Ihrer angepassten Fusion-Sequenz auf die Attribute der Elemente der Sequenz). Diese

:

integer = qi::int_[qi::_r1 = qi::_1]; 

wird nicht funktionieren wie _r1 bezieht sich auf die erste geerbt Attribut einer Regel. Ihre Regel enthält jedoch keine eingebetteten Attribute.

wird diese Arbeit:

integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; 

aber erfordert nicht Ihre Art als Fusionssequenz anzupassen.

Und so wird dies:

integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; 
+0

oh schön, danke. Es sieht so aus, als hätte ich die ganze Zeit nur einen Template-Tippfehler gehabt. – jtolds

+2

'git commit -a -m 'Hartmut Kaiser ist der Mann!'' – jtolds