Fases del compilador con ejemplo: proceso y pasos de compilación

¿Cuáles son las fases del diseño del compilador?

Compilador Funciona en varias fases, cada una de las cuales transforma el programa fuente de una representación a otra. Cada fase toma las entradas de la etapa anterior y envía su salida a la siguiente fase del compilador.
Hay 6 fases en un compilador. Cada una de estas fases ayuda a convertir el lenguaje de alto nivel en código de máquina. Las fases de un compilador son:

  1. Análisis léxico
  2. Análisis de sintaxis
  3. Análisis semántico
  4. Generador de código intermedio
  5. Optimizador de código
  6. Generador de códigos
Fases del compilador
Fases del compilador

Todas estas fases convierten el código fuente dividiéndolo en tokens, creando árboles de análisis y optimizando el código fuente en diferentes fases.

Fase 1: Análisis Léxico

El análisis léxico es la primera fase en la que el compilador escanea el código fuente. Este proceso se puede realizar de izquierda a derecha, carácter por carácter, y agrupar estos personajes en tokens.
Aquí, el flujo de caracteres del programa fuente se agrupa en secuencias significativas identificando los tokens. Realiza el ingreso de los tickets correspondientes en la tabla de símbolos y pasa ese token a la siguiente fase.
Las funciones principales de esta fase son:

  • Identificar las unidades léxicas en un código fuente.
  • Clasifique unidades léxicas en clases como constantes, palabras reservadas e introdúzcalas en diferentes tablas. Ignorará los comentarios en el programa fuente.
  • Identificar token que no forma parte del idioma.

Ejemplo:
x = y + 10

Tokens

X identificador
= Operador de asignación
Y identificador
+ Operador de suma
10 Número

Fase 2: Análisis de sintaxis

El análisis de sintaxis consiste en descubrir la estructura del código. Determina si un texto sigue o no el formato esperado. El objetivo principal de esta fase es asegurarse de que el código fuente escrito por el programador sea correcto o no.
El análisis de sintaxis se basa en las reglas basadas en el lenguaje de programación específico mediante la construcción del árbol de análisis con la ayuda de tokens. También determina la estructura del idioma de origen y la gramática o sintaxis del idioma.
A continuación se muestra una lista de tareas realizadas en esta fase:

  • Obtener tokens del analizador léxico
  • Comprueba si la expresión es sintácticamente correcta o no.
  • Informar todos los errores de sintaxis
  • Construya una estructura jerárquica que se conoce como árbol de análisis.

Ejemplo

Cualquier identificador/número es una expresión.
Si x es un identificador e y+10 es una expresión, entonces x= y+10 es una declaración.
Considere el árbol de análisis para el siguiente ejemplo

(a+b)*c

Ejemplo de análisis de sintaxis

En árbol de análisis

  • Nodo interior: registro con un campo de operador y dos campos para hijos
  • Hoja: registros con 2 o más campos; uno para el token y otra información sobre el token
  • Asegurar que los componentes del programa encajen de manera significativa.
  • Reúne información de tipos y comprueba la compatibilidad de tipos.
  • Comprueba que los operandos estén permitidos por el idioma de origen

Fase 3: Análisis Semántico

El análisis semántico comprueba la coherencia semántica del código. Utiliza el árbol de sintaxis de la fase anterior junto con la tabla de símbolos para verificar que el código fuente dado sea semánticamente consistente. También comprueba si el código transmite un significado apropiado.
Semantic Analyzer comprobará si hay discrepancias de tipos, operandos incompatibles, una función llamada con argumentos inadecuados, una variable no declarada, etc.
Funciones de la fase de análisis semánticos son:

  • Le ayuda a almacenar la información de tipo recopilada y guardarla en una tabla de símbolos o un árbol de sintaxis.
  • Le permite realizar verificación de tipo
  • En el caso de una discrepancia de tipos, donde no existen reglas de corrección de tipos exactas que satisfagan la operación deseada, se muestra un error semántico.
  • Recopila información de tipos y comprueba la compatibilidad de tipos.
  • Comprueba si el idioma de origen permite los operandos o no

Ejemplo

float x = 20.2;
float y = x*30;

En el código anterior, el analizador semántico encasillará el número entero 30 para que flote 30.0 antes de la multiplicación.

Fase 4: Generación de código intermedio

Una vez finalizada la fase de análisis semántico, el compilador genera código intermedio para la máquina de destino. Representa un programa para alguna máquina abstracta.
El código intermedio se encuentra entre el lenguaje de alto nivel y el de máquina. Este código intermedio debe generarse de tal manera que facilite su traducción al código de máquina de destino.
Funciones de generación de Código Intermedio:

  • Debe generarse a partir de la representación semántica del programa fuente.
  • Mantiene los valores calculados durante el proceso de traducción.
  • Le ayuda a traducir el código intermedio al idioma de destino.
  • Le permite mantener el orden de prioridad del idioma de origen.
  • Contiene el número correcto de operandos de la instrucción.

Ejemplo

Por ejemplo,

total = count + rate * 5

El código intermedio con la ayuda del método del código de dirección es:

 
t1 := int_to_float(5) 
t2 := rate * t1 
t3 := count + t2
total := t3

Fase 5: Optimización del código

La siguiente fase es la optimización del código o código intermedio. Esta fase elimina líneas de código innecesarias y organiza la secuencia de declaraciones para acelerar la ejecución del programa sin desperdiciar recursos. El objetivo principal de esta fase es mejorar el código intermedio para generar un código que se ejecute más rápido y ocupe menos espacio.
Las funciones principales de esta fase son:

  • Le ayuda a establecer un equilibrio entre la velocidad de ejecución y de compilación.
  • Mejora el tiempo de ejecución del programa de destino.
  • Genera código simplificado aún en representación intermedia
  • Eliminar código inalcanzable y deshacerse de variables no utilizadas
  • Eliminar declaraciones que no se modifican del bucle

Ejemplo:
Considere el siguiente código

a = intofloat(10)
b = c * a
d = e + b
f = d

Puede llegar a ser

b =c * 10.0
f = e+b

Fase 6: Generación de código

La generación de código es la última y última fase de un compilador. Obtiene entradas de las fases de optimización del código y, como resultado, produce el código de página o el código objeto. El objetivo de esta fase es asignar almacenamiento y generar código de máquina reubicable.
También asigna ubicaciones de memoria para la variable. Las instrucciones del código intermedio se convierten en instrucciones de máquina. Esta fase convierte el código optimizado o intermedio al idioma de destino.
El idioma de destino es el código de máquina. Por lo tanto, todas las ubicaciones de memoria y registros también se seleccionan y asignan durante esta fase. El código generado por esta fase se ejecuta para tomar entradas y generar resultados esperados.

Ejemplo

a = b + 60.0
Posiblemente se traduciría a registros.

MOVF a, R1
MULF #60.0, R2
ADDF R1, R2

Gestión de tablas de símbolos

Una tabla de símbolos contiene un registro para cada identificador con campos para los atributos del identificador. Este componente facilita que el compilador busque el registro del identificador y lo recupere rápidamente. La tabla de símbolos también le ayuda en la gestión del alcance. La tabla de símbolos y el controlador de errores interactúan con todas las fases y la tabla de símbolos se actualiza en consecuencia.

Rutina de manejo de errores

En el proceso de diseño del compilador, pueden producirse errores en todas las fases que se detallan a continuación:

  • Analizador léxico: tokens mal escritos
  • Analizador de sintaxis: falta paréntesis
  • Generador de código intermedio: operandos no coincidentes para un operador
  • Optimizador de código: cuando no se puede acceder a la declaración
  • Código Generator: Cuando la memoria está llena o no se asignan los registros adecuados
  • Tablas de símbolos: Error de múltiples identificadores declarados

Los errores más comunes son secuencias de caracteres no válidas en el escaneo, secuencias de tokens no válidas en el tipo, error de alcance y análisis sintáctico en el análisis semántico.
El error puede encontrarse en cualquiera de las fases anteriores. Después de encontrar errores, la fase debe solucionarlos para continuar con el proceso de compilación. Estos errores deben informarse al controlador de errores que maneja el error para realizar el proceso de compilación. Generalmente, los errores se informan en forma de mensaje.

Resum

  • El compilador opera en varias fases, cada fase transforma el programa fuente de una representación a otra.
  • Seis fases de diseño del compilador son 1) Análisis léxico 2) Análisis sintáctico 3) Análisis semántico 4) Generador de código intermedio 5) Optimizador de código 6) Código Generator
  • El análisis léxico es la primera fase en la que el compilador escanea el código fuente.
  • El análisis de sintaxis consiste en descubrir la estructura del texto.
  • El análisis semántico comprueba la coherencia semántica del código.
  • Una vez finalizada la fase de análisis semántico del compilador, genere código intermedio para la máquina de destino.
  • La fase de optimización del código elimina líneas de código innecesarias y organiza la secuencia de declaraciones.
  • La fase de generación de código obtiene entradas de la fase de optimización del código y, como resultado, produce el código de página o el código objeto.
  • Una tabla de símbolos contiene un registro para cada identificador con campos para los atributos del identificador.
  • La rutina de manejo de errores maneja errores e informa durante muchas fases.