El primer compilador fue escrito por Grace Hopper en 1952, mientras que el intérprete Lisp fue escrito en 1958 por el estudiante de John McCarthy Steve Russell. Escribir un compilador parece un problema mucho más difícil que un intérprete. Si es así, ¿por qué se escribió el primer compilador seis años antes que el primer intérprete?
history
compiler
interpreters
anguyen
fuente
fuente
Respuestas:
Eso podría ser cierto hoy, pero diría que no fue así hace unos 60 años. Algunas razones por las cuales:
fuente
El punto fundamental es que el entorno de hardware informático de la década de 1950 lo hizo de tal manera que solo un compilador era factible dado el procesamiento orientado a lotes de las computadoras en ese entonces.
En ese momento, las mejores interfaces de usuario se limitaban principalmente a tarjetas perforadas e impresoras de teletipo . En 1961, el sistema SAGE se convirtió en la primera pantalla de tubo de rayos catódicos (CRT) en una computadora. Por lo tanto, la naturaleza interactiva de un intérprete no era preferible o natural hasta mucho más tarde.
Numerosas computadoras en la década de 1950 usaban interruptores del panel frontal para cargar instrucciones, y la salida era simplemente filas de lámparas / LED, y los aficionados incluso usaban interruptores y LED del panel frontal en la década de 1970. Tal vez estés familiarizado con el infame Altair 8800 .
Otras limitaciones de hardware también hicieron que los intérpretes fueran inviables. Hubo una disponibilidad extremadamente limitada de memoria primaria (por ejemplo, RAM) en las computadoras en la década de 1950. Antes del circuito integrado de semiconductores (que no llegó hasta 1958) la memoria se limitaba a la memoria de núcleo magnético o la memoria de línea de retardo que se medía en bits o palabras , sin prefijo. Combinado con la lentitud de la memoria de almacenamiento secundaria (p. Ej., Disco o cinta), se consideraría un desperdicio, si no inviable, tener mucha de la memoria utilizada para el intérprete, incluso antes de que se cargara el programa que se está interpretando.
Las limitaciones de memoria seguían siendo un factor importante cuando el equipo liderado por John Backus en IBM creó el compilador FORTRAN en 1954-57. Este innovador compilador tuvo éxito solo porque era un compilador optimizador .
La mayoría de las computadoras en la década de 1950 apenas tenían un sistema operativo, y mucho menos características modernas como el enlace dinámico y la administración de memoria virtual, por lo que la idea de un intérprete era demasiado radical y poco práctica en ese momento.
Apéndice
Los idiomas de la década de 1950 eran primitivos. Incluían solo un pequeño puñado de operaciones, a menudo influenciadas por las instrucciones del hardware subyacente o la definición del problema de su uso específico.
En ese momento, las computadoras rara vez eran computadoras de propósito general en el sentido en que pensamos en las computadoras de hoy. El hecho de que fueran reprogramables sin tener que reconstruirlo se consideraba un concepto revolucionario: anteriormente las personas habían estado utilizando máquinas electromecánicas (típicamente calculadoras) para calcular o calcular respuestas (la mayoría de las aplicaciones en la década de 1950 eran de naturaleza numérica).
Desde el punto de vista de la informática, los compiladores e intérpretes son traductores y tienen una complejidad aproximadamente igual de implementada.
fuente
Los primeros lenguajes de programación fueron bastante simples (sin recurrencia, por ejemplo) y cercanos a la arquitectura de la máquina, que en sí era simple. La traducción fue entonces un proceso sencillo .
Un compilador era más simple como programa que un intérprete que tendría que mantener juntos tanto los datos para la ejecución del programa como las tablas para interpretar el código fuente. Y el intérprete ocuparía más espacio , por sí mismo, para el código fuente del programa y para las tablas simbólicas.
La memoria podría ser tan escasa (tanto por razones de costo como arquitectónicas) que los compiladores podrían ser programas independientes que sobrescribieron el sistema operativo (utilicé uno de estos). El sistema operativo tuvo que volver a cargarse después de compilar para ejecutar el programa compilado. ... lo que deja en claro que ejecutar un intérprete para trabajo real simplemente no era una opción .
Para ser verdad, la simplicidad requerida de los compiladores era tal que los compiladores no eran muy buenos (la optimización del código todavía estaba en la infancia, cuando se consideraba). El código de máquina escrito a mano tenía, al menos hasta finales de los años sesenta en algunos lugares, la reputación de ser significativamente más eficiente que el código generado por el compilador. Incluso había un concepto de relación de expansión de código , que comparaba el tamaño del código compilado con el trabajo de un muy buen programador. Por lo general, era mayor que 1 para la mayoría de los compiladores (¿todos?), Lo que significaba programas más lentos y, mucho más importante, programas más grandes que requerían más memoria. Esto seguía siendo un problema en los años sesenta.
El interés del compilador era la facilidad de programación, especialmente para los usuarios que no eran especialistas en computación, como los científicos en varios campos. Este interés no era el rendimiento del código. Pero aún así, el tiempo del programador se consideraba un recurso barato. El costo fue en tiempo de computadora, hasta 1975-1980, cuando el costo cambió de hardware a software. Lo que significa que incluso el compilador no fue tomado en serio por algunos profesionales .
El costo muy alto del tiempo de computadora fue otra razón para descalificar a los intérpretes , hasta el punto de que la idea misma habría sido ridícula para la mayoría de las personas.
El caso de Lisp es muy especial, porque era un lenguaje extremadamente simple que lo hacía factible (y la computadora se había vuelto un poco más grande en 58). Más importante aún, el intérprete de Lisp fue una prueba de concepto con respecto a la autodefinición de Lisp ( meta-circularidad ), independientemente de cualquier problema de usabilidad.
El éxito de Lisp se debe en gran parte al hecho de que esta autodefinición lo convirtió en un excelente banco de pruebas para estudiar estructuras de programación y diseñar nuevos lenguajes (y también por su conveniencia para la computación simbólica).
fuente
No estoy de acuerdo con la premisa de la pregunta.
El primer compilador del Adm. Hopper (el A-0) se parecía más a un enlazador o un lenguaje macro. Ella almacenaba subrutinas en una cinta (a cada una se le asignaba un número) y sus programas se escribirían como una lista de subrutinas y argumentos. El compilador copiará las subrutinas solicitadas de la cinta y las volverá a ordenar en un programa completo.
Ella usó la palabra "compilar" en el mismo sentido que compila una antología de poemas: reunir varios artículos en un solo volumen.
Ese primer compilador no tenía un lexer o analizador, por lo que puedo decir, lo que lo convierte en un ancestro lejano de un compilador moderno. Más tarde creó otro compilador (el B-0, también conocido como FLOW-MATIC) con el objetivo de una sintaxis más parecida al inglés, pero no se completó hasta 1958 o 1959, casi al mismo tiempo que el intérprete Lisp.
Por lo tanto, creo que la pregunta en sí está un poco equivocada. Parece que los compiladores e intérpretes co-evolucionaron casi exactamente al mismo tiempo, sin duda debido al intercambio de ideas que habrían tenido muchos científicos pensando en la misma línea en esos días.
Una mejor respuesta con citas aquí: https://stackoverflow.com/a/7719098/122763 .
fuente
La otra parte de la ecuación es que los compiladores eran una abstracción escalonada por encima de un ensamblador. Primero teníamos un código de máquina codificado. "Nosotros" éramos el ensamblador. Cada salto y desplazamiento, etc. se calcularon a mano en hexadecimal (u octal) y luego se perforaron en cinta de papel o tarjetas. Entonces, cuando los ensambladores llegaron a la escena, fue un gran ahorro de tiempo. El siguiente paso fueron los macro ensambladores. Eso le dio la capacidad de escribir una macro que se expandiría en un conjunto de instrucciones de máquina. Así que Fortran y Cobol fueron un gran paso adelante. La falta de recursos (almacenamiento, memoria y ciclos de CPU) significaba que los intérpretes de uso general tenían que esperar a que la tecnología creciera. La mayoría de los primeros intérpretes eran motores de código de bytes (como Java o CLR de hoy, pero con mucha menos capacidad). UCSD Pascal era un lenguaje muy popular (y rápido). MS Basic era un motor de código de bytes bajo el capó.
En términos de sobrecarga de instrucciones, dependía totalmente de qué procesador se estaba ejecutando. La industria pasó por una gran crisis RISC vs CISC por un tiempo. Personalmente escribí ensamblador para IBM, Data General, Motorola, Intel (cuando aparecieron), TI y muchos otros. Hubo una diferencia bastante significativa en los conjuntos de instrucciones, registros, etc. que influirían en lo que se requería para "interpretar" un código p.
Como referencia de tiempo, comencé a programar en la compañía telefónica alrededor de 1972.
fuente
Si no tiene todo en la memoria, el código compilado es mucho más rápido. No olvide que en estos tiempos las funciones se unieron al código compilado. Si no está compilando, no sabe qué funciones necesitará. Entonces, estás llamando a funciones desde ... ¡Oh, no desde el disco todavía, estamos en los primeros 50 lazos, sino desde las tarjetas! En tiempo de ejecución!
Por supuesto, es posible encontrar soluciones alternativas, pero aún no se encontraron, ya que los idiomas eran muy simples y no estaban tan lejos del código de máquina. Y compilar fue fácil y suficiente.
fuente
Antes de que se escribiera el primer compilador, la gente escribía código de ensamblador que era un gran progreso en comparación con el código binario simple. En ese momento, había un fuerte argumento de que el código compilado por un compilador sería menos eficiente que el código ensamblador; en ese momento, la relación de (costo de la computadora) con (costo del programador) era muy, muy diferente a la actual. Entonces hubo una fuerte resistencia contra los compiladores desde ese punto de vista.
Pero los compiladores son muchísimo más eficientes que los intérpretes. Si hubieras sugerido escribir un intérprete en ese momento, la gente hubiera pensado que estás loco. ¿Te imaginas comprar una computadora de un millón de dólares y luego desperdiciar el 90% de su poder para interpretar el código?
fuente
Antes de que un programa de bucle pueda ser interpretado, debe almacenarse en un medio que pueda leerse repetidamente. En la mayoría de los casos, el único medio adecuado sería RAM. Dado que el código generalmente se ingresará en tarjetas perforadas que, para los idiomas legibles por humanos, es probable que estén en gran parte vacías, se debe realizar algún tipo de procesamiento sobre el código antes de que se almacene en la RAM. En muchos casos, procesar el texto de la tarjeta perforada en un formulario que sea adecuado para la ejecución directa por parte del procesador no es realmente más difícil que procesarlo en un formulario que pueda manejarse eficientemente a través de un intérprete.
Tenga en cuenta que el objetivo de los primeros compiladores no era producir un archivo de lenguaje de ensamblaje o código de objeto en el disco, sino más bien terminar el código en la RAM que estaba listo para ejecutarse. En realidad, esto es sorprendentemente fácil cuando no hay un sistema operativo que se interponga en el camino. Un compilador puede generar código a partir de un extremo de la memoria y asignar variables y objetivos de ramificación a partir del otro. Si una declaración está marcada con la etiqueta "1234", el compilador almacenará en la variable llamada "1234" una instrucción para saltar a la dirección de generación de código actual, creando esa variable si no existe. Una declaración "goto 1234" creará una variable "1234" si no existe, y luego saltará a esa variable [que con suerte tendrá un salto a la ubicación correcta almacenada antes de que se ejecute esa declaración].
goto
una etiqueta que aún no se ha definido, ya que sabe cuándogoto
compila hacia dónde va a saltar: a una variable. Puede que esa no sea la forma más eficiente de generar código, pero es adecuada para el tamaño de los programas que se esperaba que manejaran las computadoras.fuente
Porque los intérpretes necesitan compiladores para funcionar.
La declaración anterior no es realmente cierta. Hablando estrictamente, puede hacer un intérprete sin usar o interactuar con un compilador. Pero los resultados de hacer esto no se parecerían mucho a lo que creo que quieres decir con esos términos.
En sentido estricto, los compiladores e intérpretes hacen cosas completamente diferentes. Un compilador lee el texto de alguna fuente y lo transforma en otro formato: lenguaje ensamblador, código de máquina, otro lenguaje de alto nivel, una estructura de datos o cualquier otra cosa. Mientras tanto, un intérprete toma una estructura de datos de algún tipo y realiza instrucciones basadas en ella.
Lo que tendemos a pensar como un "compilador" hoy en día es en realidad un compilador que se ha emparejado con un generador de código : un programa que toma datos de alguna fuente y emite código en algún formato según lo que ve. Es un uso bastante intuitivo para los compiladores, y fue una de las primeras cosas para las que se crearon los compiladores. Pero si lo miras de otra manera, esto parece muy similar a lo que hace un intérprete. Siempre genera código en lugar de realizar operaciones más generales, pero el principio es el mismo.
Si lo miramos desde el otro lado, un intérprete necesita obtener sus datos de alguna parte . Estos son solo datos, por lo que puede construirlos de la misma manera que construiría cualquier otro tipo de datos. Como estamos hablando de interpretación, parece natural que pueda construir sus datos según las instrucciones en un archivo de texto. Pero para hacer eso, necesitaría algo para leer en el texto y crear su estructura de datos, y eso es un compilador . Está conectado al intérprete en lugar de a un generador de código, pero de todos modos es un compilador.
Es por eso que los compiladores se escribieron primero. La idea de interpretar las estructuras de datos no era nueva incluso cuando se concibieron los compiladores, pero los compiladores eran el "eslabón perdido" que permitía a los programadores construir esas estructuras a partir del texto.
fuente
Otro factor: cuando se escribieron los primeros compiladores, el costo del tiempo de máquina era mucho más alto de lo que es ahora. Los intérpretes usan mucho más tiempo de máquina.
fuente