Ich habe mehrere Artikel, Artikel und Abschnitt 4.1.4, Kapitel 4 von Compiler: Prinzipien, Techniken und Werkzeuge (2. Ausgabe) (auch bekannt als "The Dragon Book") gelesen, in denen das Thema der syntaktischen Compiler-Fehlerbehebung behandelt wird. Nachdem ich mit mehreren modernen Compilern experimentiert habe, habe ich festgestellt, dass sie sich auch von semantischen Fehlern sowie von syntaktischen Fehlern erholen .
Ich verstehe die Algorithmen und Techniken hinter Compilern, die sich von syntaktisch verwandten Fehlern erholen, ziemlich gut, verstehe jedoch nicht genau, wie ein Compiler sich von einem semantischen Fehler erholen kann.
Ich verwende derzeit eine geringfügige Variation des Besuchermusters, um Code aus meinem abstrakten Syntaxbaum zu generieren. Stellen Sie sich vor, mein Compiler kompiliert die folgenden Ausdrücke:
1 / (2 * (3 + "4"))
Der Compiler würde den folgenden abstrakten Syntaxbaum generieren:
op(/)
|
-------
/ \
int(1) op(*)
|
-------
/ \
int(2) op(+)
|
-------
/ \
int(3) str(4)
Die Codegenerierungsphase würde dann das Besuchermuster verwenden, um den abstrakten Syntaxbaum rekursiv zu durchlaufen und eine Typprüfung durchzuführen. Der abstrakte Syntaxbaum wird durchlaufen, bis der Compiler zum innersten Teil des Ausdrucks gelangt. (3 + "4")
. Der Compiler überprüft dann jede Seite der Ausdrücke und stellt fest, dass sie nicht semantisch äquivalent sind. Der Compiler löst einen Typfehler aus. Hier liegt das Problem. Was soll der Compiler jetzt tun ?
Damit der Compiler diesen Fehler beheben und die äußeren Teile der Ausdrücke vom Typ überprüfen kann, muss er einen Typ ( int
oder str
) von der Auswertung des innersten Teils des Ausdrucks zum nächsten innersten Teil des Ausdrucks zurückgeben. Aber es gibt einfach keinen Typ, der zurückgegeben werden könnte . Da ein Typfehler aufgetreten ist, wurde kein Typ abgeleitet.
Eine mögliche Lösung, die ich postuliert habe, ist, dass, wenn ein Typfehler auftritt, ein Fehler ausgelöst werden sollte und ein spezieller Wert, der anzeigt, dass ein Typfehler aufgetreten ist, an frühere Traversal-Aufrufe des abstrakten Syntaxbaums zurückgegeben werden sollte. Wenn frühere Traversal-Aufrufe auf diesen Wert stoßen, wissen sie, dass ein Typfehler tiefer im abstrakten Syntaxbaum aufgetreten ist, und sollten vermeiden, einen Typ abzuleiten. Obwohl diese Methode zu funktionieren scheint, scheint sie sehr ineffizient zu sein. Wenn sich der innerste Teil eines Ausdrucks tief im abstrakten Syntaxbaum befindet, muss der Compiler viele rekursive Aufrufe ausführen, um zu erkennen, dass keine echte Arbeit ausgeführt werden kann, und einfach von jedem zurückkehren.
Wird die oben beschriebene Methode verwendet (ich bezweifle es). Wenn ja, ist es nicht effizient? Wenn nicht, welche Methoden werden genau verwendet, wenn Compiler semantische Fehler beheben?