Frage

Ich versuche, einen Shell-Sprache-Parser in Boost.Spirit zu schreiben. Ich bin jedoch unklar, über einige grundlegende Fragen der Semantik von rules.

in der Dokumentation suchen, gibt es Mitglieder r.alias() und r.copy() von rule. IIUC sollten diese Mitglieder einen Verweis auf die Regel zurückzukehren und eine Kopie des Inhalts der Regel sind. Es ist jedoch nicht klar definiert, was passiert, wenn ich nur die Regel in einer Definition einer anderen Regel verwenden. Aus meinen Versuchen, fand ich beiden Seiten rekursive Regeln können definiert werden durch:

rule<Iter> r1, r2;
r1 = ... >> r2 >> ...;
r2 = ... >> r1 >> ...;

, die die Regeln schon sagt sind durch Bezugnahme innerhalb Parser Ausdrücke genommen. Das Problem ist, was tut sie, wenn die Variable geht von Rahmen aus, zum Beispiel:

rule<Iter> r1;
{ 
  rule<Iter> r2;
  r1 = ... >> r2 >> ...;
  r2 = ... >> r1 >> ...;
}
... // use r1

Auf die gleiche Note, würde von einem Parsing Ausdruck einer Regel Zuweisung eines rvalue vom Typ Regel Arbeit, die (r.copy() ein R-Wert vom Typ rule sein würde, ist es nicht)? zB.

rule<Iter> f() { return char_('a') << char_('b'); }
rule<Iter> r1 = ... << f();

Kann jemand mich aufklären über die detaillierte Semantik von rule Exemplaren und Referenzen und korrigiert möglicherweise keine Missverständnisse in diesem Beitrag nicht?

War es hilfreich?

Lösung

Die Antwort hängt davon ab, welche Version des Geistes Sie sich beziehen.


Spirit.Classic (der ehemalige Geist V1.x) implementiert spezielle Kopiersemantik für Regeln. Die Dokumentation sagt:

  

Wenn eine Regel überall referenziert wird in   die rechte Seite eines EBNF   Ausdruck, wird die Regel durch die gehalten   Ausdruck durch Bezugnahme eingeschlossen. Es ist der   Verantwortung des Kunden, um sicherzustellen,   dass die referenzierten Regel Aufenthalte in   Umfang und nicht bekommen zerstört hat   während sie verwiesen wird.

Der Zuweisungsoperator verweist im Wesentlichen der rhs Regel ohne als auch eine tiefe Kopie zu erstellen. Dies wurde getan, damit:

rule<> r1, r2;
r1 = ...;
r2 = r1;

Aber das erwies sich als sehr Verwirrung, da es Regeln genauso wie ‚normale‘ Objekte verhindert Handhabung.

Aus diesem Grunde gibt es die Mitgliedsfunktion rule::copy(), so dass auf explizite tiefe Kopien von der Regel machen (zum Beispiel sie in einem STL-Containern zu speichern).

Zur gleichen Zeit folgt aus:

r2 = r1.copy();

ist schlicht falsch. r2 verweist auf die (destructed) temporäre Kopie von r1 aus der Funktion copy() zurückgegeben.


In Spirit.Qi (das heißt Geist V2.x) wird das Verhalten teilweise geändert. Regeln jetzt verhalten, wie wenn sie außerhalb von Parsern behandelt erwartet. Sie können sie in Behältern lagern normalerweise (der Zuweisungsoperator macht das erwartete Verhalten). Aber Vorsicht, dass nach wie vor in einem Parser Ausdruck Regeln unter Bezugnahme gehalten werden, die noch in der Regel die gleiche Art und Weise beziehen kann nach wie vor:

rule<> r1, r2;
r1 = ... >> r2 >> ...;
r2 = ... >> r1 >> ...;

Manchmal ist es notwendig, eine tiefe Kopie einer Regel zu machen, so gibt es immer noch das Mitglied functon copy.

Die geänderten Kopie Semantik haben eine andere Nebenwirkung. Konstrukte wie:

r1 = r2;

erstellen nun eine (tief) Kopie r2, die vielleicht nicht, was Sie erwarten, vor allem, wenn r2 seine rhs nur zugewiesen bekommen, nachdem ‚zugewiesen‘ zu r1 zu sein. Aus diesem Grund gibt es die neue Member-Funktion alias ermöglicht Referenzsemantik für diese Ecke Fall:

r1 = r2.alias();

Auf jedem Fall in beiden Versionen von Geist werden sie mit baumelnden Referenzen am Ende, wenn ein Teil der Regeln von einem Parser Ausdruck verweisen of scope gehen.

BTW, weder Geist Version implementiert eine Funktion rule::ref().

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top