Frage

Könnte mir jemand bitte Ratschläge/Ideen geben, wie man mit den Situationen umgeht, in denen es erforderlich ist, um weitere Erklärungen zu betrachten, um im aktuellen Moment korrekte semantische Aktionen durchzuführen? Zum Beispiel ist es ein bekanntes Ereignis, wenn jemand einen Dolmetscher/Compiler einer Programmiersprache schreibt, die "Vorwärtsdeklarationen" nicht unterstützt. Lassen Sie uns ein Beispiel haben:

foo(123);//<-- our parser targets here. we estimate we have a function 
         //    invocation, but we have no idea about foo declaration/prototype,
         //     so we can't be sure that "foo" takes one integer argument.   


void foo(int i){
//...
}

Es ist ziemlich klar, dass wir mindestens zwei Pässe haben müssen. Erstens analysieren wir alle Funktionserklärungen und erhalten alle erforderlichen Informationen wie: die Menge Argumente, die die Funktion ausübt, ihre Typen und dann können wir mit Funktionsaufrufen und der Lösung der Schwierigkeiten wie oben gelöst werden. Wenn wir diesen Weg gehen, müssen wir alle diese Pässe mit einigen tun Ast Mechanismen/Besucher durchqueren. In diesem Fall müssen wir uns mit AST befassen, um Besucher zu überqueren/anzuwenden, und wir müssen uns mit dem "guten Auf Wiedersehen" auf die Schönheit von Phoenix -Konstruktionen, die direkt in unsere Parser integriert sind, sagen.

Wie würden Sie damit umgehen?

War es hilfreich?

Lösung

2. Antwort auf Semantik] Dieses spezielle Beispiel ist einfach. Was Sie tun können, sind Aufzeichnungsaufrufe für noch nicht deklarierte Funktionen und die tatsächlichen Argumententypen. Wenn Sie später auf eine Funktionserklärung stoßen, überprüfen Sie, ob vorhandene Funktionsaufrufe (besser) mit dieser neuen Funktion übereinstimmen. Sie werden offensichtlich Fehler erst am Ende des Parse erkennen, weil die allerletzte Zeile eine fehlende Funktion einführen könnte. Nach dieser Zeile ist jedoch jeder Funktionsaufruf, der überhaupt nicht übereinstimmt, ein Fehler.

Das Problem ist, dass dies für einfache Semantik funktioniert. Wenn Sie sich komplexere Sprachen ansehen - z. B. mit C ++ - wie Funktion Vorlagen - Es wird nicht mehr möglich, solche Lookups in einer einfachen Tabelle durchzuführen. Sie benötigen spezielle Tabes, die strukturell Ihren Sprachkonstrukten entsprechen. Ein AST ist einfach nicht die beste Struktur für diese, geschweige denn der teilweise AST während der Parsen.

Andere Tipps

Wenn Sie zwei Pässe durchführen möchten, können Sie anstelle einer semantischen Überprüfung am Ende des ersten Pass

[functionCall(name, args)]
[functionDef(name, args, body)]

Sie würden so etwas definiert (keine richtige Spiritsyntax, aber Sie verstehen den Punkt)

functionCall(string name, vector<string> args)
{
  if (!first_pass) {
    // check args for validity
    // whatever else you need to do
  }
} 

functionDef(string name, vector<string> args, ... body)
{
  if (first_pass)
    // Add function decleration to symbol table
  else
    // define function
}

Ich denke, Sie treffen unbegründete Annahmen. Zum Beispiel: "Es ist ziemlich klar, dass wir mindestens zwei Pässe haben müssen". Nein, es ist nicht. Wenn die Syntax so ist, dass foo(123) kann nur als analysiert werden function-name "(" expression ")", dann ist ein Pass genug.

Daher würde ich empfehlen, Ihre Syntax für eindeutiges Parsen zu entwerfen. Vermeiden Sie Konstrukte, die nicht isoliert analysiert werden können, z.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top