La historia del desarrollo del compilador

Compilador

Un compilador es un programa que traduce lenguajes informáticos de alto nivel que son fáciles de escribir, leer y mantener para las personas a lenguajes de máquina de bajo nivel que las computadoras pueden reconocer y ejecutar. Un compilador toma un programa fuente como entrada y lo traduce a un programa equivalente en el idioma de destino. El programa fuente es generalmente un lenguaje de alto nivel, como Pascal y C++, mientras que el lenguaje de destino es el lenguaje ensamblador o el código de destino de la máquina de destino, a veces llamado código de máquina.

El flujo de trabajo principal de un compilador moderno es el siguiente:

Código fuente) → preprocesador) → compilador) → ensamblador) → código objeto) → enlazador) → documento ejecutable.

Directorio [ocultar]

Cómo funciona 1

2 tipos de compiladores

3 Preprocesador (preprocesador)

4 Frontend del compilador (frontend)

5 Backend del compilador (backend)

6 Comparación de lenguajes compilados y lenguajes interpretados

7 Historia

8 Ver también

Principio de operación

La traducción es del código fuente (generalmente un lenguaje de alto nivel) a un destino que puede ejecutarse directamente mediante una computadora o máquina virtual. Código (normalmente lenguaje de máquina o de bajo nivel). Pero también hay compiladores desde lenguajes de bajo nivel hasta lenguajes de alto nivel. Los compiladores que se utilizan para regenerar código de lenguaje de alto nivel a partir de código de lenguaje de bajo nivel generado por lenguajes de alto nivel también se denominan descompiladores. También hay compiladores que generan un lenguaje de alto nivel a partir de otro, o que generan código intermedio que requiere procesamiento posterior (también llamado cascada).

La salida típica del compilador es un archivo objeto que consta de código de máquina, que contiene el nombre y la dirección del punto de entrada y llamadas externas (llamadas a funciones que no están en este archivo objeto). No es necesario que el mismo compilador genere un conjunto de archivos objeto, pero los compiladores utilizados deben usar el mismo formato de salida y pueden vincularse entre sí para producir un programa ejecutable que el usuario pueda ejecutar directamente.

Tipo de compilador

Un compilador puede generar código objeto que se ejecuta en el mismo entorno que la computadora y el sistema operativo (plataforma) en el que se encuentra el compilador. Este compilador también se denomina compilador "nativo". Además, el compilador puede generar código objeto que se ejecuta en otras plataformas. Este tipo de compilador también se denomina compilador cruzado. Los compiladores cruzados son muy útiles para generar nuevas plataformas de hardware. Un "compilador de fuente a fuente" se refiere a un compilador que utiliza un lenguaje de alto nivel como entrada y la salida también es un lenguaje de alto nivel. Por ejemplo, los compiladores de paralelización automática normalmente toman un lenguaje de alto nivel como entrada, transforman el código que contiene y lo anotan con anotaciones de código paralelo (como OpenMP) o construcciones de lenguaje (como la directiva DOALL de FORTRAN).

Preprocesador (preprocesador)

Esta función es complementar el programa fuente reemplazando segmentos de programa predefinidos.

Frontal del compilador

El front-end es el principal responsable de analizar el programa fuente de entrada, y el analizador léxico y el analizador de sintaxis trabajan juntos. El analizador léxico es responsable de encontrar el '(Token ' en el programa fuente, y el analizador de sintaxis reúne estas palabras dispersas en expresiones, declaraciones, funciones, etc. significativas de acuerdo con la gramática predefinida. Por ejemplo, "a = b+ c; " El analizador léxico frontal ve "a, =, b, +, c"; de acuerdo con la gramática definida, el analizador primero los ensambla en la expresión "b+c" y luego los ensambla en la declaración "a = b +c" . El front-end también es responsable de las comprobaciones semánticas, como detectar si las variables involucradas en la operación son del mismo tipo y el manejo simple de errores. El resultado final suele ser un árbol de sintaxis abstracta (AST) para que el El backend puede optimizarlo y procesarlo aún más.

Backend del compilador

El backend del compilador es el principal responsable de analizar y optimizar el código de representación intermedio para generar código de máquina. >En términos generales, todo el análisis, optimización y modificaciones del compilador se pueden dividir en dos categorías: intraprocedimiento o interprocedimiento. Obviamente, el análisis y la optimización entre funciones son más precisos, pero tardan más en completarse

El objeto del análisis del compilador es generado por el código intermedio transferido. Los compiladores de optimización modernos generalmente usan varias capas de código intermedio para representar el programa. El IR de alto nivel está cerca del formato del programa fuente de entrada. que depende del lenguaje y contiene más información global y la estructura del programa fuente IR es independiente del lenguaje de entrada, y el IR de bajo nivel es similar al lenguaje de máquina. capa de código intermedia más apropiada.

El análisis de compilación común incluye árbol de llamadas de funciones, gráfico de flujo de control, definición-uso de variables, cadena de uso-definición (definir-usar/usar-definir o cadena u-d/d-u), análisis de alias de variables y análisis de punteros. y análisis de dependencia de datos.

Los resultados del análisis del programa anterior son un requisito previo para la optimización y transformación del compilador. Las optimizaciones e innovaciones comunes incluyen: inserción de funciones, eliminación de códigos muertos, estructuras de bucles estandarizadas, desenrollado de bucles, fusión de bucles, fusión de bucles, relleno de matrices, etc. El propósito de la transformación de optimización es reducir la longitud del código, mejorar la utilización de la memoria y la caché, y reducir la frecuencia de lectura y escritura de discos y el acceso a datos de la red. Optimizaciones más avanzadas pueden incluso convertir el código de serie en código paralelo de subprocesos múltiples.

La generación de código máquina es el proceso de convertir código intermedio optimizado en instrucciones de máquina. Los compiladores modernos adoptan principalmente la estrategia de generar código ensamblador en lugar de generar directamente código objeto binario. Incluso durante la fase de generación de código, los compiladores avanzados todavía tienen que realizar mucho análisis, optimización y transformación. Por ejemplo, cómo asignar registros, cómo elegir la selección de instrucciones de máquina adecuada, cómo combinar varios códigos en una oración, etc.

Comparación de lenguajes compilados y lenguajes interpretados

Mucha gente divide los lenguajes de programación de alto nivel en dos categorías: lenguajes compilados y lenguajes interpretados. Sin embargo, de hecho, la mayoría de estos lenguajes pueden ser implementados tanto por compiladores como por intérpretes, y la clasificación en realidad refleja el método de implementación general del lenguaje. (Sin embargo, algunos lenguajes interpretados son difíciles de implementar con compiladores. Por ejemplo, los lenguajes interpretados que permiten cambios de código en línea).

Historia

En la década de 1950, John de IBM Backus Lideró un equipo de investigación para desarrollar el lenguaje FORTRAN y su compilador. Sin embargo, debido a que la gente no sabía mucho sobre la teoría de la compilación en ese momento, el trabajo de desarrollo se volvió complicado y arduo. Al mismo tiempo, Noam Chomsky inició una investigación sobre la estructura del lenguaje natural. Su descubrimiento finalmente condujo a una estructura de compilador extremadamente simple, incluso con cierta automatización. Las investigaciones de Chomsky llevaron a la clasificación de las lenguas en función de su facilidad gramatical y los algoritmos necesarios para identificarlas. Como se llama ahora la jerarquía de Chomsky, consta de cuatro niveles de gramática: Tipo 0, Tipo 1, Tipo 2 y Tipo 3, cada uno de los cuales es un caso especial del primero. La gramática tipo 2 (o gramática libre de contexto) ha demostrado ser la más útil en los lenguajes de programación y hoy representa la forma estándar de estructurar los lenguajes de programación. El problema de análisis (un algoritmo eficiente de reconocimiento gramatical libre de contexto) se estudió en las décadas de 1960 y 1970 y resolvió este problema perfectamente. Ahora es una parte estándar de la filosofía de compilación.

Los autómatas finitos y las expresiones regulares están estrechamente relacionados con las gramáticas libres de contexto, y corresponden a las gramáticas Tipo 3 de Chomsky. La investigación sobre ellos comenzó casi simultáneamente con el trabajo de Chomsky, que introdujo la forma simbólica en que las palabras representan los lenguajes de programación.

Luego se perfeccionó el método de generación de código objeto efectivo, que era el compilador original, que todavía se utiliza hoy en día. La gente normalmente lo llama técnica de optimización, pero solo mejora su efectividad porque nunca obtiene el código objetivo optimizado, por lo que debería llamarse técnica de mejora de código.

Cuando el problema de análisis se vuelve fácil de entender, la gente dedica mucho tiempo a desarrollar programas y estudiar la construcción automática de esta parte del compilador. Originalmente, estos programas se llamaban compiladores - compiladores, pero más exactamente deberían llamarse generadores de analizadores, ya que solo pueden procesar automáticamente una parte de la compilación. El más famoso de estos programas es YACC (Another Compiler - Compiler), que fue escrito por Steve Johnson en 1975 para sistemas Unix. Asimismo, la investigación sobre autómatas de estados finitos desarrolló herramientas llamadas generadores de escáner, de los cuales Lex (desarrollado para sistemas Unix por Mike Lesk al mismo tiempo que Yacc) fue el mejor.

A finales de los años 1970 y principios de los 1980, una gran cantidad de proyectos se centraron en automatizar la generación de otras partes del compilador, incluida la generación de código. Estos intentos no tuvieron mucho éxito, probablemente porque las operaciones eran demasiado complejas y no se entendían bien.

Los desarrollos recientes en el diseño de compiladores incluyen: Primero, los compiladores incluyen aplicaciones con algoritmos más complejos para inferir o simplificar información en un programa; esto es paralelo al desarrollo de lenguajes de programación más complejos. Entre ellos, se encuentra un algoritmo unificado de verificación de tipos Hindley-Milner compilado mediante un lenguaje funcional típico.

En segundo lugar, los compiladores se están convirtiendo cada vez más en parte de un entorno de desarrollo interactivo (IDE) basado en ventanas, que incluye editores, enlazadores, depuradores y administradores de proyectos. No existen muchos estándares IDE de este tipo, pero el desarrollo de entornos de ventanas estándar se ha convertido en la dirección. Por otro lado, aunque se han realizado muchas investigaciones en el campo de los principios de compilación en los últimos años, los principios básicos de diseño del compilador no han cambiado mucho en los últimos 20 años y rápidamente se están convirtiendo en un vínculo central en los cursos de informática.

En la década de 1990, muchos compiladores y herramientas de desarrollo de compiladores gratuitos se desarrollaron como parte del Proyecto GNU u otros proyectos de código abierto. Estas herramientas se pueden utilizar para compilar todos los lenguajes de programación de computadoras. Algunos de ellos se consideran de alta calidad y su código fuente gratuito está disponible para aquellos interesados ​​en la teoría de compilación moderna.

Alrededor de 1999, SGI publicó el código fuente de un compilador industrial de optimización paralela, Pro64, que fue utilizado como plataforma de investigación por muchos grupos de investigación de compiladores en todo el mundo y se denominó Open64. Open64 tiene una buena estructura de diseño, análisis y optimización integrales y es una plataforma ideal para la investigación avanzada sobre compiladores.

Un compilador es un programa especial que convierte un programa escrito en un lenguaje de programación específico en código de máquina que una máquina puede ejecutar. Cuando escribimos un programa, el entorno que utilizamos es un editor de texto. En este momento, mi programa llama a este programa el programa fuente. Luego, el programador puede ejecutar el compilador correspondiente, que convierte el archivo fuente correspondiente en código de máquina (mediante un proceso complejo) especificando el nombre del archivo que se compilará.

Cómo funciona el compilador

Primero, el compilador realiza un análisis de sintaxis, es decir, separa esas cadenas. Luego realizar un análisis semántico, es decir, aclarar el significado de cada unidad gramatical analizada mediante análisis gramatical. Finalmente, se genera el archivo de destino, también llamado archivo obj. El código ejecutable final puede ser generado por el vinculador. A veces necesitamos vincular los archivos de destino generados por varios archivos para generar el código final. A este proceso lo llamamos reticulación.

>