Es ist möglich (wenn mühsam), direkten Maschinencode zu schreiben. Vielleicht schreiben Sie das Programm in Assembler auf ein Blatt Papier und übersetzen es dann von Hand in die numerischen Maschinencode-Anweisungen, die Sie in den Maschinenspeicher eingeben. Sie können den Assembler-on-Paper-Schritt sogar überspringen, wenn Sie die numerischen Werte aller Maschinencodeanweisungen gespeichert haben - heutzutage keine Seltenheit, ob Sie es glauben oder nicht!
Die ersten Computer wurden direkt in Binärform programmiert, indem die physischen Schalter umgeschaltet wurden. Es war eine große Produktivitätsverbesserung, als die Hardware so weiterentwickelt wurde, dass der Programmierer (oder der Dateneingabeassistent) den Code in hexadezimalen Zahlen über eine Tastatur eingeben konnte!
Ein Software-Assembler wurde erst relevant, als mehr Speicher verfügbar wurde (da der Assembler-Code mehr Platz beansprucht als der unformatierte Maschinencode) und die Hardware so entwickelt wurde, dass alphanumerische Eingaben möglich sind. Die ersten Assembler wurden also direkt von Leuten geschrieben, die fließend mit Maschinencode umgehen können.
Wenn Sie einen Assembler haben, können Sie einen Compiler für eine höhere Sprache in Assembler schreiben.
Die Geschichte für C hat mehrere Schritte. Der erste C-Compiler wurde in B (ein Vorgänger von C) geschrieben, der wiederum in BCPL geschrieben wurde. BCPL ist eine ziemlich einfache Sprache (zum Beispiel hat sie überhaupt keine Typen), ist aber immer noch ein Schritt weiter als Raw Assembler. Sie sehen also, wie allmählich komplexere Sprachen in einfacheren Sprachen erstellt werden, bis hin zu Assembler. Und selbst C ist für heutige Verhältnisse eine ziemlich kleine und einfache Sprache.
Heutzutage wird der erste Compiler für eine neue Sprache oft in C geschrieben, aber wenn die Sprache eine bestimmte Reife erreicht, wird sie oft "in sich selbst" umgeschrieben. Der erste Java-Compiler wurde in C geschrieben, später jedoch in Java umgeschrieben. Der erste C # -Compiler wurde in C ++ geschrieben, aber vor kurzem wurde er in C # umgeschrieben. Der Python-Compiler / -Interpreter ist in C geschrieben, aber das PyPy-Projekt ist ein Versuch, es in Python umzuschreiben.
Es ist jedoch nicht immer möglich, einen Compiler / Interpreter für eine Sprache in der Sprache selbst zu schreiben. Ein in JavaScript geschriebener JavaScript-Interpreter ist vorhanden, aber die Compiler / Interpreter in aktuellen Browsern sind aus Leistungsgründen immer noch in C oder C ++ geschrieben. In JavaScript geschriebenes JavaScript ist einfach zu langsam.
Sie müssen C jedoch nicht als "Startsprache" für einen Compiler verwenden. Der erste F # -Compiler wurde in OCaml geschrieben, der anderen Sprache, die mit F # am engsten verwandt ist. Wenn der Compiler fertig war, wurde er in F # umgeschrieben. Der erste Compiler für Perl 6 wurde in Haskell geschrieben (eine reine funktionale Sprache, die sich von Perl stark unterscheidet), verfügt jedoch jetzt über einen Compiler in C.
Ein interessanter Fall ist Rust, wo der erste Compiler in OCaml geschrieben wurde (jetzt ist er in Rust umgeschrieben). Dies ist insofern bemerkenswert, als OCaml im Allgemeinen als höher eingestuft wird als Rust, eine Sprache, die den Metallsystemen näher kommt. Es handelt sich also nicht immer um Sprachen höherer Ebenen, die in Sprachen niedrigerer Ebenen implementiert sind, sondern möglicherweise auch umgekehrt.