2010-07-21 2 views
7

Hallo allerseits Ich implementiere derzeit eine einfache Programmiersprache für Lernerfahrung, aber ich brauche einen Rat. Momentan entwerfe ich meinen Interpreter und ich habe ein Problem.Implementieren einer stack-basierten virtuellen Maschine für eine Untergruppe von C

Meine Sprache ist eine Teilmenge von C und ich habe ein Problem in Bezug auf die Stack-Interpreter-Implementierung. In der Sprache wird die folgenden kompilieren:

somefunc() 
{ 
    1 + 2; 
} 

main() 
{ 
    somefunc(); 
} 

Nun ist dies in Ordnung, aber wenn „1 + 2“ das Ergebnis berechnet wird, wird auf einen Stapel geschoben und dann die Funktion zurück, aber es gibt immer noch eine Reihe auf dem Stapel, und es sollte nicht sein. Wie kann ich dieses Problem umgehen?

Ich habe darüber nachgedacht, einen "state" des Stacks vor einem Funktionsaufruf zu speichern und den "state" nach dem Funktionsaufruf wiederherzustellen. Speichern Sie zum Beispiel die Anzahl der Elemente auf dem Stapel, führen Sie dann den Funktionscode aus, geben Sie zurück und dann aus dem Stapel, bis wir die gleiche Anzahl von Elementen wie zuvor haben (oder vielleicht +1, wenn die Funktion etwas zurückgibt).

Irgendwelche Ideen? Danke für irgendwelche Tipps!

Antwort

8

Große Frage! Eines meiner Hobbies ist das Schreiben von Compilern für Spielzeugsprachen, also ein Lob für Ihren ausgezeichneten Programmiergeschmack.

Ein Ausdruck Anweisung ist eine wo der Code in der Anweisung ist einfach ein Ausdruck. Dies bedeutet alles in der Form <expression> ;, die Dinge wie Zuweisungen und Funktionsaufrufe enthält, aber nicht if s, while s, oder return s. Jede Ausdruckanweisung hat am Ende des Stapels einen Restwert, den Sie verwerfen sollten.

1 + 2 ist ein Ausdruck Aussage, aber so sind diese:

  • x = 5;
    Die Zuordnung Ausdruck da das Ergebnis einer Zuweisung den Wert 5 auf den Stapel verlässt, ist der Wert des links- Handoperand. Nachdem die Anweisung beendet ist Pop Sie den ungenutzten Wert 5.

  • printf("hello world!\n");
    printf() gibt die Anzahl der ausgegebenen Zeichen aus. Sie haben diesen Wert auf dem Stapel übrig, also pop, wenn die Anweisung beendet ist.

effektiv jeder Ausdruck Anweisung einen Wert auf dem Stapel verlassen, es sei denn der Typ void ist Ausdruck. In diesem Fall müssen Sie entweder void Anweisungen eingeben und danach nichts mehr ausgeben, oder einen vorgetäuschten "void" -Wert auf den Stack schieben, damit Sie immer einen Wert ausgeben können.

+0

Es ist lustig, dass Sie, weil In meiner AST-Darstellung habe ich einen Knoten namens "ASTStmtExpr" nur dafür! Ich glaube, ich beginne zu verstehen, irgendwie ... Hier ist, was ich unsicher bin: Aufgrund der Einschränkungen dieser Kommentar Antworten habe ich eine snipplet einzufügen: \t Leere Compiler :: Besuch (const ASTStmtExpr & expr_stmt, std :: shared_ptr func) \t \t { \t \t \t expr_stmt.expr() -> akzeptieren (* this, func); \t Sie sagen, ich sollte ein OP_POP danach hinzufügen, und für Dinge wie Zuweisungen würde ich ein dummy "Nil" -Objekt drücken, so dass es dann geknallt würde? –

+0

Entschuldigung, ich wusste nicht, dass die Kommentare nicht formatiert sind. –

+1

Für Zuweisungen nein, drücken Sie keinen Dummy-Wert, weil Sie das Ergebnis der Zuweisung bereits auf dem Stapel haben. Eine Zuweisung ist nur ein Ausdruck, der den Operator '=' verwendet, der sich nicht von '+' oder '-' unterscheidet, außer' = 'hat einen Nebeneffekt der Zuweisung zu einer Variablen. Ansonsten verhält es sich wie alle anderen Operatoren. –

2

Sie benötigen einen intelligenteren Parser. Wenn Sie einen Ausdruck sehen, dessen Wert nicht verwendet wird, müssen Sie einen POP ausgeben.

+0

Hallo, danke für die Antwort. Ich bin immer noch in den frühen Phasen der Programmierung Compiler und ich habe über eine Optimierung wie folgt gedacht, aber war nicht in der Lage, eine machbare Lösung zu finden :(Vielleicht werde ich es wieder versuchen, wieder danke !! –

0

Dies ist eine wichtige Gelegenheit zur Lernoptimierung. Sie haben eine Funktion, die Zahl, aber Ganzzahl Mathe, das int Math-Ergebnis wird nicht einmal in irgendeiner Weise, Form oder Form verwendet.

Wenn Ihr Compiler die Funktion optimieren würde, würde sich eine Menge Bytecode reduzieren, der für nichts generiert und ausgeführt wird!

Verwandte Themen