El documento describe las fases típicas de un compilador. Un compilador opera en fases que transforman progresivamente el programa fuente en representaciones intermedias hasta generar el programa objeto. Las principales fases son el análisis léxico, sintáctico y semántico, generación de código intermedio, optimización de código e intermedio y generación del código objeto.
1. 1.7 Fases de un compilador
Conceptualmente, un compilador opera en fases, cada una de las cuales
transforma al programa fuente de una presentación en otra. En la figura se
muestra una descomposición típica de un compilador. En la práctica, se pueden
agrupar algunas fases, y las representaciones intermedias entre las fases
agrupadas no necesitan ser construídas explícitamente.
Analizador semantico
Analizador léxico
Generador de código
intermedio
Analizador sintetico
Generador de código
Optimador de código
Manejador de erroresAdministrador de la
tabla de simbolos
Programa fuente
Programa objeto
2. Administración de la tabla de simbolos.
Una función especial de un compilador es registrar los identificadores utilizados en el
programa fuente y reunir informacion sobre los distintos atributos de cada indentificador.
Estos atributos pueden proporcionar información sobre la memoria asignada a un
identificador, su tipo, su ambito (la parte del programa donde tiene validez) y, en el caso
de nombres de procedimientos, cosas como el numero y tipos de sus argumento.
Detección e información de errores.
Cada fase puede encontrar errores. Sin embargo, despues de detectar un error, cada fase
debe de tratar de alguna forma ese error, para poder continuar la compilación,
permitiendo la detección de más errores en el programa fuente. Un compilador que se
detiene cuando encuentra el primer error, no resulta útil como debiera.
Generación de codigo intermedio.
Después de los análisis sintáctico y semántico , algunos compiladores generan una
representación intermedia explícita del programa fuente. Se puede considerar esta
representación intermedia como un programa para una máquina abstracta. Esta
represenatación intermedia debe de tener dos propiedades importantes; debe ser fácil de
producir y fácil de traducir al programa objeto.
Optimización de código.
La fase de optimización de código trata de mejorar el código intermedio, de modo que
resulte un código de máquina más rapido de ejecutar.
Hay mucha variación en la cantidad de optimización de código que ejecutan los distintos
compiladores. En los que hacen mucha optimización, llamados “compiladores
optimizadores”, una parte significativa del tiempo del compilador se ocupa en esta fase.
Sin embargo, hay optimizaciones sencillas que mejoran sensiblemente el tiempo de
ejecución del programa objeto sin retardar demasiado la compilación.
Generación de código.
La fase final de un compilador es la generación de código objeto, que por lo general
consiste en código de máquina relocalizable o código emsamblador. Las posiciones de
memoria se seleccionan para cada una de las variables usadas por el programa. Después
cada una de las instrucciones intermedias se traduce a una secuencia de instrucciones de
máquina que ejecuta la misma tarea. Un aspecto decisivo es la asignación de variables a
registros.
Sacar copias de la página de la 10 a la 15
3. 1.1 Alfabeto.
Un alfabeto es un conjunto de símbolos finito y no vacío. Convencionalmente,
utilizamos el símbolo ∑ para designar un alfabeto. Entre los alfabetos más
comunes se incluyen los siguientes:
∑ = {0,1}, el alfabeto binario.
∑ = {a,b, . . . , z}, el conjunto de todas las letras minúsculas.
El conjunto de todos los caracteres ASCII o el conjunto de todos los
caracteres ASCII imprimibles.
1.2 Cadenas.
Una cadena de caracteres (que también se denomina en ocasiones palabra) es
una secuencia finita de símbolos
seleccionados de algún alfabeto. Por ejemplo, 01101 es una cadena del alfabeto
binario ∑ = {0,1}. La cadena 111 es otra cadena de dicho alfabeto.
La cadena vacía
La cadena vacía es aquella cadena que presenta cero apariciones de símbolos.
Esta cadena, designada por ɛ , es una cadena que puede construirse en cualquier
alfabeto
Longitud de una cadena
Suele ser útil clasificar las cadenas por su longitud, es decir, el número de
posiciones ocupadas por símbolos
dentro de la cadena. Por ejemplo, 01101 tiene una longitud de 5. Es habitual decir
que la longitud de una cadena es igual al “número de símbolos” que contiene; esta
proposición está aceptada coloquialmente, sin embargo, no es estrictamente
correcta. Así, en la cadena 01101 sólo hay dos símbolos, 0 y 1, aunque tiene cinco
posiciones para los mismos y su longitus es igual a 5. Sin embargo, generalmente
podremos utilizar la expresión “número de símbolos” cuando realmente a lo que se
está haciendo referencia es al “número de posiciones”. La notación estándar para
indicar la longitud de una cadena w es |w|. Por ejemplo, |011| = 3 y |ε | = 0.
1.3 Lenguajes.
Un conjunto de cadenas, todas ellas seleccionadas de un Σ∗, donde Σ es un
determinado alfabeto se denomina lenguaje.La elección del término “lenguaje”
puede parecer extraña. Sin embargo, los lenguajes habituales pueden
interpretarse como conjuntos de cadenas.Un ejemplo sería el inglés, donde la
colección de las palabras correctas inglesas es un conjunto de cadenas del
alfabeto que consta de todas las letras. Otro ejemplo es el lenguaje C,o cualquier
otro lenguaje de programación, donde los programas correctos son un
4. subconjunto de las posibles cadenas que pueden formarse a partir del alfabeto del
lenguaje. Este alfabeto es un subconjunto de los caracteres ASCII.El alfabeto en
concreto puede diferir ligeramente entre diferentes lenguajes de programación,
aunque generalmente incluye las letrasmayúsculas y minúsculas, los dígitos, los
caracteres de puntuación y los símbolos matemáticos.
1.4 Tipos de lenguajes.
Expresiones regulares
Ahora vamos a desviar nuestra atención de las descripciones tipo máquina de los
lenguajes, autómatas finitos deterministas y no deterministas, a un tipo de
expresión algebraica: la “expresión regular”. Comprobaremos que las expresiones
regulares pueden definir de forma exacta los mismos lenguajes que describen los
distintos tipos de autómatas: los lenguajes regulares. Sin embargo, las
expresiones regulares ofrecen algo que los autómatas no proporcionan: una forma
declarativa para expresar las cadenas que deseamos aceptar.
Aunque las expresiones regulares describen los lenguajes de manera
completamente diferente a como lo hacen los autómatas finitos, ambas notaciones
representan exactamente el mismo conjunto de lenguajes, que hemos
denominado “lenguajes regulares”.
Para demostrar que las expresiones regulares definen la misma clase, tenemos
que probar que:
1. Todo lenguaje definidomediante uno de estos autómatas también se define
mediante una expresión regular.
Para demostrar esto, podemos suponer que el lenguaje es aceptado por algún
AFD.
2. Todo lenguaje definido por una expresión regular puede definirse mediante uno
de estos autómatas. Para esta parte de la demostración, lo más sencillo es probar
que existe un AFN con transiciones-ε que acepta el mismo lenguaje.
1.5 Herramientas computacionales ligadas con lenguajes
5. 1.6Estructura del traductor.
Un traductor divide su labor en dos etapas: una que analiza la entrada y genera
estructuras intermedias y otra que sintetiza la salida a partir de dichas estructuras.
Por tanto, el esquema de un traductor pasa de ser el de la figura 1.1, a ser el de la
figura 1.7. Básicamente los objetivos de la etapa de análisis son: a) controlar la
corrección del programa fuente, y b) generar las estructuras necesarias para
comenzar la etapa de síntesis.
Para llevar esto a cabo, la etapa de análisis consta de las siguientes fases: O
Análisis lexicográfico. Divide el programa fuente en los componentes básicos del
lenguaje a compilar. Cada componente básico es una subsecuencia decaracteres
del programa fuente, y pertenece a una categoría gramatical: números,
identificadores de usuario (variables, constantes, tipos, nombres de
procedimientos, ...), palabras reservadas, signos de puntuación, etc.