Gibt es einen wirklichen Unterschied zwischen einem Compiler und einem Assembler?

14

Gibt es einen Unterschied zwischen den beiden? Gemäß Ullmans Buch konvertieren Compiler eine Sprache in eine andere (normalerweise niedrige) Sprache, und ein Assembler auch. Wie unterscheiden sich die beiden?

gpuguy
quelle
1
Ein Assembler ist ein Compiler, der bestimmte Aufgaben ausführt. Die Begriffe sind in der Praxis etwas unterschiedlich, aber es gilt die grundlegende Definition von "Compiler" (Übersetzen zwischen Sprachen).
Raphael
Alle Assembler sind (einfache) Compiler, da sie eine Sprache in eine andere transformieren. Nicht alle Compiler sind Assembler.
user253751

Antworten:

16

Ein Assembler übersetzt Assembler-Code in Maschinencode. Die Übersetzung ist mechanisch und kann nur auf eine Weise erfolgen. Im Gegensatz dazu hat ein Compiler mehr Freiheit, wenn er die entsprechende Programmiersprache kompiliert - er kann zum Beispiel optimieren und selbst nicht optimierende Compiler produzieren unterschiedlichen Code. Außerdem können Compiler so geschrieben werden, dass das "Front-End" (entsprechend der Programmiersprache) und das "Back-End" (entsprechend der Computerarchitektur) getrennt werden, wohingegen bei Assemblern die beiden immer gleich sind.

Yuval Filmus
quelle
1
Warum kann die Übersetzung nur auf eine Weise erfolgen? Bedeutet das, dass der ursprüngliche ASM-Code für einen bestimmten Maschinencode (und eine bestimmte Zielarchitektur) nicht generiert werden kann? Das klingt für mich kontraintuitiv. Denn wenn ein bestimmter Maschinencode-Befehl mehreren asm-Befehlen zugeordnet werden kann, wie entscheidet die Maschine dann, welcher Befehl ausgeführt wird? Vermisse ich etwas?
Utku
2
Ich fürchte, Sie haben die Bedeutung von "Einbahnstraße" hier falsch verstanden. Dies bedeutet, dass bei einem Assembler-Code eine einzige Übersetzung T ( A ) von A in Maschinencode vorliegt. EINT(EIN)EIN
Yuval Filmus
Danke, ich sehe auch, dass in Ullmans Buch ein Compiler ein Frontend und ein Backend hat. Wenn ich richtig liege, führt das Backend die Optimierung in einer Zwischensprache, die Generierung von Maschinencode und die Optimierung des Maschinencodes durch. Jede der drei Aufgaben kann auf mehrere Arten ausgeführt werden. Ist das "Backend" ein Assembler? Ist die Zwischensprache eine Assemblersprache? Ich denke ja, aber in Ihrer Antwort wird erwähnt, dass ein Monteur seine Arbeit nur auf eine Art und Weise erledigt.
StackExchange for All
Ich habe es hier gepostet. Cs.stackexchange.com/questions/98854/…
StackExchange for All
Die Zwischensprache bezieht sich normalerweise auf eine Sprache, die maschinenunabhängig ist.
Yuval Filmus
11

Unterm Strich macht es mehr Spaß , einen Compiler zu schreiben als einen Assembler. Assemblersprachen sind in der Regel so konzipiert, dass sie für das Parsen und die Typprüfung nahezu trivial sind und eine Vielzahl tabellengesteuerter Generatoren umfassen ("der Opcode für das Hinzufügen ist 01110", "für Ladeanweisungen wird das Zieloperandenregister durch die Bits 17 bis 21 angegeben "). Normalerweise ist der interessanteste Teil eines Assemblers der Teil, der symbolische Beschriftungen in Zahlen auflöst.

Die meisten Assembler können jedoch eine kleine Menge an Arithmetik ausführen (z. B. symbolische Beschriftungen mit kleinen Konstanten addieren), und die meisten Assembler verfügen über eine Makroverarbeitungseinrichtung oder sind in diese integriert. (Auf den meisten Unix-Systemen wird die Makrofunktion tatsächlich bereitgestellt, indem der C-Pre-Prozessor über die Assembly ausgeführt wird, bevor er an den Assembler übergeben wird.)

Der MIPS-Assembler musste noch einen Schritt weiter gehen, einige interessante Entscheidungen zur Codegenerierung treffen und einige Optimierungen vornehmen. Die MIPS-Maschinensprache erfordert unterschiedliche Codesequenzen, um beispielsweise unterschiedliche Konstanten zu laden, und so musste der Assembler die Codesequenz nach dem Erstellen der Konstante auswählen . Ferner war der MIPS-Maschinencode mit Verzögerungsschlitzen behaftet , aber es lag in der Verantwortung des Assemblers, diese zu abstrahieren und dem Compiler eine "normalere" abstrakte Assemblersprache zu präsentieren. Daher muss der MIPS-Assembler eine lokale Anweisungsplanung durchführen.

Die Unterscheidung wird durch einige Arbeiten von Norman Ramsey weiter verwischt , insbesondere durch seine C - portable Assemblersprache. (Das relevante Papier ist Ramsey und Peyton Jones, "Eine einzelne Zwischensprache, die mehrere Implementierungen von Ausnahmen unterstützt", Prog. Lang. Impl. Und Dsgn. , (PLDI-21): 285–298, 2000. ) Und schließlich ist auch eine typisierte Assemblersprache von David Walker und Greg Morrisett mit einem Assembler, der die Speichersicherheit gewährleisten kann.

Wandering Logic
quelle
0

Hier ist die Realität etwas komplizierter. Ich würde erwarten, dass der Unterschied zwischen einem Assembler (A) und einem Compiler (C) unter anderem ist:

  1. Eine Zeile Quellcode bezieht sich direkt auf einen CPU-Opcode (A) oder nicht (C)
  2. In hohem Maße abhängig von der tatsächlichen CPU (A) oder maschinenunabhängig (C)

Wir neigen dazu, die Assemblersprache "Low Level" und die Quellsprache, die ein Compiler versteht, "High Level" zu nennen (dies ist eine grobe Vereinfachung, aber immer noch).

In der Assemblersprache können Sie beispielsweise eine Additionsoperation ausführen, indem Sie sagen:

  • a, b hinzufügen (für eine bestimmte CPU)
  • addiere R5, R6 (für eine andere CPU)
  • add (A5), D2 (für eine andere CPU)

In einer höheren Sprache könnten Sie schreiben:

  • x = y + z;

Und dies kann in Abhängigkeit von einer Reihe von Umständen zu einer Anweisung oder zu Hunderten von Anweisungen führen. Eine davon ist die CPU, für die der Compiler Anweisungen erstellt.

Wie Sie sehen, ist die Assembler-Quellsprache am häufigsten: (A) Eine Zeile Quellcode gibt eine Zeile CPU-Opcodes an, und dies hängt sehr stark von der CPU ab, auf die Sie abzielen. Ein C-Compiler (High Level Language) verarbeitet all diese Details für Sie - eine Zeile Quellcode kann Null werden, ein oder mehrere CPU-Opcodes, und der Compiler verarbeitet die Details dessen, was die CPU tun kann.

Ein Compiler besteht heute oft aus mehreren verschiedenen Phasen. Sie könnten als Frontend / Backend oder als andere Dinge bezeichnet werden. Ich sehe sie normalerweise als vier Stufen:

  1. In der ersten Phase wird der eigentliche Quellcode gelesen und eine interne Darstellung erstellt. Diese Phase kennt die eigentliche Ausgangssprache.
  2. Die zweite Stufe befasst sich mit der internen Darstellung und führt eine Reihe von Optimierungen durch. Heutzutage versucht der Compiler normalerweise, das Programm schneller zu machen, und kümmert sich nicht darum, ob es größer wird. Die Optimierung erfolgt auf der internen Darstellung. Interessanterweise könnten Teile davon für mehrere verschiedene Sprachen allgemein sein.
  3. Die dritte Stufe übernimmt die interne Darstellung und erstellt den tatsächlichen Code für die ausgewählte CPU. Es gibt möglicherweise mehrere verschiedene Versionen dieser Phase, die auf unterschiedliche CPUs abzielen. Tatsächlich könnten Sie den Quellcode einmal schreiben und ihn dann für verschiedene CPUS-s kompilieren.
  4. Letzte Vorbereitungen für das "Verpacken" des Programms (diese Phase könnte ein Linker sein).

Gute Compiler zu schreiben, ist ein hochqualifizierter Beruf - ein Toy Language Compiler kann an einem Nachmittag von einem Amateur erstellt werden (oder auch etwas länger).

Ghellquist
quelle