Diseño del compilador: fases del compilador
El proceso de compilación es una secuencia de varias fases. Cada fase toma la entrada de su etapa anterior, tiene su propia representación del programa fuente y alimenta su salida a la siguiente fase del compilador. Entendamos las fases de un compilador.
Análisis léxico
La primera fase del escáner funciona como un escáner de texto. Esta fase escanea el código fuente como un flujo de caracteres y lo convierte en lexemas significativos. El analizador léxico representa estos lexemas en forma de tokens como:
<token-name, attribute-value>
Análisis de sintaxis
La siguiente fase se llama análisis de sintaxis o parsing. Toma el token producido por el análisis léxico como entrada y genera un árbol de análisis sintáctico (o árbol de sintaxis). En esta fase, las disposiciones de los tokens se verifican con la gramática del código fuente, es decir, el analizador verifica si la expresión hecha por los tokens es sintácticamente correcta.
Análisis semántico
El análisis semántico comprueba si el árbol de análisis sintáctico construido sigue las reglas del lenguaje. Por ejemplo, la asignación de valores se realiza entre tipos de datos compatibles y la adición de una cadena a un número entero. Además, el analizador semántico realiza un seguimiento de los identificadores, sus tipos y expresiones; si los identificadores se declaran antes de su uso o no, etc. El analizador semántico produce un árbol de sintaxis anotado como salida.
Generación de código intermedio
Después del análisis semántico, el compilador genera un código intermedio del código fuente para la máquina de destino. Representa un programa para alguna máquina abstracta. Está entre el lenguaje de alto nivel y el lenguaje de máquina. Este código intermedio debe generarse de tal manera que sea más fácil de traducir al código de la máquina de destino.
Optimización de código
La siguiente fase hace la optimización del código del código intermedio. Se puede asumir que la optimización es algo que elimina líneas de código innecesarias y organiza la secuencia de declaraciones para acelerar la ejecución del programa sin desperdiciar recursos (CPU, memoria).
Codigo de GENERACION
En esta fase, el generador de código toma la representación optimizada del código intermedio y lo asigna al lenguaje de máquina de destino. El generador de código traduce el código intermedio en una secuencia de código de máquina (generalmente) reubicable. La secuencia de instrucciones del código de máquina realiza la tarea como lo haría el código intermedio.
Tabla de símbolos
Es una estructura de datos que se mantiene a lo largo de todas las fases de un compilador. Todos los nombres de los identificadores junto con sus tipos se almacenan aquí. La tabla de símbolos facilita al compilador buscar rápidamente el registro del identificador y recuperarlo. La tabla de símbolos también se utiliza para la gestión del alcance.