4

Ich benutze Iteratoren seit einer Weile und ich liebe sie.Wie kann ein Compiler, der die Iteratoren erkennt, implementiert werden?

Aber obwohl ich darüber nachgedacht habe, konnte ich nicht herausfinden, "wie ein Compiler, der die Iteratoren erkennt" implementiert wird. Ich habe auch darüber recherchiert, konnte aber keine Ressource finden, die die Situation im Compiler-Design-Kontext erklärt.

Um es auszuarbeiten, die meisten Artikel über Iteratoren implizieren, dass es eine Art von "Magie" gibt, die das gewünschte Verhalten implementiert. Sie schlagen vor, dass der Compiler eine Zustandsmaschine beibehält, um zu verfolgen, wo die Ausführung ist (wo die letzte "Ertragsrendite" gesehen wird). Ich interessiere mich besonders für diese Eigenschaft von Iteratoren, die die faule Auswertung ermöglicht.

Übrigens, ich weiß, was State Machines sind, haben bereits einen Compiler-Design-Kurs genommen, studierte das Dragon Book. Aber anscheinend kann ich das, was ich studiert habe, nicht mit der "Magie" von CSC in Verbindung bringen.

Jedes Wissen oder unterschiedliche Gedanken werden geschätzt.

+0

Können Sie das ein wenig mehr erklären? Zum Beispiel mit einem Quellcode-Beispiel, von dem Sie glauben, dass es für einen Compiler sehr schwierig ist, es zu erkennen? – Thilo

+0

und welche Sprache sprichst du? Was macht zum Beispiel "yeild"? –

+0

C# hat eine "yield return" -Syntax. –

Antwort

5

Es ist einfacher als es scheint. Der Compiler kann die Iteratorfunktion in einzelne Blöcke zerlegen; Chunks werden durch yield Anweisungen geteilt.

Die Zustandsmaschine muss nur verfolgen, in welchem ​​Chunk wir uns gerade befinden und springt beim nächsten Aufruf des Iterators direkt auf diesen Chunk. Wir müssen natürlich auch alle lokalen Variablen im Auge behalten.

Dann müssen wir ein paar spezielle Fälle betrachten, insbesondere Schleifen, die yield s enthalten. Glücklicherweise erlaubt IL (aber nicht C# selbst) goto, in Schleifen zu springen und sie fortzusetzen.

Beachten Sie, dass es einige sehr komplizierte Randfälle gibt, z. C# erlaubt nicht yield in finally Blöcke, weil es sehr schwierig (unmöglich?) Wäre, die Funktion auf yield zu verlassen, und später die Funktion wieder aufnehmen, Säuberung durchführen, jede Ausnahme erneut werfen und die Stapelüberwachung beibehalten.

Eric Lippert hat eine in-depth description des Prozesses veröffentlicht. (Lesen Sie auch die Artikel, die er verlinkt hat!)

1

Eine Sache, die ich versuchen würde, wäre, ein kleines Beispiel in C# zu schreiben, es zu kompilieren und dann Reflector darauf zu verwenden. Ich denke, dass diese "Rendite" -Ding nur Syntax Zucker ist, so dass Sie sehen können, wie der Compiler es in der Ausgabe des Disassemblers behandelt.

Aber, ich weiß nicht wirklich viel über diese Dinge, vielleicht bin ich völlig falsch.