¿Cómo se hicieron los primeros compiladores?

70

Siempre me pregunto esto, y tal vez necesito una buena lección de historia sobre lenguajes de programación. Pero dado que la mayoría de los compiladores de hoy en día están hechos en C, ¿cómo se hicieron los primeros compiladores (AKA antes de C) o se interpretaron todos los lenguajes?

Dicho esto, todavía no entiendo cómo se hizo incluso el primer lenguaje ensamblador, entiendo qué es el lenguaje ensamblador, pero no veo cómo funcionaron el MUY primer lenguaje ensamblador (por ejemplo, ¿cómo hicieron el primer lenguaje ensamblador? comandos (como mov R21) o w / e establecido en el equivalente binario?

mosquito
fuente
9
Hubo un programador cómico inepto en mi equipo una vez, donde todo lo que hizo fue quejarse de C #. Solíamos bromear sobre un lenguaje ficticio que él inventó llamado Crunk. Un hecho poco conocido sobre Crunk, es el primer idioma donde el compilador TAMBIÉN fue escrito en Crunk. :)
maple_shaft
2
¿Por qué alguien se quejaría de C #? ¿nunca ha usado smalltalk o Lisp? lol
2
posible duplicado del compilador
vartec
44
@maple_shaft: para ser justos, el compilador gcc está escrito en C . Eso en realidad no es un problema si tienes un buen compilador cruzado para compilar la primera versión. El primer compilador de C, por supuesto, tuvo que estar escrito en otro idioma.
Scott Whitlock
55
posible duplicado de ¿Cómo se escribió el primer compilador?
Greg Hewgill

Respuestas:

89

Ja, he hecho esto. Muchas CPU tienen instrucciones simples de tamaño fijo que solo tienen un par de bytes. Por ejemplo, para una CPU simple como un Motorola 6800, puede ajustar todas sus instrucciones en una sola hoja de papel . Cada instrucción tendría un código de operación de dos bytes asociado y argumentos. Puede ensamblar un programa manualmente buscando el código de operación de cada instrucción. Luego escribiría su programa en papel , anotando cada instrucción con su correspondiente código de operación. Una vez que haya escrito su programa, puede grabar cada código de operación en secuencia en una EPROMque luego almacenaría su programa. Conecte la EPROM a la CPU con las instrucciones correctas en las direcciones correctas, y tendrá un programa de trabajo simple. Y para responder a su próxima pregunta, sí. Fue doloroso (hicimos esto en la escuela secundaria). Pero tengo que decir que conectar cada chip en una computadora de 8 bits y escribir un programa manualmente me dio una comprensión profunda de la arquitectura de la computadora que probablemente no podría haber logrado de otra manera.

Los chips más avanzados (como x86) son mucho más difíciles de codificar a mano, porque a menudo tienen instrucciones de longitud variable. Los procesadores VLIW / EPIC como Itanium son casi imposibles de codificar a mano de manera eficiente porque manejan paquetes de instrucciones optimizados y ensamblados por compiladores avanzados. Para nuevas arquitecturas, los programas casi siempre se escriben y ensamblan primero en otra computadora, luego se cargan en la nueva arquitectura. De hecho, para empresas como Intel que realmente construyen CPU, pueden ejecutar programas reales en arquitecturas que aún no existen ejecutándolas en simuladores. Pero yo divago...

En cuanto a los compiladores, en su forma más simple, pueden ser poco más que programas de "cortar y pegar". Podría escribir un "lenguaje de alto nivel" muy simple y no optimizador que simplemente agrupe instrucciones simples de lenguaje ensamblador sin mucho esfuerzo.

Si desea un historial de compiladores y lenguajes de programación, le sugiero que CONSIGA un historial de FORTRAN .

Dave Markle
fuente
27
. . . y no debería ser "... te sugiero JMP para una historia ..."
Binary Worrier
2
Lo siento mucho mucho. Pero tuve que hacerlo. Acabo de tener. a ...
Dave Markle
9
@Dave: ¿Te das cuenta de que Velociraptor te ha condenado a muerte ?
Binario Worrier
77
Ellos "sabían" porque estaban literalmente conectados para realizar esa operación cuando vieron una señal 101010100 para una instrucción dada. De hecho, tienen una unidad en chip responsable de las instrucciones de decodificación de instrucciones: en.wikipedia.org/wiki/Decoder
Dave Markle
77
Vale la pena agregar: el compilador para un nuevo idioma, cuando está escrito en ese mismo nuevo idioma, a veces se compila con un "protocompilador" escrito en otro idioma que produce código demostrablemente correcto, pero horriblemente ineficiente. Una vez compilado, se ejecuta sobre sí mismo para producir un compilador razonablemente rápido. Compare la máquina Von Neumann. : D
BMDan 01 de
54

De eso se trata el arranque del compilador (ya que nadie mencionó cómo se llama =).

El proceso de escribir un compilador (o ensamblador) en el lenguaje de programación de destino que se pretende compilar. La aplicación de esta técnica lleva a un compilador de alojamiento propio.

Muchos compiladores para muchos lenguajes de programación son bootstrap, incluidos los compiladores para BASIC, ALGOL, C, Pascal, PL / I, Factor, Haskell, Modula-2, Oberon, OCaml, Common Lisp, Scheme, Java, Python, Scala y más ... .

El problema del huevo y la gallina

Si se necesita un compilador para el lenguaje X para obtener un compilador para el lenguaje X (que está escrito en el lenguaje X), ¿cómo se escribió el primer compilador? Los posibles métodos para resolver este problema del huevo o la gallina incluyen:

  • Implementando un intérprete o compilador para el lenguaje X en el lenguaje Y. Niklaus Wirth informó que escribió el primer compilador Pascal en Fortran.
  • Otro intérprete o compilador para X ya se ha escrito en otro idioma Y; así es como Scheme a menudo se inicia.
  • Las versiones anteriores del compilador se escribieron en un subconjunto de X para el que existía algún otro compilador; así es como algunos superconjuntos de Java, Haskell y el compilador inicial de Free Pascal son bootstrapped.
  • El compilador para X se compila de forma cruzada desde otra arquitectura donde existe un compilador para X; así es como los compiladores para C generalmente se portan a otras plataformas. Además, este es el método utilizado para Free Pascal después del arranque inicial.
  • Escribir el compilador en X; luego compílelo a mano desde la fuente (muy probablemente de manera no optimizada) y ejecútelo en el código para obtener un compilador optimizado. Donald Knuth usó esto para su sistema de programación alfabetizado WEB ...
vides
fuente
Buen enlace que también te lleva a en.wikipedia.org/wiki/History_of_compiler_writing . En general, creo que los compiladores originales fueron escritos en lenguaje ensamblador ( en.wikipedia.org/wiki/Assembly_language ). Solo más tarde surgió la idea de bootstrapping o self-hosting.
Michael Levy
1
¡+1 FINALMENTE! Es extraño que esta sea solo la tercera respuesta mejor calificada. Sí, bootstrapping. Esa es la respuesta
Adam Rackis el
15

En última instancia, todas las computadoras funcionan con códigos binarios, que se introducen en la CPU. Estos códigos binarios son perfectamente naturales para una CPU, pero también perfectamente inútiles para los seres humanos. Una de las primeras formas de escribir un programa fue haciendo agujeros en las tarjetas. La posición de los agujeros representaba una posición de bit particular dentro de una palabra, y la presencia o ausencia del agujero se interpretaba como cero o uno. Estas tarjetas se colocaron en la secuencia correcta en una caja, y luego se introdujeron en un lector de tarjetas, que efectivamente las convirtió en código binario para la CPU (y su vida se perdería si dejara caer la caja).

Obviamente, los primeros programadores resolvieron los códigos binarios uno por uno y tenían una máquina para perforar las tarjetas. Esto es esencialmente programación en lenguaje ensamblador en sus manos y rodillas. Una vez que tenga eso, puede crear todas las demás cosas a partir de él: un editor de texto simple, un compilador de lenguaje ensamblador (para convertir las declaraciones de ensamblaje de texto en códigos binarios), un vinculador y un cargador. Y el resto, como dicen, es historia.

wolfgangsz
fuente
44
Antes de las tarjetas, tenía un conjunto de interruptores para la dirección, un conjunto para la palabra de datos y un interruptor para cargar los datos. Usted programó cada dirección de memoria individualmente configurando los interruptores de dirección y datos con la representación binaria y activó el interruptor de carga y luego lo apagó. Tomó años, pero el programa solo tenía unas pocas palabras; los bytes no se habían inventado entonces.
u
44
... Y antes de eso, tenías que volver a conectarlo . ¡Diversión diversión diversión!
Michael K
Sí, pero cuando tenía que hacer eso, no era realmente lo que pensaríamos como una computadora moderna, ya que la arquitectura de Von Neumann aún no se había inventado.
Dave Markle
7

Un poco de google muestra las Órdenes iniciales de EDSAC de finales de los años 40. Como era el primer ensamblador, probablemente estaba codificado en lenguaje máquina.

Más tarde llegaron ensambladores para otras máquinas, como SOAP I y II para IBM 650. SOAP Probablemente también estaba codificado en lenguaje de máquina, aunque no he encontrado la declaración definitiva.

Un poco más tarde llegó Fortran (traductor de fórmulas), para el IBM 704. Presumiblemente fue escrito en ensamblador para el 704. Un ensamblador temprano para el 701 se acredita a Nathan Rochester .

Si quieres tener una idea de cómo programar una computadora en lenguaje máquina, visita uno de mis sitios favoritos, la computadora de retransmisión de Harry Porter .

Mike Dunlavey
fuente
Santo cielo, la computadora de Harry Porter (casi dijo Harry Potter jajaja) es INCREÍBLE. Ojalá entendiera cómo se construyó algo así :(.
1
@Sauron: Harry Porter no quisiera nada mejor que decírtelo. Fuera de esa página , tiene un powerpoint bellamente diseñado que lo explica todo. Asume algunos conocimientos básicos de circuitos, pero eso no es demasiado difícil de obtener.
Mike Dunlavey
Sé que solo estoy jugando ^ _ ^, independientemente de que sea una máquina muy impresionante y estoy seguro de que se dedicaron muchas horas de asistente :).
6

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.

JacquesB
fuente
3

Suponiendo que está comenzando con un conjunto de instrucciones simple y nada más, comenzaría creando un ensamblador o compilador mínimo , apenas funcional que pueda cargar un archivo, analizar un subconjunto mínimo del idioma de destino y generar un ejecutable archivo como salida, escribiendo el código de máquina sin procesar utilizando un editor hexadecimal o similar.

Luego usaría ese compilador o ensamblador apenas funcional para implementar un compilador o ensamblador ligeramente más capaz que pueda reconocer un subconjunto más grande del idioma de destino. Espuma, enjuague, repita, hasta que tenga el producto final.

John Bode
fuente
2

No es tan difícil, como parece. En la infancia;) hice un desmontaje x86 en mente.

Incluso no necesitas aprenderlo especialmente. Simplemente sucede, cuando puede programar en ASM y luego tratar de arreglar un binario de terceros utilizando desensambladores interactivos. O al escribir su propia protección con cifrado de código.

Es decir, a veces estás migrando incluso del lenguaje a los códigos sin ninguna sorpresa.

Pavel Koryagin
fuente
1

Los primeros compiladores se implementaron usando lenguaje ensamblador. Y los primeros ensambladores se implementaron mediante programas de codificación en binario ...


No hace tanto tiempo que la programación en binario todavía era una habilidad que la gente usaba.

Cuando era estudiante universitario, recuerdo haber hecho un ejercicio de programación que implicaba escribir un pequeño programa en el código de máquina PDP-8 (creo), ingresarlo a través de los interruptores del panel frontal y ejecutarlo. Un par de años después, me compré un kit de desarrollo del sistema 6502 que tenía un teclado hexadecimal para ingresar programas ... y 4k bytes de RAM.

Stephen C
fuente
-3

UNA RESPUESTA MUY SIMPLE Supongamos que escribimos un programa cableado y lo almacenamos en la ROM. Se puede considerar como compilador. Entonces, simplemente quiero decir que el primer compilador fue cableado. A medida que la tecnología mejoró, estos compiladores simples se utilizaron para escribir compiladores de alto nivel.

DINOTOPO
fuente