Hinweis: Wenn ich im Titel "Komplex" verwendet habe, bedeutet dies, dass der Ausdruck viele Operatoren und Operanden enthält. Nicht, dass der Ausdruck selbst komplex wäre.
Ich habe kürzlich an einem einfachen Compiler für die x86-64-Assembly gearbeitet. Ich habe das Haupt-Frontend des Compilers fertiggestellt - den Lexer und den Parser - und kann nun eine abstrakte Syntaxbaumdarstellung meines Programms generieren. Und da meine Sprache statisch geschrieben wird, mache ich jetzt die nächste Phase: Überprüfung des Quellcodes. Ich bin jedoch auf ein Problem gestoßen und konnte es nicht vernünftigerweise selbst lösen.
Betrachten Sie das folgende Beispiel:
Der Parser meines Compilers hat diese Codezeile gelesen:
int a = 1 + 2 - 3 * 4 - 5
Und konvertierte es auf folgende AST:
=
/ \
a(int) \
-
/ \
- 5
/ \
+ *
/ \ / \
1 2 3 4
Jetzt muss der AST überprüft werden. Zunächst wird der =
Bediener überprüft . Zunächst wird die linke Seite des Bedieners überprüft. Es wird angezeigt, dass die Variable a
als Ganzzahl deklariert ist. Daher muss jetzt überprüft werden, ob der Ausdruck auf der rechten Seite eine Ganzzahl ergibt.
Ich verstehe, wie dies getan werden könnte, wenn der Ausdruck nur ein einzelner Wert wäre, wie z. B. 1
oder 'a'
. Aber wie würde das für Ausdrücke mit mehreren Werten und Operanden gemacht werden - ein komplexer Ausdruck - wie der obige? Um den Wert des Ausdrucks korrekt zu bestimmen, müsste die Typprüfung anscheinend den Ausdruck selbst ausführen und das Ergebnis aufzeichnen. Dies scheint jedoch offensichtlich den Zweck der Trennung von Kompilierungs- und Ausführungsphase zu zunichte zu machen.
Die einzige andere Möglichkeit, die ich mir vorstellen kann, besteht darin, das Blatt jedes Unterausdrucks im AST rekursiv zu überprüfen und zu überprüfen, ob alle Blatttypen mit dem erwarteten Operatortyp übereinstimmen. Ausgehend vom =
Operator scannt die Typprüfung dann den gesamten AST der linken Seite und überprüft, ob alle Blätter Ganzzahlen sind. Dies würde dann für jeden Operator im Unterausdruck wiederholt.
Ich habe versucht, das Thema in meinem Exemplar von "The Dragon Book" zu recherchieren , aber es scheint nicht sehr detailliert zu sein, und ich wiederhole einfach, was ich bereits weiß.
Was ist die übliche Methode, wenn ein Compiler Ausdrücke mit vielen Operatoren und Operanden prüft? Werden die oben genannten Methoden angewendet? Wenn nicht, wie lauten die Methoden und wie genau würden sie funktionieren?
double a = 7/2
versucht, die rechte Seite als doppelt zu interpretieren. Daher werden Zähler und Nenner als doppelt interpretiert und bei Bedarf konvertiert. als Ergebnis a = 3.5
. Der Bottom-Up würde eine Ganzzahldivision durchführen und nur beim letzten Schritt (Zuweisung) konvertieren, also a = 3.0
.
int a = 1 + 2 - 3 * 4 - 5
sondernint a = 5 - ((4*3) - (1+2))