Es posible (si es tedioso) escribir código de máquina directo. Tal vez escriba el programa en un ensamblador en un pedazo de papel y luego lo traduzca a mano en las instrucciones numéricas del código de máquina que ingresa en la memoria de la máquina. Incluso puede omitir el paso de ensamblador en papel si ha memorizado los valores numéricos de todas las instrucciones del código de máquina. ¡No es raro en esos días, créalo o no!
Las primeras computadoras fueron programadas directamente en binario al conmutar los interruptores físicos. Fue una gran mejora en la productividad cuando el hardware evolucionó para permitir que el programador (o el asistente de ingreso de datos) ingrese el código en números hexadecimales a través de un teclado numérico.
Un ensamblador de software solo se volvió relevante cuando se disponía de más memoria (ya que el código del ensamblador ocupa más espacio que el código de máquina sin procesar) y el hardware evolucionó para permitir la entrada alfanumérica. Así que los primeros ensambladores fueron escritos directamente por personas que dominaban el código de la máquina.
Cuando tienes un ensamblador, puedes escribir un compilador para un lenguaje de nivel superior en ensamblador.
La historia de C tiene múltiples pasos. El primer compilador de C se escribió en B (un antecesor de C) que a su vez se escribió en BCPL. BCPL es un lenguaje bastante simple (por ejemplo, no tiene tipos en absoluto), pero aún es un paso adelante del ensamblador en bruto. Así que ya ves cómo los lenguajes gradualmente más complejos se construyen en lenguajes más simples hasta el ensamblador. Y en sí, C es un lenguaje bastante pequeño y simple para los estándares de hoy.
Hoy en día, el primer compilador para un nuevo lenguaje a menudo se escribe en C, pero cuando el lenguaje alcanza una cierta madurez, a menudo se reescribe "en sí mismo". El primer compilador de Java se escribió en C, pero luego se reescribió en Java. El primer compilador de C # se escribió en C ++, pero recientemente se ha reescrito en C #. El compilador / intérprete de Python está escrito en C, pero el proyecto PyPy es un intento de volver a escribirlo en Python.
Sin embargo, no siempre es posible escribir un compilador / intérprete para un idioma en el idioma mismo. Existe un intérprete de JavaScript escrito en JavaScript, pero los compiladores / intérpretes en los navegadores actuales todavía están escritos en C o C ++ por razones de rendimiento. JavaScript escrito en JavaScript es simplemente demasiado lento.
Pero no tienes que usar C como el "idioma de inicio" para un compilador. El primer compilador de F # se escribió en OCaml, que es el otro idioma que está más relacionado con F #. Cuando se completó el compilador, se reescribió en F #. El primer compilador para Perl 6 fue escrito en Haskell (un lenguaje funcional puro muy diferente de Perl) pero ahora tiene un compilador escrito en C.
Un caso interesante es Rust, donde el primer compilador se escribió en OCaml (ahora se reescribe en Rust). Esto es notable porque OCaml generalmente se considera un nivel más alto que Rust, que es un lenguaje de sistemas más cercano al metal. Por lo tanto, no siempre se implementan lenguajes de nivel superior en idiomas de nivel inferior, también puede ser al revés.