Fases de un compilador
División en las fases de análisis y síntesis
A veces la compilación se divide en 2 fases:
El análisis
En esta fase se estudia el programa fuente fraccionándolo en pedazos para establecer el significado del mismo y construyendo una representación inmediata.
La síntesis
En esta fase se hace la construcción del programa objeto a partir de la representación realizada en la fase de análisis.
Análisis del programa fuente
En esta fase, la cadena de caracteres que constituye el programa fuente se lee de izquierda a derecha y se agrupa en componentes léxicos, además el analizador léxico trabaja con la tabla de símbolos introduciendo en ésta los nombres de las variables
Sección de Análisis de un traductor
Análisis Léxico
La primera fase de un compilador, recibe como entrada el código fuente de otro programa (secuencia de caracteres) y produce una salida compuesta de tokens (componentes léxicos) o símbolos.
Ejemplo de Tokens
Aqui el programa fuente se lee
de izquierda a derecha y se agrupa en componentes léxicos, que son secuencias de caracteres que tienen un significado atómico.
Normalmente los espacios en blancos son eliminados.
Análisis Sintáctico
Trabaja con una gramática de contexto libre y genera el árbol sintáctico que reconoce su sentencia de entrada. En este caso las categorías gramaticales del
análisis léxico son los terminales de la gramática. Para el ejemplo que nos ocupa se parte de la gramática
S ÷ <ID> <ASIG> expr <TERM>
expr ÷ <ID>
| <ID> <+> expr
| <ID> <*> expr
| <NUM>
De manera que el análisis sintáctico intenta generar un árbol sintáctico que encaje con la sentencia de entrada.
Árbol sintáctico
El árbol puede representarse tal y como aparece en esta figura, o bien invertido.
Análisis Semántico
Esta fase revisa el árbol sintáctico junto con los atributos y la tabla de símbolos para tratar de encontrar errores semánticos. Para todo esto se analizan los operadores y operandos de expresiones y proposiciones. Finalmente reúne la información necesaria sobre los tipos de datos para la fase posterior de generación de código.
Topic principal
Sección de síntesis del traductor
Generador de código interrmedio
Transforma la salida del análisis semántico, en una representación cercana a un lenguaje intermedio cercano al código objeto.
Tiene dos propiedades importante
Debe ser fácil de producir
Debe ser fácil de traducir al lenguaje objeto
Existen varias formas de representar el código intermedio
Árboles sintácticos
Notación postfija
Código de tres direcciones
Consiste en una secuencia de instrucciones, cada una con máximo tres operandos y un operador binario.
Ejemplo
Optimizador de código intermedio
Intenta mejorar el código intermedio para que se ejecute más rápido y ocupe menos espacio
Además de la optimización a nivel de código intermedio, se puede reducir el tiempo de ejecución de un programa actuando a otros niveles: a nivel de código fuente y a nivel de código objeto.
Generador de código
La fase final donde se genera el código de máquina.
Se traducen las instrucciones intermedias a instrucciones de máquina.
Asignan variables a registros
Ejemplo
Manejo de tabla de símbolos
Una función esencial de un compilador es registrar los identificadores de usuario (nombres de variables, de funciones, de tipos, etc.) utilizados en el programa fuente y reunir información sobre los distintos atributos de cada identificador.
Estos atributos pueden proporcionar información sobre la memoria asignada a un identificador, la dirección de memoria en que se almacenará en tiempo de ejecución,
su tipo, su ámbito (la parte del programa donde es visible), etc.
Pues bien, la tabla de símbolos es una estructura de datos que posee información sobre los identificadores definidos por el usuario, ya sean constantes, variables, tipos u otros.
Interpretes vs compiladores
Compilador
Es un traductor que como entrada tiene una sentencia en lenguaje formal y la salida es un fichero ejecutable. En si traduce un código de alto nivel a código de máquina.
Intérprete
Es similar al compilador con la diferencia que la salida es una ejecución. El programa de entrada es reconocido y ejecutado a la vez. Tiene como principal ventaja que permite una fácil depuración.
Ejemplo
POSICION=INICIAL+VELOCIDADA*60
Ejemplo explicativo
Ilustración de fases de un compilador
Detección de errores y emisón de mensajes de error
Cada fase es capaz de detectar sus propios errores pero, luego de esto deben saber como manejarlo para continuar con la compilación y detectar más errores del programa fuente.
El analizador léxico detecta errores si los caracteres de entrada no conforman ningún token conocido.
El analizador sintáctico detecta errores si los tokens violan la sintaxis (reglas gramaticales).
El analizador semántico detecta errores si las sentencias estan bien sintacticamente pero no tienen significado.
Bibliografía
Gálvez, R. Mora, M. (2005).Taductores Y Compiladores con LEX / YACC, JFLEX/CUP Y JAVACC
Jiménez Millán, J. A. (2014). Compiladores y procesadores de lenguajes. Servicio de Publicaciones de la Universidad de Cádiz.
Martínez López, F. (2015). Teoría, diseño e implementación de compiladores de Lenguajes. RA-MA Editorial.