Einen Compiler schreiben: Wie man einfache Vorlagen zum Laufen bringt?

8

Ich habe eine Sprache mit einer sehr C ++ - ähnlichen Syntax. Der Lexer und der Parser sind vorhanden und erzeugen den korrekten AST. Zum größten Teil ist auch das Backend erledigt.

Das Basissystem, das der Compiler zum Erstellen von Typen verwendet, ist sehr einfach: Alle Typen gelten als integriert und alle Instanzen sind global. Es gibt also nur eine einfache Map, die einen Typnamen mit einer Methode vergleicht, die eine Variable erzeugt, die im Grunde genommen ein generischer Typ ist wie boost :: any. Eine andere Karte mit dem Namen der Variablen als Schlüssel und der Variablen als Wert dient als globaler Geltungsbereich:

%Vor%

Wenn der Compiler den AST-Knoten für eine Initialisierung wie X myVar; bekommt, tut er das im Grunde

%Vor%

Wenn myVar zu einem späteren Zeitpunkt verwendet wird, kann man mit einem einfachen Dispatch wie

darauf zugreifen %Vor%

Nun möchte ich das etwas erweitern und einfache Vorlagen verwenden. Angenommen, es gibt einen Typ "Array", der unter Verwendung eines Vektors implementiert wird. Ich könnte alles wie

registrieren %Vor%

aber das ist nicht recht managbar, da es für alle Kombinationen wiederholt werden müsste. Idealerweise würde ich Funktionalität brauchen, die es erlaubt, etwas wie dieses zu schreiben:

%Vor%

, die dann eine Variableninstanz erzeugen würde, die intern einen std :: vector & lt; X & gt ;. Ich habe mich angestrengt, kann aber nicht herausfinden, wie ich das machen soll. Vielleicht habe ich einfach mit der einfachen Typenkartierung den falschen Weg eingeschlagen und das ist der Grund, warum ich mich nicht darum kümmern kann.

Die Frage ist also einfach: Ist es möglich, dies zu tun? Und wie?

    
stijn 08.12.2011, 14:23
quelle

2 Antworten

2

Ich bin mir nicht sicher, ob ich Ihr Problem richtig verstanden habe, aber wenn Sie M parametrische Typen ( vector<> , list<> , ...) und N einfache Typen ( int , double , ...) haben , würden Sie M * N tatsächliche Implementierungen benötigen, wenn Sie alle Kombinationen unterstützen möchten. All diese Implementierungen müssen zum Zeitpunkt der Kompilierung bekannt sein (oder im Prinzip können Sie den C ++ - Compiler on-the-fly aufrufen). Willst du das wirklich?

Eine Problemumgehung könnte sein, stattdessen nicht typisierte Container zu verwenden. Beispiel: vector<Object*> speichert Zeiger, die anschließend in den erforderlichen Typ konvertiert werden können, z. B. mit dynamic_cast . Auf diese Weise benötigen Sie nur M-Implementierungen für parametrische Typen und können "array" in vector und "X" in X unabhängig voneinander auflösen.

    
Roman L 08.12.2011 21:29
quelle
1

Im Allgemeinen ist die Art, wie Sie Template-ähnliche Typen verwenden, wie beschrieben, aber statt alle möglichen Kombinationen im Voraus zu erstellen, erstellen Sie sie bei Bedarf. So haben Sie vielleicht eine getType -Routine wie:

%Vor%

Dies wird für jeden Typ aufgerufen, auf den im Programm Bezug genommen wird, und erstellt die erforderlichen Template-Instanziierungen auf Anfrage.

    
Chris Dodd 08.12.2011 22:58
quelle