Ich habe seit vielen Jahren Mühe, den Unterschied zwischen Interpreten und Compilern zu erklären. Zu den Ursachen gehören verschiedene Dinge wie Missverständnisse, die durch die Verwechslung der Programmiersprache mit ihrem Verarbeitungssystem verursacht werden, solche, die durch den Unterschied zwischen dem Inneren und dem Äußeren des Verarbeitungssystems verursacht werden, und solche, die auf historischen Hintergrund zurückzuführen sind. Ich bin. Daher ist es schwierig, die Definitionen des Interpreters und des Compilers kurz zu beschreiben, und es wird angenommen, dass eine Struktur erstellt wurde, in der Missverständnisse zu Missverständnissen führen. Daher möchte ich in diesem Artikel den Unterschied zwischen dem Interpreter und dem Compiler anhand des Ben-Diagramms erläutern, um die Situation so weit wie möglich zu verbessern.
(Dieser Artikel wurde inspiriert von "Erklärung des Unterschieds zwischen Interpreten und Compilern unter Verwendung einer mathematischen Sprache - Qiita". .)
Zuerst werde ich kurz " Interpreter
"und" Compiler
" erklären. Dies sind die Konzepte, die mit dem "Verarbeitungssystem" der Programmiersprache verbunden sind, und sie unterscheiden sich in einfachen Worten in der Implementierungsmethode der Programmiersprache. Der Interpreter "" interpretiert "" und "" führt die Zielprogrammiersprache aus. Die Interpretation hier besteht darin, basierend auf der Semantik der Programmiersprache zu entscheiden, wie dies zu tun ist. Im Gegensatz zum Interpreter beinhaltet der Compiler keine "Ausführung" und übersetzt nur die Zielsprache in eine andere Sprache. Grundsätzlich kann jede Programmiersprache entweder als "Interpreter" oder als "Compiler" implementiert werden [^ 1].
Es scheint eine einfache und klare Definition zu sein, so viel zu schreiben, aber in Wirklichkeit ist das Obige die Definition von ** "breit definiert" **, und für die Klassifizierung anhand der Realität ist etwas mehr Einfallsreichtum erforderlich.
[^ 1]: Dieser Artikel setzt eine Programmiersprache voraus, die auf einem Neumann-Computer ausgeführt werden kann. Ich werde es in diesem Artikel nicht behandeln, da es verwirrend wird, Quantencomputer zu entwickeln.
Als ich zum ersten Mal versuchte, es mit einem Diagramm zu erklären, war ich sehr besorgt darüber, wie ich es ausdrücken sollte, aber am Ende bekam ich das folgende Ben-Diagramm.
Ich wollte es so einfach wie möglich schreiben, aber ich denke, es gibt einige Teile, in denen die Absicht schwer zu lesen ist, deshalb möchte ich es kurz erklären.
Erstens bedeutet ein breiterer Compiler einfach eine "Übersetzung" in eine andere Programmiersprache, aber ein typisches Compiler-Image ist von einer Hochsprache in eine Niedrigsprache (Maschinensprache oder nahe an Maschinensprache), wie C- und Java-Compiler. Bytecode) wird übersetzt. Daher ist dieses Bild als "Compiler im engeren Sinne" definiert.
Als nächstes ist "Übersetzer" ein Verarbeitungssystem, das in dieselbe Programmiersprachenebene konvertiert. Es ist nicht eindeutig, "gleiche Ebene" zu sagen, aber wenn Sie nur drei Kategorien berücksichtigen, Maschinensprache, Bytecode und andere Hochsprachen, sind sie ungefähr gleich. Der Assembler übersetzt die Assemblersprache (Mnemonik) in eine Maschinensprache, die als Übersetzer betrachtet werden kann, da es sich fast um eine Eins-zu-Eins-Konvertierung auf derselben Ebene handelt [^ 2]. Der Parser bezieht sich in dieser Abbildung auf den Prozess der Konvertierung einer Programmiersprache in einen abstrakten Syntaxbaum (AST). Ich denke jedoch, dass der Parser auch als Übersetzer klassifiziert werden kann, wenn AST als eine Art formale Sprache angesehen wird. [^ 3]. Das Verarbeitungssystem von AltJS (TypeScript, CoffeeScript, Dart, PureScript, Elm, Scala.js, Opal ...) ist ebenfalls eine Art Übersetzer und wird oft als "Transpiler" bezeichnet. Diese Verarbeitungssysteme sind alternative Sprachen von JavaScript (Ursprung von AltJS), da die Konvertierungszielsprache auf JavaScript festgelegt ist.
[^ 2]: Der Assembler wird eigentlich nicht als "Übersetzer" oder "Compiler" bezeichnet, nur weil er konzeptionell als solcher klassifiziert werden kann. [^ 3]: Die Konvertierung in einen abstrakten Syntaxbaum ändert nichts an der Semantik der ursprünglichen Programmiersprache. Ich hatte das Gefühl, dass sie einem Übersetzer näher steht als einem Compiler, aber es ist keine allgemeine Interpretation.
Der Interpreter hat die Sprache ursprünglich direkt interpretiert und ausgeführt, wie das Verarbeitungssystem der frühen BASIC-Sprache. Daher wird der Interpreter dieses Bildes "Interpreter im engeren Sinne" genannt. Nur wenige Verarbeitungssysteme sind auf diese Weise in modernen High-End-Sprachen implementiert. Dies liegt daran, dass moderne High-End-Sprachen entwickelt wurden, um den Umgang mit Menschen zu erleichtern, und nicht für die direkte Computerausführung geeignet sind. Umgekehrt werden Sprachverarbeitungssysteme (JVMs) für Low-Level-Sprachen wie Java-Bytecodes anstelle von High-Level-Sprachen auch als "Bytecode-Interpreter" bezeichnet und fallen unter die Kategorie "Interpreter im engeren Sinne".
Wenn Sie ein modernes Hochsprachenverarbeitungssystem als Dolmetscher implementieren möchten, werden Sie mit ziemlicher Sicherheit einen "indirekten Dolmetscher" implementieren. Der Interpreter "indirekte Interpretation" ist eine Methode, um den ursprünglichen Quellcode vorübergehend in einen einfach auszuführenden Zwischenausdruck wie einen abstrakten Syntaxbaum (AST) oder Bytecode umzuwandeln und auszuführen. Dies ist ein typisches Verarbeitungssystem für sogenannte Lightwight Language / LL wie Python, Ruby und JavaScript. Wie einige von Ihnen vielleicht bereits bemerkt haben, bedeutet die Konvertierung in "Zwischendarstellung", dass eine potenziell compileräquivalente Verarbeitung im Interpreter implementiert ist. Dies ist der Grund, warum sich der Interpreter im weiteren Sinne und der Kreis der indirekten Interpretation mit dem Compiler im Ben-Diagramm überschneiden. Insbesondere in neueren Interpreter-Verarbeitungssystemen wird das Bytecode-Format, für das die Optimierungsforschung voranschreitet, häufig für die "Zwischendarstellung" verwendet und unter vollständiger Nutzung der für den Compiler entwickelten Technologie entwickelt.
Die Aufteilung von Compiler und Interpreter ändert sich, wenn sich der Kontext wie Ansichtspunkt, Ansichtspunkt und Sichtfeld ändert. Wenn Sie beispielsweise mit dem aktuellen CRuby-Verarbeitungssystem (Ruby-Verarbeitungssystem in C-Sprache) erklären, wird das CRuby-Verarbeitungssystem aus Sicht des Benutzers der Ruby-Sprache als Interpreter erkannt. Dies liegt daran, dass der CRuby-Prozessor die Ruby-Sprache zu interpretieren und auszuführen scheint. Wenn Sie jedoch Ihren Ansichtspunkt innerhalb des CRuby-Verarbeitungssystems verschieben, ändert sich die angezeigte Szenerie. Im CRuby-Verarbeitungssystem wird zuerst der Prozess der Konvertierung der Ruby-Sprache in einen abstrakten Syntaxbaum ausgeführt und dann in den für das CRuby-Verarbeitungssystem eindeutigen Bytecode konvertiert. Danach arbeitet der für das CRuby-Verarbeitungssystem eindeutige Bytecode-Interpreter und führt den generierten Bytecode aus. Auf diese Weise werden, wenn Sie es von innen genauer betrachten, "Übersetzer" ausgeführt, der die Ruby-Sprache in AST konvertiert, und "Compiler im engeren Sinne, der AST in CRuby-Verarbeitungsbytecode konvertiert" und "CRuby-Verarbeitungsbytecode" ausgeführt Sie können sehen, dass der "Interpreter im engeren Sinne" funktioniert. Wenn Sie Ihre Perspektive weiter in den Bytecode-Interpreter verschieben, können Sie auch sehen, dass dort der JIT-Compiler ausgeführt wird [^ 4]. Wenn Sie diesmal Ihren Horizont erweitern, verfügt die Ruby-Sprache auch über ein Verarbeitungssystem namens JRuby, das auf JVM ausgeführt wird. JRuby wird mit einem "Pre-Compiler" (Ahead-Of-Time-Compiler) geliefert, mit dem Sie Ruby-Skripte im Voraus in Java-Bytecode "kompilieren" können.
Um ein Beispiel für Java zu geben, wurde Jshell aus Java 9 eingeführt. Da es sich um eine sogenannte REPL (Read-Eval-Print Loop) handelt, kann sie aus Anwendersicht als ** Interpreter-Verarbeitungssystem ** angesehen werden. Ich werde. Da Java 11 Java-Dateien sofort ausführen konnte, ist dies das korrekte Verhalten des Interpreters, und es ist die Ausführungsmethode, mit der leichte Programmiersprachen wie Ruby bisher gut umgehen konnten.
Auf diese Weise erfahren Programmiersprachen und ihre Verarbeitungssysteme derzeit eine große Entwicklung, Komplexität und Diversifizierung. Infolgedessen sind Interpreter und Compiler verschachtelt, haben eine mehrstufige Struktur und mehrere Verarbeitungssysteme. Daher ist es sehr wichtig, aus welchem Kontext Sie den "Compiler" oder "Interpreter" betrachten. Mit anderen Worten, was Sie als Dolmetscher aus Ihrer eigenen Sicht sehen, kann sich von anderen Sichtweisen unterscheiden. Daher sollten Sie den Kontext genau beachten, wenn Sie darüber sprechen.
[^ 4]: Der JIT-Compiler (experimentell) ist optional in Ruby 2.6 verfügbar.
In diesem Artikel habe ich versucht, den Unterschied zwischen dem Interpreter und dem Compiler mithilfe des Ben-Diagramms zu erklären. Die Zusammenfassung ist wie folgt.
―― „Interpreter“ und „Compiler“ sind die Implementierungsmethoden des Sprachverarbeitungssystems und nicht mit der Programmiersprache verknüpft.
interpretiert
" und "führt
" die Zielprogrammiersprache aus.Bens Diagramm organisiert auch moderne Interpreten und Compiler auf rationale und intuitive Weise und respektiert gleichzeitig historische Interpretationen. Die Überlappung der Kreise soll auch ausdrücken, dass die obere Schicht die untere Schicht enthalten kann.
Wir hoffen, dass dieser Artikel Ihnen hilft, Ihre Interpreten und Compiler besser zu verstehen und neue Entdeckungen zu machen.
Recommended Posts