Está en la página 1de 47

Analizadores

léxicos y sintácticos
Tema 1:
Introducción a los compiladores

Fernando D. Lorenzo García


Compiladores
 La escritura de compiladores comprende:
 Lenguajes de programación
 La arquitectura de computadores
 La teoría de lenguajes
 Los algoritmos
 La ingeniería del software

Fernando D. Lorenzo García


Compiladores
 Se define compilador como un programa que
traduce un programa fuente a un programa
objeto equivalente.
 El compilador informa a su usuario de errores
en el programa fuente
Programa Programa
Compilador
fuente objeto

Mensaje
de error
Fernando D. Lorenzo García
Compiladores
 La función del compilador radica en que se
mantenga la semántica del programa fuente
en el programa objeto
 En un compilador nos interesan dos aspectos
 La velocidad de compilación
 La eficiencia del código objeto
 Llegar a una solución de compromiso entre
ambos

Fernando D. Lorenzo García


Necesidad de un compilador
 Eliminar conocer los detalles de la máquina
 Diseñar programa por bloques
 Despreocuparse de la ocupación de los
datos
 Portabilidad

Fernando D. Lorenzo García


Proceso de
compilación-ejecución
Estructura del programa fuente
•Inserción de ficheros
•Macroinstrucciones
Preprocesador
•Racionalizaciones
Programa fuente •Extensión de lenguajes

Compilador

Programa objeto

Ensamblador

Código máquina relocalizable


Biblioteca,
Editor de carga y enlace Archivos objeto relocalizable

Código de máquina absoluto o ejecutable


Fernando D. Lorenzo García
Definiciones
 Intérprete: Es un programa en el que sus
datos de entrada son de un programa fuente,
pero la semántica que lleva las acciones del
programa fuente, el intérprete las realiza (no
es una traducción)
 Ensamblador: Es un traductor de lenguaje
ensamblador a lenguaje máquina
 Compilador cruzado: Es un compilador que
se ejecuta en una máquina pero que genera
código para otra
Fernando D. Lorenzo García
Definiciones
 Autocompilador: Es un compilador que se
compila a sí mismo (compila su propio
fuente)
 Decompilador: Es un programa que hace el
proceso inverso a la compilación, también
denominado “recreador”

Fernando D. Lorenzo García


Fases de un compilador
 Al diseñar un compilador se suele hacer de
forma que todo el trabajo se subdivida en
fases.
Programa fuente

Análisis
Código intermedio (instrucciones)
Síntesis Tabla de símbolos (datos)

Programa objeto

Fernando D. Lorenzo García


Fases de un compilador
 El análisis está relacionado con el lenguaje
fuente y consiste en ir leyendo las
instrucciones que lo componen e ir
almacenando el significado de las mismas.
 En esta fase se obtiene un código intermedio
(información de instrucciones) y una tabla de
símbolos (información de datos)
 En la síntesis se construyen las instrucciones
del programa objeto a partir de la información
obtenida
Fernando D. Lorenzo García
Fases de un compilador
 La fase de síntesis tiene el inconveniente de
tener que ser eficiente por lo que se complica
su construcción
 Por ello esta fase incluye una optimización
que es una mejora del código intermedio
 Refinando, nos queda:

Fernando D. Lorenzo García


Fases de un compilador
Programa fuente

Código intermedio 1
Análisis Tabla de símbolos 1
Optimización del
código intermedio
Síntesis del Código intermedio 2
Código objeto Tabla de símbolos 2

Programa objeto

 Al análisis se le suele llamar FRONT-END del


compilador y a la síntesis BACK-END

Fernando D. Lorenzo García


Fases de un compilador
 El análisis se subdivide en tres niveles
Programa fuente

Análisis léxico

Análisis sintáctico Análisis


Análisis semántico +
Código intermedio
Optimización del
código intermedio
Síntesis del
Código objeto

Programa objeto
Fernando D. Lorenzo García
Fases de un compilador
 El nivel léxico se ocupa de las gramáticas
regulares o expresiones regulares mediante
el uso de autómatas finitos
 El nivel sintáctico se ocupa de las gramáticas
independientes del contexto mediante
reconocedores sintácticos basados en
máquinas de pila

Fernando D. Lorenzo García


Fases de un compilador
 El nivel semántico se ocupa de definir
completamente el lenguaje fuente, ya que
existe una información adicional dependiente
del contexto. Las herramientas utilizadas son
traducciones dirigidas por sintaxis y
gramáticas atribuidas
 Módulos relacionados al trasvase de
información de otros módulos
 Manejo de tabla de símbolos
 Manejo de errores
Fernando D. Lorenzo García
Implementación fases-pasadas
 Se denomina pasada a la implementación de
cada fase del compilador. Una pasada es un
proceso que realiza el compilador sobre el
conjunto completo del programa
 En la práctica, es importante reducir el
número de pasadas puesto que se reduce el
número de lecturas del programa y esto
implica una mayor velocidad

Fernando D. Lorenzo García


Implementación fases-pasadas
 Las fases desde el punto de vista lógico
reciben información elaborada en programas
fuentes y generan un segundo texto y así
sucesivamente (segundo texto genera un
tercero, etc.)
 Existen varias formas de implementación:

Fernando D. Lorenzo García


Implementación fases-pasadas
 Primera forma
 Que cada una de las fases fuera un programa y
se ejecutaran los programas concurrentemente.
Se ejecutan independientemente y
concurrentemente, pero existiendo comunicación
entre ellos.
 Es la manera mas directa
 Problema: Que el lenguaje de implementación no
admita programas concurrente

Fernando D. Lorenzo García


Implementación fases-pasadas
 Segunda forma
 Hacer que una fase sea subrutina de la siguiente
 Es equivalente a un proceso concurrente pero
con un solo procesador
 Simulación de lo anterior

Fernando D. Lorenzo García


Implementación fases-pasadas
 Tercera forma
 Entrelazar los códigos de las fases, es decir,
simplemente se diseñan F2 y F3 y luego se
entrelazan
F2 F3 Programa

*****************
*****************

*****************
*****************

Fernando D. Lorenzo García


Implementación fases-pasadas
 En la práctica lo mas usual es que el
analizador léxico se comporte como una
subrutina y que el analizador sintáctico y
semántico tengan sus códigos entrelazados

Fernando D. Lorenzo García


Implementación fases-pasadas
Compilador

Analizador léxico Subrutina

Analizador sintáctico
Call Analizador léxico

Analizador semántico Código


entrelazado
Analizador sintáctico
Call Analizador léxico

Analizador semántico

Fernando D. Lorenzo García


Implementación fases-pasadas
 Arrancaría el subprograma y el análisis
sintáctico haría una primera llamada al
análisis léxico, y las reiteraría en los casos
necesarios.

Fernando D. Lorenzo García


Descripción de las fases
 Análisis léxico
 Funciona a nivel de símbolos
 Lee los caracteres y construye símbolos, es decir,
agrupa los caracteres y reconoce el símbolo que
forma.
 Así, la unidad que recoge es el carácter y la que
entrega es el símbolo
 BEGIN símbolo Begin

Fernando D. Lorenzo García


Descripción de las fases
 Análisis léxico
 Al analizador sintáctico no le interesa cómo se
representa el símbolo, sino lo que él implica
 Ejemplo: BEGIN implica principio de un bloque
 Tampoco le interesa el nombre de las variables
sino la distinción y tipo de las variables
 El análisis léxico entrega un cierto código
simbólico que representa a cada símbolo

Fernando D. Lorenzo García


Descripción de las fases
 Análisis léxico
 Código ejemplo
 begin alfa := 3.51E-7 + beta ; end
 Al encontrar una variable lo normal es que la
introduzca en una tabla de símbolos que
Código número
almacena todas las(real,
Código begin
Código
Código
variable variables
entero, …)y alguna
asignación CódigoCódigo
suma
Código
variable
puntoycoma
Código end
información adicional para identificarla
completamente
 Lo que el análisis sintáctico recibe es:
 (begin)(var)(asig)(real)(suma)(var)(puntoycoma)(end)

Fernando D. Lorenzo García


Descripción de las fases
 Análisis sintáctico
 Se base en una descripción de las estructuras
que el lenguaje admite.
 Partimos de una determinada definición del
lenguaje (gramática) que nos indica que
programas y estructuras podemos escribir
 Toma los símbolos y trata de obtener una
representación de la estructura del programa
fuente, normalmente en un árbol

Fernando D. Lorenzo García


Descripción de las fases
 Análisis sintáctico
 Árbol que nos representa la estructura de nuestro
programa
Programa

Subprograma Subprograma

declaraciones instrucciones

Instrucc. 1 Instrucc. 2 Instrucc. 2

var := expresion

Fernando D. Lorenzo García


Descripción de las fases
 Análisis sintáctico
 En los nodos hoja se encuentran los símbolos
 Nodo hoja se denomina símbolo terminales
 Nodos no hoja se denomina símbolos no
terminales
 El análisis sintáctico va pasando por una serie de
estados y en cada estado sabremos en qué punto
del árbol nos encontramos
 No se genera el árbol pero si se simula su recorrido

Fernando D. Lorenzo García


Descripción de las fases
 Análisis sintáctico
 El análisis sintáctico se suele subdividir en
subrutinas
 Una por cada tipo de nodo y se van llamando entre si
 Ejemplo
 En una asignación se cogerá una variable, un
asignador y se llama a la subrutina de expresión
Asignación

var := expresion

Fernando D. Lorenzo García


Descripción de las fases
 Análisis semántico
 Revisa el programa fuente para tratar de
encontrar errores semánticos y reúne la
información sobre los tipos para la fase posterior
de generación de código.
 Un componente importante es la verificación de
tipos
 El compilador verifica que cada operador tiene
operandos permitidos por la especificación del
lenguaje

Fernando D. Lorenzo García


Descripción de las fases
 Generación de código intermedio
 Debido a que un código generado directamente
sería poco eficiente se crea un código intermedio
 Diseñado por el creador del compilador
 Características del código intermedio
 Fácil de producir
 Fácil de traducir al programa objeto
 Facilitar la programación y manipulación
 Se consigue que la optimización sea mas sencilla

Fernando D. Lorenzo García


Descripción de las fases
 Generación de código intermedio
 Los códigos intermedios se suelen llamar código
de tres direcciones
 Existen varios tipos o familias pero todas se
caracterizan porque las instrucciones constan de:
 Código de operación
 Tres direcciones
 Dos para operandos
 Una para el resultado

Fernando D. Lorenzo García


Descripción de las fases
 Generación de código intermedio
 Podemos distinguir distintos grupos de código
intermedio
 Cuartetos: Cada instrucción tiene cuatro partes:
 Un código y tres direcciones

C D1 D2 D3

Fernando D. Lorenzo García


Descripción de las fases
 Generación de código intermedio
 Tercetos: No aparece explícitamente la dirección
de almacenamiento del resultado, pero sí
implícitamente ya que se asocia con la dirección
del terceto

C D1 D2

C’ D1’ D2’

Fernando D. Lorenzo García


Descripción de las fases
 Generación de código intermedio
 Tercetos indirectos: En estos la asignación
implícita del resultado se realiza mediante una
tabla
Tabla

C D1 D2 Direc 1
Direc 2
C’ D1’ D2’
Direc 3
Direc 4

Fernando D. Lorenzo García


Descripción de las fases
 Generación de código intermedio
 Otro tipo de código intermedio sería la notación
polaca inversa
 Notación polaca inversa (POSFIJA)
 Para codificar expresiones aritméticas
 Estructura: Op1 Op2 Operador
 Ejemplo: A B +
 La notación usual se llama INFIJA
 Ejemplo: A + B

Fernando D. Lorenzo García


Descripción de las fases
 Optimización del código intermedio
 Esta fase trata de mejorar el código intermedio,
de modo que resulte un código máquina mas
rápido de ejecutar
 Las instrucciones se mejoran mediante varios
métodos fundamentales de optimización

Fernando D. Lorenzo García


Descripción de las fases
 Optimización del código intermedio
 Optimización de bucles
 Si detecta un bucle lo analiza y saca las instrucciones
invariantes al mismo, realizándose sólo una vez

FOR I = 1..10
A(I) := A( I+1 ) * 20 * K

VAR := 20 * K
FOR I = 1..10
A(I) := A( I+1 ) * VAR

Fernando D. Lorenzo García


Descripción de las fases
 Optimización del código intermedio
 Optimización local
 Son secuencias de instrucciones que se pueden
simplificar

A := A + 3


A := A + 8
A := A + 5

Se supone que A no varia entre las dos instrucciones

Fernando D. Lorenzo García


Descripción de las fases
 Optimización del código intermedio
 Optimización basada en estudios profundos
 Denominado “flujo de datos”, donde se hace un
estudio sobre lo que influyen unas variables
sobre otras y simplificarlo
V := A * B
M := V + W

… Se le asigna otro valor,
V := 50 pues no va a utilizarla mas
(Aprovecha el espacio de la variable)

Fernando D. Lorenzo García


Descripción de las fases
 Optimización del código intermedio
 Se llama compilador optimizador al que hace
mucha optimización asignando una parte
significativa del compilador a esta fase

Fernando D. Lorenzo García


Descripción de las fases
 Generación del código objeto
 Consiste en traducir el código intermedio a código
objeto, generalmente código ensamblador
 Es la fase menos sistematizada ya que depende
de la máquina objeto
 La traducción es fácil pero nos encontramos con
problemas de optimización donde se depende de
la máquina, e incluye dos aspectos

Fernando D. Lorenzo García


Descripción de las fases
 Generación de código objeto
 Uso de registros
 Pasar de variables a registros implica cambios en
relación a la velocidad de ejecución del programa
 Uso de mirillas (PEEPHOLE)
 Consiste en que para una máquina concreta existe un
repertorio particular de instrucciones que nos permiten
hacer mas rápido una secuencia de instrucciones

ADD B, 1
INR B La segunda es mas rápida

Fernando D. Lorenzo García


Descripción de las fases
 Manejo de la tabla de símbolos
 Una función esencial del compilador es registrar
los identificadores del programa fuente
 Variables, constantes, procedimientos, funciones, etc
 y reunir información sobre los distintos atributos
de cada identificador
 Variables: memoria asignada, tipo, ámbito, etc.
 Procedimiento: número y tipo de parámetros, tipo
devuelto, método de paso de argumentos, etc.

Fernando D. Lorenzo García


Descripción de las fases
 Manejo de la tabla de símbolos
 El análisis léxico introduce los identificadores en
la tabla de símbolos
 El resto de etapas introduce los atributos de cada
identificador y después la utilizan de varias forma
 La tabla de símbolos no es una estructura lineal
 La tabla es dinámica y suele ser de tipo pila con
determinadas particularidades

Fernando D. Lorenzo García


Descripción de las fases
 Manejo de errores
 Cada fase puede encontrar errores y debe
tratarlos de alguna forma
 Un compilador debe recuperarse del error y
continuar la compilación
 Debe informar de cual es el error mas probable y
su localización aproximada

Fernando D. Lorenzo García

También podría gustarte