Es posible (si es tedioso) escribir código de máquina directo. Tal vez escriba el programa en el ensamblador en una hoja 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 del 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 se programaron directamente en binario mediante interruptores físicos. ¡Fue una gran mejora de productividad cuando el hardware evolucionó para permitir que el programador (o el asistente de entrada de datos) ingrese el código en números hexadecimales a través de un teclado!
Un ensamblador de software solo se volvió relevante cuando hubo más memoria disponible (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. Entonces, los primeros ensambladores fueron escritos directamente por personas que dominaban el código de la máquina.
Cuando tiene un ensamblador, puede 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 predecesor 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 está un paso por delante del ensamblador en bruto. Entonces verá cómo los lenguajes gradualmente más complejos se construyen en lenguajes más simples desde el ensamblador. Y en sí mismo, C es un lenguaje bastante pequeño y simple para los estándares actuales.
Hoy, 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 fue escrito en C, pero luego reescrito 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 reescribirlo en Python.
Sin embargo, no siempre es factible 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 tiene que usar C como el "lenguaje inicial" para un compilador. El primer compilador de F # se escribió en OCaml, que es el otro lenguaje que está más estrechamente 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 fue escrito en OCaml (ahora está reescrito 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 idiomas de nivel superior en idiomas de nivel inferior, sino que también puede ser al revés.