Posted in |
a la/s
7:27 p.m.
Fases de un Compilador
Por razones de diseño, la construcción del compilador se divide en varios pasos o fases. Se divide en dos procesos genéricos:
Análisis: El cual hace referencia a la escritura correcta del programa fuente, escrito por un programador.
Síntesis: Una vez se ha ejecutado el análisis de manera exitosa se procede a agrupará las componentes, que conforman el programa fuente, para construir frases con sentido con el fin de generar una salida. Que puede ser en lenguaje de máquina o algún otro lenguaje destino que se considere conveniente.
El proceso de análisis comprende varias fases que son:
Análisis léxico: Es la fase encargada de la lectura y exploración misma del programa fuente, Esto
quiere decir que el analizador léxico lee el programa fuente, y lo fracciona en componentes que tienen sentido para el lenguaje de programación que sé está considerando.
Análisis sintáctico: A esta fase le corresponde evaluar que el programa fuente escrito realmente
cumpla con las especificaciones del lenguaje definido para el compilador. Para ello normalmente
el programa fuente debe reflejar una estructura especial. Esta debe responder a una serie de reglas, que pueden ser recursivas o no, las cuales se denominan con el nombre de gramáticas. (Es una de las fases más importantes de la compilación.)
Análisis Semántico: Esta fase se dedica a determinar si todos los componentes del programa están siendo usados de manera válida, para el contexto en el cual aparecen. Es decir, se deben los componentes colindantes a cada componente siendo analizado, antes de determinar que las operaciones ejecutadas por el mismo estén dentro de las operaciones permitidas por el lenguaje, para dicho tipo de situaciones.
Mapa conceptual: Análisis sintáctico y análisis semántico
Una vez el programa fuente ha sido sometido a un análisis completo y se puede tener en cuenta de que esta correctamente escrito. Solo queda faltando generar algún tipo de salida para que el ciclo de compilación quede completo.
Las fases restantes hacen una síntesis del programa fuente para generar la salida. Estas fases son:
Generación de código Intermedio: La mayoría de los compiladores modernos intentan optimizar,
hasta donde sea posible, el código que generan. Para lograr esto los compiladores analizan internamente y tratan de generar secuencias de instrucciones internamente equivalentes a las del programa fuente, o reemplazan instrucciones para hacer un uso más eficiente en la memoria. Su objeto general es general un código intermedio del programa fuente para que sea usado posteriormente por el optimizador de código.
Optimización de código: El objeto de esta fase es el de mejorar el código fuente escrito para que
sea más rápido de ejecutar, o use de manera más eficiente los recursos de la máquina. Este proceso se apoya en la generación de código intermedio que fue realizada en la fase anterior. Por lo general es mucho más complicado optimizar el código basándose en el programa fuente tal como fue escrito por el programador.
Generación de código: El proceso de generación de código es el que constituye la salida, es decir,
genera el código de máquina que corresponde al programa fuente. Hay que recordar la diferencia con los intérpretes y su salida exclusiva de código.
Ejemplo de cómo se compila una línea genérica de un lenguaje:
Tomando una sencilla instrucción del lenguaje pascal se explicará cuál es la forma en que el compilador se comporta en cada fase y etapa respectiva. Sea la instrucción:
Suma:= ultimo + penúltimo
Inicialmente el analizador léxico leerá la línea carácter a carácter usando como referencia los
espacios en blanco, que indican donde comienza y donde termina cada componen. El analizador
léxico será invocado de manera sucesiva por el analizador sintáctico y a cada llamada, en su orden
devolviendo lo siguiente:
El identificador: Suma
El símbolo de asignación: =
El identificador: último
El operador de suma: +
El identificador: penúltimo
Luego comienza el análisis sintáctico para verificar que la línea escrita en el lenguaje esta correcta.
Para lo anterior representa en una estructura jerárquica denominada árbol gramatical así:
otro ejemplo: w=f*d/t
Posteriormente al análisis continúa la etapa de síntesis que se realiza en su orden de la siguiente
manera:
Generación de código intermedio: Consiste en construir un código con variables temporales donde
se use el recurso de memoria para representar cada instrucción de forma temporal. En el problema que llevamos como ejemplo el código intermedio seria:
Temp1=id2+id3
Id1=Temp1
Después el código intermedio es pasado por el optimizador de código y obtenemos lo siguiente:
Id1=Temp1
La etapa final en el proceso de síntesis del compilador es convertir el código optimizado a un código entendible por la máquina (lenguaje de maquina o ensamblador). En nuestro ejemplo queda de la siguiente forma:
Mov Id3, R1 Mueva el contenido de Id3 a R1
Add Id2, R1 Sume Id2 con lo que tiene en R1
Mov R1, Id1 lleve el contenido de la suma a Id1
Un segundo ejemplo sobre la forma en que se trabaja un compilador. Sea la instrucción del lenguaje C:
Posición = Inicial + Velocidad * 60
Etapa de análisis:
Analizador léxico:
El identificador: Posición
El símbolo de asignación:=
El identificador: Inicial
El operador de suma: +
El identificador: Velocidad
El operador de suma: *
El identificador constante: 60
Analizador Sintáctico: (Representación mediante un árbol sintáctico)
Etapa de Síntesis:
Generación de código intermedio
Temp1=enteroreal (60)
Temp2=Id3*temp1
Temp3=id2+temp2
Id1=temp3
Optimización de código:
Temp1=id3*60
Id1=1d2+temp1
Generación de código:
Mov Id3, r2
Mult #60, r2
Mov r2, r1
Add Id2, r1
Mov r1,Id1