De Wikipedia, la enciclopedia libre
Saltar a navegación Saltar a búsqueda

En informática , un compilador es un programa informático que traduce el código informático escrito en un lenguaje de programación (el idioma de origen ) a otro idioma (el idioma de destino ). El nombre "compilador" se usa principalmente para programas que traducen código fuente de un lenguaje de programación de alto nivel a un lenguaje de nivel inferior (por ejemplo, lenguaje ensamblador , código objeto o código de máquina ) para crear un programa ejecutable . [1] [2] : p1

Hay muchos tipos diferentes de compiladores que producen resultados en diferentes formas útiles. Un compilador que puede ejecutarse en una computadora cuya CPU o sistema operativo es diferente de aquel en el que se ejecutará el código que produce se denomina compilador cruzado . Un compilador de arranque está escrito en el lenguaje que pretende compilar. Un programa que se traduce de un lenguaje de bajo nivel a uno de nivel superior es un descompilador . Un programa que traduce entre lenguajes de alto nivel generalmente se denomina compilador o transcompilador de fuente a fuente . Un reescritor de idiomas suele ser un programa que traduce la forma de expresionessin un cambio de idioma. El término compilador-compilador se refiere a las herramientas utilizadas para crear analizadores que realizan análisis de sintaxis .

Un compilador es probable que realizar muchas o todas de las siguientes operaciones: preprocesamiento , análisis léxico , análisis sintáctico , análisis semántico ( traducción dirigida por la sintaxis ), conversión de programas de entrada a una representación intermedia , optimización de código y generación de código . Los compiladores implementan estas operaciones en fases que promueven un diseño eficiente y transformaciones correctas de la entrada de origen en la salida de destino. Las fallas del programa causadas por el comportamiento incorrecto del compilador pueden ser muy difíciles de rastrear y solucionar; por lo tanto, los implementadores del compilador invierten un esfuerzo significativo para asegurarcorrección del compilador . [3]

Los compiladores no son el único procesador de lenguaje utilizado para transformar programas fuente. Un intérprete es un software de computadora que transforma y luego ejecuta las operaciones indicadas. [2] : p2 El proceso de traducción influye en el diseño de los lenguajes informáticos, lo que conduce a una preferencia de compilación o interpretación. En la práctica, se puede implementar un intérprete para lenguajes compilados y se pueden implementar compiladores para lenguajes interpretados.

Historia [ editar ]

Un diagrama del funcionamiento de un compilador típico de múltiples idiomas y múltiples destinos

Los conceptos de computación teórica desarrollados por científicos, matemáticos e ingenieros formaron la base del desarrollo de la computación digital moderna durante la Segunda Guerra Mundial. Los lenguajes binarios primitivos evolucionaron porque los dispositivos digitales solo entienden unos y ceros y los patrones de circuito en la arquitectura de la máquina subyacente. A finales de la década de 1940, se crearon los lenguajes ensambladores para ofrecer una abstracción más funcional de las arquitecturas informáticas. Memoria limitadaLa capacidad de las primeras computadoras generó importantes desafíos técnicos cuando se diseñaron los primeros compiladores. Por lo tanto, el proceso de compilación debía dividirse en varios programas pequeños. Los programas de front-end producen los productos de análisis que utilizan los programas de back-end para generar el código de destino. A medida que la tecnología informática proporcionaba más recursos, los diseños de los compiladores podían adaptarse mejor al proceso de compilación.

Por lo general, es más productivo para un programador utilizar un lenguaje de alto nivel, por lo que el desarrollo de lenguajes de alto nivel se derivó naturalmente de las capacidades ofrecidas por las computadoras digitales. Los lenguajes de alto nivel son lenguajes formales que están estrictamente definidos por su sintaxis y semántica que forman la arquitectura del lenguaje de alto nivel. Los elementos de estos lenguajes formales incluyen:

  • Alfabeto , cualquier conjunto finito de símbolos;
  • Cadena , una secuencia finita de símbolos;
  • Idioma , cualquier conjunto de cadenas de un alfabeto.

Las oraciones en un idioma pueden definirse mediante un conjunto de reglas llamadas gramática. [4]

La forma Backus-Naur (BNF) describe la sintaxis de las "oraciones" de un idioma y fue utilizada para la sintaxis de Algol 60 por John Backus . [5] Las ideas derivan de los conceptos gramaticales libres de contexto de Noam Chomsky , un lingüista. [6] "BNF y sus extensiones se han convertido en herramientas estándar para describir la sintaxis de las notaciones de programación y, en muchos casos, partes de los compiladores se generan automáticamente a partir de una descripción BNF". [7]

En la década de 1940, Konrad Zuse diseñó un lenguaje de programación algorítmico llamado Plankalkül ("Plan Cálculo"). Si bien no se produjo una implementación real hasta la década de 1970, presentó conceptos que luego se vieron en APL diseñado por Ken Iverson a fines de la década de 1950. [8] APL es un lenguaje para cálculos matemáticos.

El diseño de lenguaje de alto nivel durante los años de formación de la informática digital proporcionó herramientas de programación útiles para una variedad de aplicaciones:

  • FORTRAN (traducción de fórmulas) para aplicaciones científicas y de ingeniería se considera el primer idioma de alto nivel. [9]
  • COBOL (Common Business-Oriented Language) evolucionó de A-0 y FLOW-MATIC para convertirse en el lenguaje de alto nivel dominante para aplicaciones comerciales. [10]
  • LISP (Procesador de listas) para cálculo simbólico. [11]

La tecnología del compilador evolucionó a partir de la necesidad de una transformación estrictamente definida del programa fuente de alto nivel en un programa objetivo de bajo nivel para la computadora digital. El compilador podría verse como un front-end para tratar el análisis del código fuente y un back-end para sintetizar el análisis en el código de destino. La optimización entre el front-end y el back-end podría producir un código de destino más eficiente. [12]

Algunos hitos iniciales en el desarrollo de la tecnología de compiladores:

  • 1952 : Un compilador de Autocode desarrollado por Alick Glennie para la computadora Manchester Mark I en la Universidad de Manchester es considerado por algunos como el primer lenguaje de programación compilado.
  • 1952 : El equipo de Grace Hopper en Remington Rand escribió el compilador para el lenguaje de programación A-0 (y acuñó el término compilador para describirlo), [13] [14] aunque el compilador A-0 funcionó más como cargador o enlazador. que la noción moderna de un compilador completo.
  • 1954-1957 : Un equipo dirigido por John Backus en IBM desarrolló FORTRAN, que generalmente se considera el primer lenguaje de alto nivel. En 1957, completaron un compilador FORTRAN al que generalmente se le atribuye haber introducido el primer compilador completo sin ambigüedades.
  • 1959 : La Conferencia sobre Lenguaje de Sistemas de Datos (CODASYL) inició el desarrollo de COBOL . El diseño de COBOL se basó en A-0 y FLOW-MATIC. A principios de la década de 1960, COBOL se compiló en varias arquitecturas.
  • 1958-1962 : John McCarthy del MIT diseñó LISP . [15] Las capacidades de procesamiento de símbolos proporcionaron características útiles para la investigación de inteligencia artificial. En 1962, el lanzamiento de LISP 1.5 señaló algunas herramientas: un intérprete escrito por Stephen Russell y Daniel J. Edwards, un compilador y ensamblador escrito por Tim Hart y Mike Levin. [dieciséis]

Los primeros sistemas operativos y software se escribieron en lenguaje ensamblador. En la década de 1960 y principios de la de 1970, el uso de lenguajes de alto nivel para la programación de sistemas todavía era controvertido debido a las limitaciones de recursos. Sin embargo, varios esfuerzos de investigación y la industria comenzó el cambio hacia sistemas de alto nivel lenguajes de programación, por ejemplo, BCPL , BLISS , B , y C .

BCPL (lenguaje de programación básico combinado) diseñado en 1966 por Martin Richards en la Universidad de Cambridge se desarrolló originalmente como una herramienta de escritura de compiladores. [17] Se han implementado varios compiladores, el libro de Richards proporciona información sobre el lenguaje y su compilador. [18] BCPL no solo fue un lenguaje de programación de sistemas influyente que todavía se utiliza en la investigación [19], sino que también proporcionó una base para el diseño de lenguajes B y C.

BLISS (Lenguaje básico para la implementación de software del sistema) fue desarrollado para una computadora PDP-10 de Digital Equipment Corporation (DEC) por el equipo de investigación de la Universidad Carnegie Mellon (CMU) de WA Wulf. El equipo de CMU pasó a desarrollar el compilador BLISS-11 un año después, en 1970.

Multics (Multiplexed Information and Computing Service), un proyecto de sistema operativo de tiempo compartido, involucró al MIT , Bell Labs , General Electric (más tarde Honeywell ) y fue dirigido por Fernando Corbató del MIT. [20] Multics fue escrito en el lenguaje PL / I desarrollado por IBM e IBM User Group. [21] El objetivo de IBM era satisfacer los requisitos empresariales, científicos y de programación de sistemas. Hubo otros lenguajes que podrían haberse considerado pero PL / I ofreció la solución más completa a pesar de que no se había implementado. [22]Durante los primeros años del proyecto Multics, Doug McIlory y Bob Morris de Bell Labs podrían compilar un subconjunto del lenguaje en lenguaje ensamblador con el compilador Early PL / I (EPL). [23] EPL apoyó el proyecto hasta que se pudo desarrollar un compilador de arranque para el PL / I completo. [24]

Bell Labs abandonó el proyecto Multics en 1969: "Con el tiempo, la esperanza fue reemplazada por la frustración, ya que el esfuerzo del grupo inicialmente no logró producir un sistema económicamente útil". [25] La participación continua aumentaría los costos de apoyo al proyecto. Entonces, los investigadores recurrieron a otros esfuerzos de desarrollo. Dennis Ritchie y Ken Thompson escribieron un lenguaje de programación de sistema B basado en conceptos BCPL . Ritchie creó un compilador de arranque para B y escribió el sistema operativo Unics (Uniplexed Information and Computing Service) para un PDP-7 en B. Unics finalmente se deletreó Unix.

Bell Labs inició el desarrollo y la expansión de C basado en B y BCPL. El compilador BCPL había sido transportado a Multics por Bell Labs y BCPL era un lenguaje preferido en Bell Labs. [26] Inicialmente, se utilizó un programa front-end para el compilador B de Bell Labs mientras se desarrollaba un compilador C. En 1971, un nuevo PDP-11 proporcionó el recurso para definir extensiones a B y reescribir el compilador. En 1973, el diseño del lenguaje C estaba esencialmente completo y el kernel Unix para un PDP-11 se reescribió en C. Steve Johnson comenzó el desarrollo de Portable C Compiler (PCC) para admitir la redirección de compiladores C a nuevas máquinas. [27] [28]

La programación orientada a objetos (OOP) ofrecía algunas posibilidades interesantes para el desarrollo y mantenimiento de aplicaciones. Los conceptos de POO se remontan más atrás, pero formaban parte de la ciencia del lenguaje LISP y Simula . [29] En Bell Labs, el desarrollo de C ++ se interesó en la programación orientada a objetos. [30] C ++ se utilizó por primera vez en 1980 para la programación de sistemas. El diseño inicial aprovechó las capacidades de programación de sistemas de lenguaje C con conceptos de Simula. Las instalaciones orientadas a objetos se agregaron en 1983. [31] El programa Cfront implementó un front-end de C ++ para el compilador de lenguaje C84. En los años siguientes, se desarrollaron varios compiladores de C ++ a medida que crecía la popularidad de C ++.

En muchos dominios de aplicaciones, la idea de utilizar un lenguaje de nivel superior se hizo popular rápidamente. Debido a la funcionalidad en expansión soportada por los lenguajes de programación más nuevos y la creciente complejidad de las arquitecturas de computadora, los compiladores se volvieron más complejos.

DARPA (Agencia de Proyectos de Investigación Avanzada de Defensa) patrocinó un proyecto de compilación con el equipo de investigación CMU de Wulf en 1970. El diseño de PQCC de Compilador de Calidad de Producción-Compilador produciría un Compilador de Calidad de Producción (PQC) a partir de definiciones formales del lenguaje fuente y el destino. [32] PQCC intentó extender el término compilador-compilador más allá del significado tradicional como generador de analizador sintáctico (por ejemplo, Yacc ) sin mucho éxito. PQCC podría denominarse más correctamente un generador de compiladores.

La investigación de PQCC sobre el proceso de generación de código buscó construir un sistema de escritura de compiladores verdaderamente automático. El esfuerzo descubrió y diseñó la estructura de fases del PQC. El compilador BLISS-11 proporcionó la estructura inicial. [33] Las fases incluyeron análisis (front-end), traducción intermedia a máquina virtual (middle-end) y traducción al destino (back-end). TCOL fue desarrollado para la investigación de PQCC para manejar construcciones específicas del lenguaje en la representación intermedia. [34] Las variaciones de TCOL admitían varios idiomas. El proyecto PQCC investigó técnicas de construcción de compiladores automatizados. Los conceptos de diseño resultaron útiles para optimizar compiladores y compiladores para el lenguaje de programación orientado a objetos Ada .

El Documento de Ada Stoneman formalizó el entorno de soporte del programa (APSE) junto con el kernel (KAPSE) y el mínimo (MAPSE). Un intérprete de Ada NYU / ED apoyó los esfuerzos de desarrollo y estandarización con el Instituto Nacional Estadounidense de Estándares (ANSI) y la Organización Internacional de Estándares (ISO). El desarrollo inicial del compilador Ada por parte de los Servicios Militares de EE. UU. Incluyó a los compiladores en un entorno de diseño integrado completo según las líneas del Documento Stoneman. El Ejército y la Marina trabajaron en el proyecto Ada Language System (ALS) dirigido a la arquitectura DEC / VAX, mientras que la Fuerza Aérea comenzó en el Ada Integrated Environment (AIE) dirigido a la serie IBM 370. Si bien los proyectos no proporcionaron los resultados deseados, contribuyeron al esfuerzo general en el desarrollo de Ada. [35]

Otros esfuerzos de compilación de Ada se pusieron en marcha en Gran Bretaña en la Universidad de York y en Alemania en la Universidad de Karlsruhe. En los EE. UU., Verdix (luego adquirido por Rational) entregó el Sistema de Desarrollo Verdix Ada (VADS) al Ejército. VADS proporcionó un conjunto de herramientas de desarrollo que incluyen un compilador. Unix / VADS se podría alojar en una variedad de plataformas Unix como DEC Ultrix y Sun 3/60 Solaris dirigido a Motorola 68020 en una evaluación de Army CECOM. [36] Pronto hubo muchos compiladores de Ada disponibles que pasaron las pruebas de validación de Ada. El proyecto GNU de la Free Software Foundation desarrolló la Colección de compiladores GNU (GCC), que proporciona una capacidad central para admitir varios idiomas y objetivos. La versión Ada GNATes uno de los compiladores de Ada más utilizados. GNAT es gratuito pero también hay soporte comercial, por ejemplo, AdaCore, fue fundada en 1994 para proporcionar soluciones de software comercial para Ada. GNAT Pro incluye GNAT basado en GNU GCC con un conjunto de herramientas para proporcionar un entorno de desarrollo integrado .

Los lenguajes de alto nivel continuaron impulsando la investigación y el desarrollo de compiladores. Las áreas de enfoque incluyeron optimización y generación automática de código. Las tendencias en los lenguajes de programación y los entornos de desarrollo influyeron en la tecnología de los compiladores. Se incluyeron más compiladores en las distribuciones de lenguajes (PERL, Java Development Kit) y como un componente de un IDE (VADS, Eclipse, Ada Pro). Creció la interrelación e interdependencia de las tecnologías. La llegada de los servicios web promovió el crecimiento de los lenguajes web y los lenguajes de programación. Los scripts se remontan a los primeros días de las interfaces de línea de comandos (CLI), donde el usuario podía ingresar comandos para ser ejecutados por el sistema. Conceptos de Shell de usuario desarrollados con lenguajes para escribir programas de shell. Los primeros diseños de Windows ofrecían una sencilla capacidad de programación por lotes. La transformación convencional de estos lenguajes utilizó un intérprete. Aunque no se utilizan ampliamente, se han escrito compiladores Bash y Batch. Más recientemente, los lenguajes interpretados sofisticados se convirtieron en parte del kit de herramientas de los desarrolladores. Los lenguajes de scripting modernos incluyen PHP, Python, Ruby y Lua. (Lua se usa ampliamente en el desarrollo de juegos). Todos estos tienen soporte para intérpretes y compiladores.[37]

"Cuando el campo de la compilación comenzó a finales de los 50, su enfoque se limitó a la traducción de programas de lenguaje de alto nivel a código de máquina ... El campo del compilador está cada vez más entrelazado con otras disciplinas, incluida la arquitectura informática, los lenguajes de programación, los métodos formales, ingeniería de software y seguridad informática ". [38] El artículo "Investigación del compilador: los próximos 50 años" señaló la importancia de los lenguajes orientados a objetos y Java. La seguridad y la computación paralela se mencionaron entre los futuros objetivos de investigación.

Construcción del compilador [ editar ]

Un compilador implementa una transformación formal de un programa fuente de alto nivel a un programa objetivo de bajo nivel. El diseño del compilador puede definir una solución de extremo a extremo o abordar un subconjunto definido que interactúe con otras herramientas de compilación, por ejemplo, preprocesadores, ensambladores, enlazadores. Los requisitos de diseño incluyen interfaces rigurosamente definidas tanto internamente entre los componentes del compilador como externamente entre los conjuntos de herramientas de soporte.

En los primeros días, el enfoque adoptado para el diseño del compilador se vio directamente afectado por la complejidad del lenguaje informático a procesar, la experiencia de las personas que lo diseñaron y los recursos disponibles. Las limitaciones de recursos llevaron a la necesidad de pasar por el código fuente más de una vez.

Un compilador para un lenguaje relativamente simple escrito por una persona podría ser una sola pieza de software monolítica. Sin embargo, a medida que el idioma de origen crece en complejidad, el diseño puede dividirse en varias fases interdependientes. Las fases separadas proporcionan mejoras de diseño que centran el desarrollo en las funciones del proceso de compilación.

Compiladores de una pasada frente a compiladores de varias pasadas[ editar ]

La clasificación de compiladores por número de pasadas tiene su origen en las limitaciones de recursos de hardware de las computadoras. La compilación implica realizar mucho trabajo y las primeras computadoras no tenían suficiente memoria para contener un programa que hiciera todo este trabajo. Así que los compiladores se dividieron en programas más pequeños, cada uno de los cuales pasó por encima de la fuente (o alguna representación de la misma) realizando algunos de los análisis y traducciones requeridos.

La capacidad de compilar en una sola pasada se ha considerado clásicamente como un beneficio porque simplifica el trabajo de escribir un compilador y los compiladores de una sola pasada generalmente realizan compilaciones más rápido que los compiladores de múltiples pasadas . Por lo tanto, impulsados ​​en parte por las limitaciones de recursos de los primeros sistemas, muchos de los primeros lenguajes se diseñaron específicamente para que pudieran compilarse en una sola pasada (por ejemplo, Pascal ).

En algunos casos, el diseño de una característica del lenguaje puede requerir que un compilador realice más de una pasada sobre la fuente. Por ejemplo, considere una declaración que aparece en la línea 20 de la fuente que afecta la traducción de una declaración que aparece en la línea 10. En este caso, el primer paso debe recopilar información sobre las declaraciones que aparecen después de las declaraciones que afectan, con la traducción real sucediendo durante una pasada posterior.

La desventaja de compilar en una sola pasada es que no es posible realizar muchas de las sofisticadas optimizaciones necesarias para generar código de alta calidad. Puede ser difícil contar exactamente cuántas pasadas realiza un compilador de optimización. Por ejemplo, las diferentes fases de optimización pueden analizar una expresión muchas veces pero solo analizar otra expresión una vez.

Dividir un compilador en pequeños programas es una técnica utilizada por los investigadores interesados ​​en producir compiladores demostrablemente correctos. Probar la corrección de un conjunto de programas pequeños a menudo requiere menos esfuerzo que demostrar la corrección de un programa único equivalente más grande.

Estructura del compilador de tres etapas [ editar ]

Diseño del compilador

Independientemente del número exacto de fases en el diseño del compilador, las fases se pueden asignar a una de las tres etapas. Las etapas incluyen un front-end, un intermedio y un back-end.

  • El front-end escanea la entrada y verifica la sintaxis y la semántica de acuerdo con un idioma fuente específico. Para los lenguajes de tipo estático , realiza la verificación de tipos mediante la recopilación de información de tipos. Si el programa de entrada es sintácticamente incorrecto o tiene un error de tipo, genera mensajes de error y / o advertencia, generalmente identificando la ubicación en el código fuente donde se detectó el problema; en algunos casos, el error real puede ser (mucho) anterior en el programa. Los aspectos de la interfaz incluyen análisis léxico, análisis de sintaxis y análisis semántico. La interfaz transforma el programa de entrada en una representación intermedia(IR) para su posterior procesamiento por el extremo intermedio. Este IR suele ser una representación de nivel inferior del programa con respecto al código fuente.
  • El extremo intermedio realiza optimizaciones en el IR que son independientes de la arquitectura de la CPU a la que se dirige. Esta independencia de código fuente / código de máquina está destinada a permitir que las optimizaciones genéricas se compartan entre versiones del compilador que admiten diferentes lenguajes y procesadores de destino. Ejemplos de optimizaciones intermedias son la eliminación de código inútil ( eliminación de código muerto ) o inalcanzable ( análisis de accesibilidad ), descubrimiento y propagación de valores constantes ( propagación constante ), reubicación de la computación en un lugar ejecutado con menos frecuencia (por ejemplo, fuera de un bucle) , o especialización de la computación basada en el contexto. Produciendo finalmente el IR "optimizado" que es utilizado por el back-end.
  • El extremo posterior toma el IR optimizado del extremo medio. Puede realizar más análisis, transformaciones y optimizaciones que son específicas para la arquitectura de la CPU de destino. El back-end genera el código de ensamblaje dependiente del objetivo, realizando la asignación de registros en el proceso. El back-end realiza la programación de instrucciones , que reordena las instrucciones para mantener ocupadas las unidades de ejecución paralela llenando los espacios de retardo . Aunque la mayoría de los problemas de optimización son NP-hard , heuristicLas técnicas para resolverlos están bien desarrolladas y actualmente se implementan en compiladores de calidad de producción. Normalmente, la salida de un back-end es un código de máquina especializado para un procesador y sistema operativo en particular.

Este enfoque de front / middle / back-end hace posible combinar front-end para diferentes idiomas con back-end para diferentes CPU mientras se comparten las optimizaciones del middle-end. [39] Ejemplos prácticos de este enfoque son GNU Compiler Collection , Clang ( compilador C / C ++ basado en LLVM ), [40] y Amsterdam Compiler Kit , que tienen múltiples front-end, optimizaciones compartidas y múltiples back-end.

Interfaz [ editar ]

Lexer y analizador ejemplo para C . A partir de la secuencia de caracteres " if(net>0.0)total+=net*(1.0+tax/100.0);", el escáner compone una secuencia de tokens y categoriza cada uno de ellos, por ejemplo, como identificador , palabra reservada , literal numérico u operador . El analizador transforma esta última secuencia en un árbol de sintaxis , que luego es tratado por las fases restantes del compilador. El analizador y el analizador manejan las partes regulares y correctamente libres de contexto de la gramática para C , respectivamente.

El front-end analiza el código fuente para construir una representación interna del programa, llamada representación intermedia (IR). También administra la tabla de símbolos , una estructura de datos que asigna cada símbolo en el código fuente a la información asociada, como la ubicación, el tipo y el alcance.

Si bien la interfaz puede ser una única función o programa monolítico, como en un analizador sin escáner , tradicionalmente se implementó y analizó en varias fases, que pueden ejecutarse de forma secuencial o simultánea. Este método se ve favorecido debido a su modularidad y separación de preocupaciones . Más comúnmente en la actualidad, la interfaz se divide en tres fases: análisis léxico (también conocido como lexing o escaneo), análisis de sintaxis (también conocido como escaneo o análisis sintáctico) y análisis semántico.. Lexing y parsing comprenden el análisis sintáctico (sintaxis de palabras y sintaxis de frases, respectivamente) y, en casos simples, estos módulos (el lexer y parser) se pueden generar automáticamente a partir de una gramática para el idioma, aunque en casos más complejos estos requieren modificación manual . La gramática léxica y la gramática de frases suelen ser gramáticas libres de contexto , lo que simplifica el análisis de manera significativa, con la sensibilidad al contexto manejada en la fase de análisis semántico. La fase de análisis semántico es generalmente más compleja y está escrita a mano, pero puede automatizarse total o parcialmente utilizando gramáticas de atributos . Estas fases en sí mismas se pueden desglosar aún más: lexing como escaneo y evaluación, y análisis como construcción de un árbol de sintaxis concreto.(CST, árbol de análisis) y luego transformarlo en un árbol de sintaxis abstracto (AST, árbol de sintaxis). En algunos casos se utilizan fases adicionales, en particular la reconstrucción de la línea y el preprocesamiento, pero son raras.

Las principales fases de la interfaz incluyen las siguientes:

  • La reconstrucción de línea convierte la secuencia de caracteres de entrada a una forma canónica lista para el analizador. Los lenguajes que restringen sus palabras clave o permiten espacios arbitrarios dentro de los identificadores requieren esta fase. Losanalizadores sintácticos de arriba hacia abajo , de descenso recursivo y controlados por tablas que se usaban en la década de 1960 generalmente leían la fuente un carácter a la vez y no requerían una fase de tokenización separada. Atlas Autocode e Imp (y algunas implementaciones de ALGOL y Coral 66 ) son ejemplos de lenguajes estropeados cuyos compiladores tendrían unafase de reconstrucción de línea .
  • El preprocesamiento admite lasustitución de macros y la compilación condicional . Normalmente, la fase de preprocesamiento ocurre antes del análisis sintáctico o semántico; por ejemplo, en el caso de C, el preprocesador manipula tokens léxicos en lugar de formas sintácticas. Sin embargo, algunos lenguajes como Scheme admiten sustituciones de macros basadas en formas sintácticas.
  • El análisis léxico (también conocido como lexing o tokenización ) divide el texto del código fuente en una secuencia de pequeñas piezas llamadas tokens léxicos . [41] Esta fase se puede dividir en dos etapas: la exploración , que segmenta el texto de entrada en unidades sintácticas llamadas lexemas y les asigna una categoría; y el evaluador , que convierte los lexemas en valor procesado. Un token es un par que consta de un nombre de token y un valor de token opcional. [42]Las categorías de tokens comunes pueden incluir identificadores, palabras clave, separadores, operadores, literales y comentarios, aunque el conjunto de categorías de tokens varía en diferentes lenguajes de programación . La sintaxis del lexema es típicamente un lenguaje regular , por lo que se puede usar un autómata de estado finito construido a partir de una expresión regular para reconocerlo. El software que realiza el análisis léxico se denomina analizador léxico . Es posible que este no sea un paso separado; se puede combinar con el paso de análisis sintáctico en el análisis sintáctico sin escáner , en cuyo caso el análisis sintáctico se realiza a nivel de carácter, no a nivel de token.
  • El análisis de sintaxis (también conocido como análisis sintáctico ) implica analizar la secuencia del token para identificar la estructura sintáctica del programa. Esta fase típicamente construye un árbol de análisis , que reemplaza la secuencia lineal de tokens con una estructura de árbol construida de acuerdo con las reglas de una gramática formal que define la sintaxis del lenguaje. El árbol de análisis a menudo se analiza, aumenta y transforma en fases posteriores del compilador. [43]
  • El análisis semántico agrega información semántica al árbol de análisis y crea la tabla de símbolos . Esta fase realiza comprobaciones semánticas como la comprobación de tipos (comprobación de errores de tipo) o la vinculación de objetos (asociando referencias de función y variable con sus definiciones) o asignación definitiva (requiriendo que todas las variables locales se inicialicen antes de su uso), rechazando programas incorrectos o emitiendo advertencias. El análisis semántico generalmente requiere un árbol de análisis completo, lo que significa que esta fase sigue lógicamente a lafase de análisis y, lógicamente, precede a la generación del código. fase, aunque a menudo es posible plegar múltiples fases en una sola pasada sobre el código en una implementación de compilador.

Extremo medio [ editar ]

El extremo medio, también conocido como optimizador, realiza optimizaciones en la representación intermedia para mejorar el rendimiento y la calidad del código de máquina producido. [44] El extremo intermedio contiene aquellas optimizaciones que son independientes de la arquitectura de la CPU a la que se dirige.

Las principales fases del extremo medio incluyen las siguientes:

  • Análisis : es la recopilación de información del programa a partir de la representación intermedia derivada de la entrada; El análisis de flujo de datos se utiliza para construir cadenas de definición de uso , junto con análisis de dependencia , análisis de alias , análisis de punteros , análisis de escape , etc. El análisis preciso es la base para la optimización de cualquier compilador. El gráfico de flujo de control de cada función compilada y el gráfico de llamadas del programa generalmente también se construyen durante la fase de análisis.
  • Optimización : la representación del lenguaje intermedio se transforma en formas funcionalmente equivalentes pero más rápidas (o más pequeñas). Las optimizaciones más populares son la expansión en línea , la eliminación de código muerto , la propagación constante , la transformación de bucle e incluso la paralelización automática .

El análisis del compilador es el requisito previo para cualquier optimización del compilador, y funcionan estrechamente juntos. Por ejemplo, el análisis de dependencia es crucial para la transformación de bucles .

El alcance del análisis y las optimizaciones del compilador varía mucho; su alcance puede variar desde operar dentro de un bloque básico hasta procedimientos completos o incluso el programa completo. Existe una compensación entre la granularidad de las optimizaciones y el costo de compilación. Por ejemplo, las optimizaciones de mirilla se realizan rápidamente durante la compilación, pero solo afectan a un pequeño fragmento local del código y se pueden realizar independientemente del contexto en el que aparece el fragmento de código. Por el contrario, la optimización interprocedimiento requiere más tiempo de compilación y espacio de memoria, pero permite optimizaciones que solo son posibles considerando el comportamiento de múltiples funciones simultáneamente.

El análisis y las optimizaciones entre procedimientos son comunes en los compiladores comerciales modernos de HP , IBM , SGI , Intel , Microsoft y Sun Microsystems . El software libre GCC fue criticado durante mucho tiempo por carecer de potentes optimizaciones entre procedimientos, pero está cambiando a este respecto. Otro compilador de código abierto con una completa infraestructura de análisis y optimización es Open64 , que muchas organizaciones utilizan con fines comerciales y de investigación.

Debido al tiempo y espacio extra necesarios para el análisis y las optimizaciones del compilador, algunos compiladores los omiten de forma predeterminada. Los usuarios tienen que usar las opciones de compilación para decirle explícitamente al compilador qué optimizaciones deben habilitarse.

Back-end [ editar ]

El back-end es responsable de las optimizaciones específicas de la arquitectura de la CPU y de la generación de código [44] .

Las principales fases del back-end incluyen las siguientes:

  • Optimizaciones dependientes de la máquina : optimizaciones que dependen de los detalles de la arquitectura de la CPU a la que apunta el compilador. [45] Un ejemplo destacado son las optimizaciones de mirilla , que reescribe secuencias cortas de instrucciones de ensamblador en instrucciones más eficientes.
  • Generación de código : el idioma intermedio transformado se traduce al idioma de salida, generalmente el idioma nativo de la máquina del sistema. Esto implica decisiones de recursos y almacenamiento, como decidir qué variables encajar en los registros y la memoria y la selección y programación de las instrucciones de la máquina adecuadas junto con sus modos de direccionamiento asociados(consulte también el algoritmo Sethi-Ullman ). Es posible que también sea necesario generar datos de depuración para facilitar la depuración .

Corrección del compilador [ editar ]

La corrección del compilador es la rama de la ingeniería de software que se ocupa de intentar mostrar que un compilador se comporta de acuerdo con la especificación de su lenguaje . [ cita requerida ] Las técnicas incluyen desarrollar el compilador usando métodos formales y usando pruebas rigurosas (a menudo llamadas validación del compilador) en un compilador existente.

Idiomas compilados versus interpretados [ editar ]

Los lenguajes de programación de nivel superior suelen aparecer con un tipo de traducción en mente: ya sea diseñado como lenguaje compilado o lenguaje interpretado . Sin embargo, en la práctica, rara vez hay algo en un lenguaje que requiera que sea compilado o interpretado exclusivamente, aunque es posible diseñar lenguajes que se basen en la reinterpretación en tiempo de ejecución. La categorización generalmente refleja las implementaciones más populares o extendidas de un lenguaje; por ejemplo, BASIC a veces se llama lenguaje interpretado y C compilado, a pesar de la existencia de compiladores BASIC e intérpretes C.

La interpretación no reemplaza la compilación por completo. Solo lo oculta al usuario y lo hace gradual. Aunque un intérprete puede ser interpretado por sí mismo, se necesita un programa ejecutado directamente en algún lugar al final de la pila (ver lenguaje de máquina ).

Además, los compiladores pueden contener intérpretes por motivos de optimización. Por ejemplo, cuando se puede ejecutar una expresión durante la compilación y los resultados se pueden insertar en el programa de salida, se evita que tenga que volver a calcularse cada vez que se ejecuta el programa, lo que puede acelerar enormemente el programa final. Las tendencias modernas hacia la compilación justo a tiempo y la interpretación de códigos de bytes a veces desdibujan aún más las categorizaciones tradicionales de compiladores e intérpretes.

Algunas especificaciones de lenguaje especifican que las implementaciones deben incluir una función de compilación; por ejemplo, Common Lisp . Sin embargo, no hay nada inherente en la definición de Common Lisp que impida su interpretación. Otros lenguajes tienen características que son muy fáciles de implementar en un intérprete, pero hacen que escribir un compilador sea mucho más difícil; por ejemplo, APL , SNOBOL4 y muchos lenguajes de scripting permiten a los programas construir código fuente arbitrario en tiempo de ejecución con operaciones de cadena regulares y luego ejecutar ese código pasándolo a una función de evaluación especial . Para implementar estas características en un lenguaje compilado, los programas generalmente deben enviarse con una biblioteca en tiempo de ejecución. que incluye una versión del propio compilador.

Tipos [ editar ]

Una clasificación de los compiladores es la plataforma en la que se ejecuta el código generado. Esto se conoce como plataforma de destino.

Un compilador nativo o alojado es aquel cuya salida está destinada a ejecutarse directamente en el mismo tipo de computadora y sistema operativo en el que se ejecuta el propio compilador. La salida de un compilador cruzado está diseñada para ejecutarse en una plataforma diferente. Los compiladores cruzados se utilizan a menudo al desarrollar software para sistemas integrados que no están destinados a admitir un entorno de desarrollo de software.

La salida de un compilador que produce código para una máquina virtual (VM) puede o no ejecutarse en la misma plataforma que el compilador que lo produjo. Por esta razón, estos compiladores no suelen clasificarse como compiladores nativos o cruzados.

El lenguaje de nivel inferior que es el objetivo de un compilador puede ser en sí mismo un lenguaje de programación de alto nivel . C, visto por algunos como una especie de lenguaje ensamblador portátil, es frecuentemente el lenguaje de destino de tales compiladores. Por ejemplo, Cfront , el compilador original de C ++ , usó C como idioma de destino. El código C generado por dicho compilador generalmente no está destinado a ser leído y mantenido por humanos, por lo que se ignoran el estilo de sangría y la creación de un código intermedio C bonito. Algunas de las características de C que lo convierten en un buen lenguaje de destino incluyen la #linedirectiva, que puede ser generada por el compilador para admitir la depuración de la fuente original, y el amplio soporte de plataforma disponible con los compiladores de C.

Si bien un tipo de compilador común genera código de máquina, hay muchos otros tipos:

  • Los compiladores de fuente a fuente son un tipo de compilador que toma un lenguaje de alto nivel como entrada y genera un lenguaje de alto nivel. Por ejemplo, un compilador de paralelización automática tomará frecuentemente un programa de lenguaje de alto nivel como entrada y luego transformará el código y lo anotará con anotaciones de código paralelo (por ejemplo, OpenMP ) o construcciones de lenguaje (por ejemplo, DOALLdeclaraciones de Fortran ).
  • Compiladores de bytecode que compilan en lenguaje ensamblador de una máquina teórica, como algunas implementaciones de Prolog
    • Esta máquina Prolog también se conoce como Warren Abstract Machine (o WAM).
    • Los compiladores de códigos de bytes para Java , Python también son ejemplos de esta categoría.
  • Los compiladores Just-In-Time (compilador JIT) posponen la compilación hasta el tiempo de ejecución. Existen compiladores JIT para muchos idiomas modernos, como Python , JavaScript , Smalltalk , Java , Microsoft .NET 's Common Intermediate Language (CIL) y otros. Un compilador JIT generalmente se ejecuta dentro de un intérprete. Cuando el intérprete detecta que una ruta de código está "activa", lo que significa que se ejecuta con frecuencia, se invocará el compilador JIT y compilará el código "activo" para aumentar el rendimiento.
    • Para algunos lenguajes, como Java, las aplicaciones se compilan primero utilizando un compilador de código de bytes y se entregan en una representación intermedia independiente de la máquina . Un intérprete de código de bytes ejecuta el código de bytes, pero el compilador JIT traducirá el código de bytes a código de máquina cuando sea necesario un mayor rendimiento. [46] [se necesita fuente no primaria ]
  • Los compiladores de hardware (también conocidos como herramientas de síntesis) son compiladores cuya salida es una descripción de la configuración del hardware en lugar de una secuencia de instrucciones.
    • La salida de estos compiladores tiene como objetivo el hardware de la computadora a un nivel muy bajo, por ejemplo, una matriz de puertas programables en campo (FPGA) o un circuito integrado estructurado específico de la aplicación (ASIC). [47] [Se necesita fuente no primaria ] Se dice que tales compiladores son compiladores de hardware, porque el código fuente que compilan controla efectivamente la configuración final del hardware y cómo opera. La salida de la compilación es solo una interconexión de transistores o tablas de búsqueda .
    • Un ejemplo de compilador de hardware es XST, la herramienta de síntesis de Xilinx utilizada para configurar FPGA. [48] [Se necesita fuente no primaria ] Hay herramientas similares disponibles de Altera, [49] [Se necesita fuente no primaria ] Synplicity, Synopsys y otros proveedores de hardware. [ cita requerida ]
  • Un ensamblador es un programa que compila lenguaje ensamblador legible por humanos en código de máquina , las instrucciones reales ejecutadas por hardware. El programa inverso que traduce el código máquina al lenguaje ensamblador se llama desensamblador .
  • Un programa que se traduce de un lenguaje de bajo nivel a uno de nivel superior es un descompilador . [ cita requerida ]
  • Un programa que traduce entre lenguajes de alto nivel generalmente se denomina traductor de lenguaje, compilador de fuente a fuente , conversor de lenguaje o reescritura de lenguaje . [ cita requerida ] El último término generalmente se aplica a traducciones que no implican un cambio de idioma. [50]
  • Un programa que se traduce a un formato de código objeto que no es compatible con la máquina de compilación se denomina compilador cruzado y se usa comúnmente para preparar código para aplicaciones integradas. [ cita requerida ] [ aclaración necesaria ]
  • Un programa que vuelve a escribir código objeto en el mismo tipo de código objeto mientras aplica optimizaciones y transformaciones es un recompilador binario .

Ver también [ editar ]

  • Interpretación abstracta
  • Análisis de abajo hacia arriba
  • Compilar y empezar a cargar
  • Compilar granja
  • Lista de compiladores
  • Lista de publicaciones importantes en informática § Compiladores
  • Metacompilacion

Referencias [ editar ]

  1. ^ Personal de PC Mag (28 de febrero de 2019). "Enciclopedia: Definición de compilador" . PCMag.com . Consultado el 28 de febrero de 2017 .
  2. ^ a b Compiladores: principios, técnicas y herramientas de Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman - Segunda edición, 2007
  3. ^ Sol, Chengnian; Le, Vu; Zhang, Qirun; Su, Zhendong (2016). "Hacia la comprensión de los errores del compilador en GCC y LLVM" . ACM .
  4. ^ apuntes de conferencias Compiladores: principios, técnicas y herramientas Departamento de Ciencias de la Computación e Ingeniería de la Información de Jing-Shin Chang Universidad Nacional de Chi-Nan
  5. ^ Naur, P. et al. "Informe sobre ALGOL 60". Communications of the ACM 3 (mayo de 1960), 299–314.
  6. ^ Chomsky, Noam; Lightfoot, David W. (2002). Estructuras sintácticas . Walter de Gruyter. ISBN 978-3-11-017279-9.
  7. ^ Gries, David (2012). "Apéndice 1: Formulario Backus-Naur" . La ciencia de la programación . Springer Science & Business Media. pag. 304. ISBN 978-1461259831.
  8. ^ Iverson, Kenneth E. (1962). Un lenguaje de programación . John Wiley e hijos. ISBN 978-0-471430-14-8.
  9. ^ Backus, John. "La historia de FORTRAN I, II y III" (PDF) . Historia de los lenguajes de programación . Softwarepreservation.org .
  10. ^ Porter Adams, Vicki (5 de octubre de 1981). "Capitán Grace M. Hopper: la Madre de COBOL". InfoWorld. 3 (20): 33. ISSN 0199-6649.
  11. ^ McCarthy, J .; Brayton, R .; Edwards, D .; Fox, P .; Hodes, L .; Luckham, D .; Maling, K .; Park, D .; Russell, S. (marzo de 1960). "Manual del programador LISP I" (PDF). Boston, Massachusetts: Grupo de Inteligencia Artificial, Centro de Computación y Laboratorio de Investigación del MIT.
  12. ^ Principios, técnicas y herramientas de los compiladores 2da edición por Aho, Lam, Sethi, Ullman ISBN 0-321-48681-1 
  13. ^ Hopper, Grace Murray (1952). "La educación de una computadora". Actas de la reunión nacional de la ACM de 1952 (Pittsburgh) : 243–249. doi : 10.1145 / 609784.609818 . S2CID 10081016 . 
  14. ^ Ridgway, Richard K. (1952). "Compilación de rutinas". Actas de la Reunión Nacional de la ACM de 1952 (Toronto) : 1–5. doi : 10.1145 / 800259.808980 . S2CID 14878552 . 
  15. ^ " Funciones recursivas de expresiones simbólicas y su cálculo por máquina ", Comunicaciones de la ACM, abril de 1960
  16. ^ McCarthy, John; Abrahams, Paul W .; Edwards, Daniel J .; Hart, Timothy P .; Levin, Michael I. (1965). Manual del programador Lisp 1.5 . La prensa del MIT. ISBN 9780262130110.
  17. ^ " BCPL: una herramienta para la escritura del compilador y la programación del sistema " M. Richards, Laboratorio de Matemáticas de la Universidad de Cambridge, Inglaterra 1969
  18. ^ BCPL: El lenguaje y su compilador, M Richards, Cambridge University Press (publicado por primera vez el 31 de diciembre de 1981)
  19. ^ La guía del usuario de BCPL Cintsys y Cintpos, M. Richards, 2017
  20. Corbató, FJ; Vyssotsky, VA "Introducción y descripción general del sistema MULTICS" . 1965 Conferencia conjunta sobre informática de otoño . Multicians.org.
  21. ^ Informe II del Comité de desarrollo del lenguaje avanzado SHARE, 25 de junio de 1964
  22. ^ Artículo de Multicians.org "La elección de PL / I", Editor / tom Van Vleck
  23. ^ "PL / I como herramienta para la programación del sistema", FJ Corbato, Datamation 6 de mayo de 1969
  24. ^ " El compilador Multics PL / 1 ", RA Freiburghouse, GE, Conferencia conjunta sobre informática de otoño de 1969
  25. ^ Columna de datamación , 1969
  26. ^ Dennis M. Ritchie, " El desarrollo del lenguaje C ", Segunda conferencia sobre la historia de los lenguajes de programación de ACM, abril de 1993
  27. ^ SC Johnson, "un compilador portátil de C: teoría y práctica", quinto simposio ACM POPL, enero de 1978
  28. ^ A. Snyder, un compilador portátil para el lenguaje C , MIT, 1974.
  29. ^ K. Nygarard, Universidad de Oslo, Noruega, " Conceptos básicos en programación orientada a objetos ", SIGPLAN Notices V21, 1986
  30. ^ B. Stroustrup: "¿Qué es la programación orientada a objetos?" Actas 14th ASU Conference, 1986.
  31. ^ Bjarne Stroustrup, "Una descripción general del lenguaje de programación C ++", Manual de tecnología de objetos (Editor: Saba Zamir, ISBN 0-8493-3135-8 ) 
  32. ^ Leverett, Cattell, Hobbs, Newcomer, Reiner, Schatz, Wulf: "Una descripción general del proyecto de compilador-compilador de calidad de producción", CMU-CS-89-105, 1979
  33. ^ W. Wulf, K. Nori, " Enlace retardado en compiladores generados por PQCC ", Informe de exhibición de investigación de CMU, CMU-CS-82-138, 1982
  34. ^ Joseph M. Newcomer, David Alex Lamb, Bruce W. Leverett, Michael Tighe, William A. Wulf - Carnegie-Mellon University y David Levine, Andrew H. Reinerit - Intermetrics: "TCOL Ada: Informe revisado sobre una representación intermedia para el Lenguaje de programación estándar del Departamento de Defensa ", 1979
  35. ^ William A. Whitaker, "Ada - el proyecto: el grupo de trabajo de orden superior del Departamento de Defensa", Avisos de ACM SIGPLAN (volumen 28, n. ° 3, marzo de 1991)
  36. ^ CECOM Center for Software Engineering Advanced Software Technology, "Informe final - Evaluación de la suite ACEC Benchmark para aplicaciones en tiempo real", AD-A231 968, 1990
  37. ^ P. Biggar, E. de Vries, D. Gregg, "Una solución práctica para compiladores de lenguaje de secuencias de comandos", presentación a Science of Computer Programming, 2009
  38. ^ M. Hall, D. Padua, K. Pingali, "Investigación del compilador: los próximos 50 años", ACM Communications 2009 Vol 54 # 2
  39. ^ Cooper y Torczon 2012, p. 8
  40. ^ Lattner, Chris (2017). "LLVM" . En Brown, Amy; Wilson, Greg (eds.). La arquitectura de las aplicaciones de código abierto . Archivado desde el original el 2 de diciembre de 2016 . Consultado el 28 de febrero de 2017 .
  41. ^ Aho, Lam, Sethi, Ullman 2007, p. 5-6, 109-189
  42. ^ Aho, Lam, Sethi, Ullman 2007, p. 111
  43. ^ Aho, Lam, Sethi, Ullman 2007, p. 8, 191-300
  44. ↑ a b Blindell, Gabriel Hjort (3 de junio de 2016). Selección de instrucciones: principios, métodos y aplicaciones . Suiza. ISBN 9783319340197. OCLC  951745657 .
  45. ^ Cooper y Toczon (2012), p. 540
  46. ^ Aycock, John (2003). "Una breve historia del Just-in-Time". Computación ACM. Surv . 35 (2 de junio): 93-113. doi : 10.1145 / 857076.857077 . S2CID 15345671 . [se necesita fuente no primaria ]
  47. ^ Swartz, Jordan S .; Betz, Vaugh; Rose, Jonathan (22 a 25 de febrero de 1998). "Un enrutador rápido impulsado por la capacidad de enrutamiento para FPGA" (PDF) . FPGA '98 Actas del Sexto Simposio Internacional ACM / SIGDA de 1998 sobre matrices de puertas programables en campo . Monterey, CA: ACM : 140-149. doi : 10.1145 / 275107.275134 . ISBN  978-0897919784. S2CID  7128364 . Archivado (PDF) desde el original el 9 de agosto de 2017.
  48. ^ Personal de Xilinx (2009). "Descripción general de la síntesis XST" . Xilinx, Inc. Archivado desde el original el 2 de noviembre de 2016 . Consultado el 28 de febrero de 2017 .[se necesita fuente no primaria ]
  49. ^ Personal de Altera (2017). "Motor Spectra-Q ™" . Altera.com. Archivado desde el original el 10 de octubre de 2016 . Consultado el 28 de febrero de 2017 .[se necesita fuente no primaria ]
  50. ^ "Tutorial de traductor de idiomas" (PDF) . Universidad de Washington .

Lectura adicional [ editar ]

  • Aho, Alfred V .; Sethi, Ravi ; Ullman, Jeffrey D. (1986). Compiladores: principios, técnicas y herramientas (1ª ed.). Addison-Wesley . ISBN 9780201100884.
  • Allen, Frances E. (septiembre de 1981). "Una historia de la tecnología de procesadores de lenguaje en IBM". IBM Journal of Research and Development . IBM . 25 (5): 535–548. doi : 10.1147 / rd.255.0535 .
  • Allen, Randy; Kennedy, Ken (2001). Optimización de compiladores para arquitecturas modernas . Editores Morgan Kaufmann . ISBN 978-1-55860-286-1.
  • Appel, Andrew Wilson (2002). Implementación del compilador moderno en Java (2ª ed.). Prensa de la Universidad de Cambridge . ISBN 978-0-521-82060-8.
  • Appel, Andrew Wilson (1998). Implementación del compilador moderno en ML . Prensa de la Universidad de Cambridge . ISBN 978-0-521-58274-2.
  • Bornat, Richard (1979). Comprensión y redacción de compiladores: una guía para hacerlo usted mismo (PDF) . Editorial Macmillan . ISBN 978-0-333-21732-0.
  • Calingaert, Peter (1979). Horowitz, Ellis (ed.). Ensambladores, compiladores y traducción de programas . Serie de ingeniería de programas informáticos (1ª edición, 1ª ed.). Potomac, Maryland: Computer Science Press, Inc. ISBN 0-914894-23-4. ISSN  0888-2088 . LCCN  78-21905 . Consultado el 20 de marzo de 2020 . (2 + xiv + 270 + 6 páginas)
  • Cooper, Keith Daniel; Torczon, Linda (2012). Ingeniería de un compilador (2ª ed.). Ámsterdam: Elsevier / Morgan Kaufmann. pag. 8. ISBN 9780120884780. OCLC  714113472 .
  • McKeeman, William Marshall ; Horning, James J .; Wortman, David B. (1970). Un generador de compiladores . Englewood Cliffs, Nueva Jersey : Prentice-Hall . ISBN 978-0-13-155077-3.
  • Muchnick, Steven (1997). Diseño e implementación de compiladores avanzados . Editores Morgan Kaufmann . ISBN 978-1-55860-320-2.
  • Scott, Michael Lee (2005). Pragmática del lenguaje de programación (2ª ed.). Morgan Kaufmann . ISBN 978-0-12-633951-2.
  • Srikant, YN; Shankar, Priti (2003). El manual de diseño del compilador: optimizaciones y generación de código de máquina . Prensa CRC . ISBN 978-0-8493-1240-3.
  • Terry, Patrick D. (1997). Compiladores y generadores de compiladores: Introducción a C ++ . Prensa informática internacional Thomson. ISBN 978-1-85032-298-6.
  • Wirth, Niklaus (1996). Construcción del compilador (PDF) . Addison-Wesley . ISBN 978-0-201-40353-4. Archivado desde el original (PDF) el 17 de febrero de 2017 . Consultado el 24 de abril de 2012 .
  • Comunidad LLVM. "El generador de código independiente de destino LLVM" . Documentación LLVM . Consultado el 17 de junio de 2016 .
  • Referencias de libros de texto del compilador Una colección de referencias a los libros de texto de construcción del compilador convencionales

Enlaces externos [ editar ]

  • Compiladores en Curlie
  • Enfoque incremental para la construcción del compilador  : tutorial en PDF
  • Compilar-Howto
  • Conceptos básicos del diseño del compilador en Wayback Machine (archivado el 15 de mayo de 2018)
  • Animación corta en YouTube que explica la diferencia conceptual clave entre compiladores e intérpretes.
  • Análisis de sintaxis y análisis de LL1 en YouTube
  • Construyamos un compilador , por Jack Crenshaw
  • Foro sobre el desarrollo de compiladores en Wayback Machine (archivado el 10 de octubre de 2014)