Wie programmiert man Programmiersprachen?

3 Antworten

Vom Beitragsersteller als hilfreich ausgezeichnet

Die Ur-Programmiersprache sind die Opcodes, die der Prozessor verarbeiten kann. Diese wurden beim Entwurf des Prozessors festgelgt und dann als Hardware realisiert. Beim 4004 waren die noch übersichtlich, heute füllt man damit komplette Bücher bei x86_64. Die Ablaufsteuerung im Przessor schaltet anhand der Opcodes entsprechend Bustreiber der internen Prozessorbusse, die die entsprechenden Eingabeoperanden von den Eingaberegistern zu den Eingängen der Recheneinheiten führen und deren Ausgang dann mit dem Eingang des Zielregisters verbinden. So ein z.B. Addierer sind dann nur eine logische Schaltungen, die parallel je nach der Verarbeitungsbreite 4,8 oder 64 mal vorhanden ist. Ebenso sind die Register, die intern die Operanden speichern, eben "nur" viele D-Flip-Flops. Neben den Rechenoperationen stellt das Steuerwerk natürlich auch noch Befehle zur Kommunikation mit dem Arbeitsspeicher, Peripherie, Sprungfehle (bedingt/unbedingt), etc. bereit.

Die Assemblerbefehle sind eine 1:1 Abbildung auf die Opcodes und dienen nur dazu, dass man sich beim Programmieren nicht die Zahlen merken muss. Ein Assembler "hilft" bei der Programmierung noch ein wenig mehr, indem er es erlaubt, symbolische Namen für Speicheradressen zu verwenden, die er dann bei der Übersatzung des Programmes selbst in die entsprechende Zahl umsetzt. Aber ansonsten schreibt man in Assembler den reinen Maschinencode.

Alle höheren Programmiersprachen dienen nur dazu, um dem Menschen das Erstellen von Programmen, das Wiederverwenden von Code, den Austausch von Code zwischen verschiedenen Plattformen, etc. durch eine höhere Abstraktionsebene zu vereinfachen. Im Endeffekt wird durch die entsprechenden Compiler oder Interpreter immer der prozessorspezifische Maschinencode erzeugt / ausgeführt, das aber ggf. über mehrere Zwischenstufen.

Zum Compilerbau haben meine Vorredner jetzt schon einiges geschrieben, das umfasste in meinem Studium eine komplette Vorlesung, die sich ausschließlich damit beschäftigte, das ist jetzt nicht in ein paar Sätzen zusammenzufassen...

Woher ich das weiß:Berufserfahrung – Softwareentwickler & Admin

Das ist ein bisschen wie das Henne-Ei-Problem. Was war zuerst da? Der Compiler oder das Programm, welches mit dem Compiler übersetzt wurde? Ein Compiler besteht aus mehreren Teilen, u.a. dem Lexer, Parser und Treewalker. Programmiersprachen funktionieren grundsätzlich nach dem Prinzip der Grammatiken, einem Konstrukt aus der theoretischen Informatik. Es ist sehr interessant, sich mal damit zu befassen.

Sprachen an sich werden oft als Spezifikation entwickelt. Die ersten Compiler werden oft in bestehenden Sprachen geschrieben.

Von ganz unten zu modernen Sprachen zu kommen, nennt sich "Bootstrapping": https://de.wikipedia.org/wiki/Bootstrapping_(Programmierung)

Je nach Situation kann das verschiedene Formen annehmen. Im Extremfall startet man mit einem Prozessor, welcher Maschinensprache ausführen kann und in welchem man solche Programme laden kann (ob durch physische Schalter oder moderne Speicherchips). So wird dann in dieser Maschinensprache erst Assembler oder Compiler für Teilmengen einfacher Sprachen wie C geschrieben, in denen kompliziertere Compiler geschrieben werden, welche schließlich die ersten Versionen der Compiler für die gewünschte Programmiersprache bauen.

Wenn eine Sprache sich selbst kompiliert, gibt es entweder alternative Compiler in anderen Sprachen oder Versionen, welche sich sukzessiv bauen. Siehe z. B.: https://rustc-dev-guide.rust-lang.org/building/bootstrapping/what-bootstrapping-does.html

Woher ich das weiß:eigene Erfahrung – Langjähriger Poweruser & praktische Programmiererfahrung