2010-08-12 3 views
10

Ich versuche, einen Shell-Sprache-Parser in Boost.Spirit zu schreiben. Ich bin jedoch über einige grundlegende Fragen in Bezug auf die Semantik von rule s unklar.Kopiere oder referenziere Semantik von boost :: spirit's rule <>?

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

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

was darauf schließen läßt die Regeln getroffen werden, durch Bezugnahme innerhalb Parser Ausdrücke. Das Problem ist, was tut sie, wenn die Variable den Gültigkeitsbereich verlässt, 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() wäre ein rvalue des Typs rule auch, ist es nicht)? z.B.

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

Kann mir jemand auf die detaillierten Semantik von rule ‚s Kopien und Verweise, aufklären und möglicherweise irgendwelche Missverständnisse in diesem Beitrag nicht korrekt?

Antwort

13

Die Antwort hängt davon ab, auf welche Version von Spirit du dich beziehst.

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

Wenn eine Regel irgendwo in die rechte Seite eines EBNF Ausdruck verwiesen wird, die Regel von dem Ausdruck durch Bezugnahme gehalten wird. Es ist die Verantwortung des Clients sicherzustellen, , dass die referenzierte Regel bleibt in Bereich und wird nicht zerstört , während es referenziert wird.

Der Zuweisungsoperator verweist im Wesentlichen auf die rhs-Regel, ohne auch eine tiefe Kopie zu erstellen. Dies wurde zu erlauben, getan:

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

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

Aus diesem Grund gab es die Elementfunktion rule::copy(), die es ermöglicht, explizite tiefe Kopien einer Regel zu machen (zum Beispiel, um sie in einem STL-Container zu speichern). diese

Zur gleichen Zeit:

r2 = r1.copy(); 

ist schlicht falsch. r2 würde sich auf die (zerstörte) temporäre Kopie von r1 beziehen, die von der Funktion copy() zurückgegeben wurde.


In Spirit.Qi (d. H. Geist V2.x) wird das Verhalten teilweise geändert.Regeln verhalten sich nun wie erwartet, wenn sie außerhalb von Parsern behandelt werden. Sie können sie normalerweise in Containern speichern (der Zuweisungsoperator macht das erwartete Verhalten verfügbar). 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 wie beziehen kann, bevor:

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

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

Die geänderte Kopiesemantik hat einen weiteren Nebeneffekt. Konstrukte mögen:

r1 = r2; 

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

r1 = r2.alias(); 

Auf jedem Fall in beiden Versionen des Geistes Sie mit baumelnden Referenzen am Ende werden, wenn ein Teil der Regeln von einem Parser verwiesen Ausdruck gehen aus dem Rahmen.

BTW, keine Spirit-Version implementiert eine Funktion rule::ref().

+0

Danke für diese Antwort. Ich habe nur eine weitere Frage: Ist es irgendwie möglich, rvalues ​​(provisories) von Parser-Ausdrücken eines Typs im Parser-Ausdruck zu verwenden, um Anweisungen wie 'r1 = r1 | zu erlauben string ("abc") oder Regeln in einer Funktion erzeugen? – jpalecek

+0

Während der Ausdruck 'r1 = r1 | string ("abc") 'ist theoretisch möglich, es ist eine Linksrekursion, die zu einer unendlichen Rekursion führt, wenn Spirit rekursive Descent-Parser erzeugt. Aber der Ausdruck 'r1 = string ("abc") | r1 'wird wie erwartet funktionieren. Sie können eine Regel in einer Funktion generieren, wenn Sie sicherstellen, dass sie sich nicht auf eine andere Regel bezieht, die den Gültigkeitsbereich überschritten hat. In Spirit.Classic müssen Sie außerdem r.copy() von der Funktion zurückgeben. – hkaiser

+0

'r1 = Zeichenfolge ("abc") | r1 'ist auch eine Links-Rekursion :) Aber was ich machen wollte, ist, dass r1 zu dem passt, was r1 früher gefunden hat und "abc". BTW wie kann ich eine Regel in einer Funktion erzeugen? Das funktioniert nicht für mich: http://pastebin.org/482764 – jpalecek