Proy_Compiladores

56
1 Fecha de Exposición: 14 de Junio del 2010 Profesora: Ing. Reinoso Alumnas: CORIMAYO, Carina Melisa MAMANI, Gabriela NOBLEGA, Valeria Laura COMPILADORES Revisión General de Temas tratados durante el cursado de la Materia

Transcript of Proy_Compiladores

Page 1: Proy_Compiladores

1

Fecha de Exposición: 14 de Junio del 2010Profesora: Ing. ReinosoAlumnas:

CORIMAYO, Carina MelisaMAMANI, GabrielaNOBLEGA, Valeria Laura

COMPILADORES

Revisión General de Temas tratados durante el cursado de la Materia

Page 2: Proy_Compiladores

2

¿Qué es un Compilador?Traductor: Un Traductor es un programa que toma como entrada un texto escrito en un lenguaje, llamado fuente y da como salida otro texto en un lenguaje, denominado objeto.

Tipos de Compilación:

Compilador: es un traductor que convierte un texto escrito en un lenguaje de alto nivel a un lenguaje de bajo nivel (código máquina).

Ensamblador: es un lenguaje de bajo nivel, donde cada sentencia del lenguaje fuente se traduce a una instrucción en código máquina.

Intérprete: no genera código objeto, analiza y ejecuta directamente cada proposición del código fuente.

Preprocesador: procesan un texto fuente modificándolo en cierta forma previamente a la compilación

TraductorLenguaje Fuente

Lenguaje Objeto

Page 3: Proy_Compiladores

3

Compilador:Un compilador presenta las siguientes características:

Programa que lee un programa fuente en un lenguaje, lo traduce a un programa equivalente en otro lenguaje además da mensajes de error y lleva a cabo determinadas correcciones y puede optimizar el código generado.

CompiladorPrograma Fuente

Programa Objeto

Error

Page 4: Proy_Compiladores

4

Interprete:Es un programa que lee un programa escrito en un lenguaje de

programación y produce el resultado de ejecutar tal programa.

IntérpretePrograma Fuente Salida

Datos

Page 5: Proy_Compiladores

5

Compilador vs. Intérprete Ventajas Compilador:* Se compila una vez, se ejecuta muchas veces.* Produce un código optimizado.* La ejecución del programa objeto es mucho mas rápida que si se interpreta

el programa fuente.* El compilador tiene una visión global del programa, por lo que la

información de mensajes de error es más detallada.* Mayor consumo de memoria Ventajas Intérprete:* Un Intérprete necesita menos memoria que un compilador.* Permiten una mayor interactividad con el código en tiempo de desarrollo, lo

que facilita la búsqueda de errores.* En algunos lenguajes está permitido es frecuente añadir código según se

ejecuta otro código.* Menor consumo de memoria

Page 6: Proy_Compiladores

6

Contexto de un Compilador

En el Proceso un programa fuente puede estar dividido en módulos almacenados en ficheros diferentes, la tarea de recopilar el código almacenado en estos ficheros pueden ser encomendados a un preprocesador.

En el Ensamblador muchos compiladores proporcionan el programa final en lenguaje para poder obtener un programa ejecutable es preciso ensamblar este programa final con un ensamblador convencional.

Esta herramienta toma el código máquina relocalizable de los distintos objetos compilados y de librerías modifica las direcciones relocalizables para situarlos a los valores absolutos adecuados y crear el programa ejecutable

PREPROCESADOR

COMPILADOR

ENSAMBLADOR

ENLAZADOR

LIBRERIAS

Programa Fuente

Programa Fuente Final

Código Ensamblador

Código Objeto en Código Máquina

Programa Final

Page 7: Proy_Compiladores

7

CompilaciónExiste 2 partes importantes en la compilación:

En la etapa de análisis se divide el programa fuente en sus piezas constituyentes y crea una representación intermedia del mismo.

En la etapa de síntesis se construye el programa destino deseado a partir de una descripción en un lenguaje de representación intermedia.

Compilación

Análisis Síntesis

Léxico“Tokens”

Sintáctico“Intrucciones”

Semántico“significado”

Generación deCódigo

Page 8: Proy_Compiladores

8

Fases de un Compilador

Dependencia Física

Independencia Física

Administrador de la Tabla de Símbolos

Analizador Léxico

Analizador Sintáctico

Analizador Semático

Generador de Código Intermedio

Optimizador de Código

Generador de Código

Generador de Código

Programa Fuente

Programa Objeto

Page 9: Proy_Compiladores

9

Análisis LéxicoDefinición:

El analizador léxico o scanner, trasforma el texto fuente en una secuencia ordenada de elementos léxicamente válidos (tokens).

Tipos de Tokens: Específicos:•Palabras Reservadas•Separadores•Operadores No Específicos•Identificadores•Constantes•Etiquetas Estructura•Tipo •Lexema

Analizador Léxico

Analizador Sintáctico

Tabla de Simbolos

Programa FuenteDivisión de Componentes

Léxicos

Page 10: Proy_Compiladores

10

Al iniciarse el proceso de compilación el código objeto es un flujo de caracteres que el analizador léxico debe reconocer y presentarlos en una representación mas útil para el analizador sintáctico. Las funciones características del analizador léxico son:

Eliminar espacios Ignorar comentarios Tratar con la tabla de símbolos Reconocer identificadores y palabra reservadas Manejar el fichero fuente Contabilizar posición de tokens Procesar macros, constantes, includes… Generar tokens bajo demanda del analizador sintáctico

Pasos para especificar un analizador léxico:

Estructurar la colección de tokens Identificar la colección de tokens Describir el lenguaje como expresiones regulares Especificar un diagrama de transición Traducir el diagrama a una tabla de transición.

Análisis Léxico

Page 11: Proy_Compiladores

11

Análisis SintácticoDefinición:El Analizador Sintáctico o parser recibe los tokens y comprueba su

ordenación correcta. Genera un árbol sintáctico.

Tiene como objetivo analizar la secuencia de tokens y comprobar que son correctas sintácticamente. A partir de una secuencia de tokens el analizador sintáctico nos devuelve si la secuencia es correcta o no sintácticamente, también nos devuelve el orden en el que hay que aplicar las producciones de la gramática para obtener la secuencia de entrada (árbol sintáctico).

Programa Fuente Analizador

LexicográficoAnalizador Sintáctico

Tabla de Simbolos

Siguiente Token()

TOKENS

Árbol Sintáctico

Page 12: Proy_Compiladores

12

Función:

Comprobar el orden en el que llegan los tokens.Construir una representación del programa fuente.Si es sintácticamente incorrecto generara error

Criterios de diseño del Analizador Sintáctico:

Eficiencia: El tiempo de análisis debe ser proporcional al tamaño del programa analizado

Predictivo: Al detectar algún error debe determinar que quiso decir.Sin Retroceso: Al ejecutar una tarea no vuelve para atrás.

Análisis Sintáctico

Page 13: Proy_Compiladores

13

Analizador SemánticoDefinición:

El analizador semántico comprueba que el árbol sintáctico es semánticamente válido. Revisa el programa fuente para comprobar que las reglas semánticas se cumplen. Genera un árbol semántico o etiquetado.

Validación:

Tipos de resultados intermedios Conversiones implícitas de tipo Sobrecarga de operadores

Page 14: Proy_Compiladores

14

Tabla de Símbolos y Gestión de Errores

Tabla de Símbolo: Es el medio de almacenamiento de toda la información referente a las variables y objetos en general del programa que se está compilando.

Gestión de Errores: Están incluidas en cada uno de los procesos de compilación (análisis lexicográfico, sintáctico y semántico), y se encargan de informar de los errores que encuentran en texto fuente, después de detectar un error cada fase debe tratar de alguna forma ese error para poder continuar la compilación.

Page 15: Proy_Compiladores

15

Tipos de Analizadores Sintácticos Analizador Descendente:Se construye el árbol de análisis sintáctico partiendo del símbolo inicial y aplicando las producciones

mediante derivaciones por la izquierda, el símbolo a expandir es el que este más a la izquierda.

Analizador Ascendente:Se construye el árbol de análisis sintáctico partiendo de la frase a reconocer y

aplicando las producciones mediante reducciones hasta llegar a símbolo inicial de la gramática.

Ejemplo:G=({+,*, ID, (, )}, {E, T, P}, E, P) P={ E:=E+T | T; T:=T*P | P; P:= ID | ( E ) }FraseID + ( ID * ID )

Ejemplo:G=({+,*, ID, (, )}, {E, T, P}, E, P) P={ E:=E+T | T; T:=T*P | P; P:= ID | ( E ) }FraseID + ( ID * ID )

Page 16: Proy_Compiladores

16

Tipos de Analizadores Sintácticos

L L

Es Predictivo

Se aplican las producciones por izquierda

El orden de lectura de la entrada es de izquierda a derecha

(1)

El orden de lectura de la entrada es de izquierda a derecha

S L R

Es Predictivo

Se aplican las producciones por derecha

(1)

Simple

L R

Es Predictivo

Se aplican las producciones por derecha

El orden de lectura de la entrada es de izquierda a derecha

(1)

Look a Head: Al construir el analizador va a tratar de mirar por adelantado el texto para comprenderlo y hacer mas sencillo y mejores estados

LA L R

Es Predictivo

Se aplican las producciones por derecha

El orden de lectura de la entrada es de izquierda a derecha

(1)

Descendentes

Ascendentes

Tipos de Analizadores

Page 17: Proy_Compiladores

17

Rutinas de Recuperación de Error…

Objetivo del Manejador de Errores:El analizador sintáctico informará de cualquier error de

sintaxis de manera inteligible. A su vez, deberá recuperarse de ellos para poder continuar procesando el resto de su entrada.

Objetivo de la Rutina de Recuperación de Errores:

Localizar el error Corregir el error Recuperar Continuar el análisis

Page 18: Proy_Compiladores

18

Rutinas de Recuperación de Error

Estrategias : Modo de Pánico

Método más sencillo de implementar Utilizado por la mayoría de los analizadores sintácticos Su sencillez está garantizada contra lazos infinitos

A Nivel de Fase Puede corregir supuestamente cualquier error El diseñador se encarga de elegir la correcion a utilizar Puede caer en lazos infinitos

Producción de Error Informa de los errores que podría corregir No detecta todos los errores solo aquellos predeterminados en su

diseño

Corrección Global Tienen interés desde un punto de vista teórico Se basa en el metodo de minima distancia de corrección de error

Page 19: Proy_Compiladores

19

Analizadores Descendentes Recursivos Características:

Producen retrocesos Prueban todas las posibilidades con un algoritmo de

backtracking. Fáciles de implementar.

Analizadores predictivos:

Utilizan información de la cadena de entrada para predecir qué subcadena lleva al éxito.

Producen los árboles de análisis desde el axioma hasta llegar a la frase (construcción de forma explícita)

Page 20: Proy_Compiladores

20

Analizador LL(1)

ELEMENTOS DE UN ANALIZADOR LR

Entrada: cadena de componente obtenida del análizador léxico

Salida: representación implícita del árbol de análisis sintáctico que va ha ser una lista de todas las producciones aplicadas.

Pila: simula la construcción del árbol de análisis y sus derivaciones.

Tabla de análisis: en las columnas van los símbolos terminales, en las filas los no terminales y en la intersección de las celdas se encuentra la producción a aplicar

Recuperación de error: métodos utilizados por el analizador sintáctico que permiten continuar con su funciones

RUTINA DE RECUPERACIÓN DE

ERRORES

ANALIZADOR LL(1)

El que crea el árbol y lo analiza

ENTRADACOMPONENTES LÉXICOS

SALIDAOK, ERROR

TABLA DE ANÁLISISMOTOR DEL

ANALIZADORPILA DE ANÁLISIS

Page 21: Proy_Compiladores

21

Tabla de Análisis Sintáctico

Pasos para la construcción de la Tabla:

1) Obtener:1) Conjunto Primero: es el conjunto formado

por todos los símbolos terminales que inician las cadenas y que se derivan del no terminal para el cual estamos calculando el conjunto

2) Conjunto Siguiente: es el conjunto formado por todos los símbolos terminales que cumplen con las reglas para el cálculo de este conjunto.

Basados en las reglas para la obtención de los mismos

2) Elaboración de la Tabla

Term n

No Terminal m

.

.

.

No Terminal 2

No Terminal 1

......Term 2Term 1

TABLA LL(1)

En donde en cada celda va una producción o un error

Page 22: Proy_Compiladores

22

Conjunto Primero: Reglas Si x es un Terminal y esta al inicio de la producción agregar al

Conj. Primero del no terminal para el que se calcula el Conj. Primero ese no terminal

Prim(NT)={x}

Si el No terminal produce λ añadir al Conj. Primero del no terminal para el que se calcula el Conj. Primero ese

Prim(NT)={λ}

Si NT ->UYZ, donde U es un no terminal añadir al Conj. Primero del no terminal para el que se calcula el Conj. Primero de ese No Terminal

Prim(NT)={Prim(U)}

Page 23: Proy_Compiladores

23

Se considera el lado derecho de las producciones donde aparezca el no terminal en cuestión y las veces en que este aparezca:

Si NT es el símbolo inicial de la gramática entonces al Conj. Siguiente de ese simbolo agregar el símbolo $

Sig(NT que es axiona)={$}

Si A deriva BCD y C es el no terminal en cuestión y D deriva en λ o es λ entonces al Conj. Siguiente de A añadir el Conj. Sig de A excepto λ

Sig(NT)={Sig (A)} Si A deriva BCD y C es el no terminal en cuestión y D NO

deriva en λ entonces al Conj. Siguiente de A añadir el Conj. Sig de A unido el Conj de Primero de D

Sig(NT)={Sig (A) U Prim (D)}

Conjunto Siguiente: Reglas

Page 24: Proy_Compiladores

24

Elaboración de la Tabla

Se considerará en primer lugar los símbolos obtenidos en el Conj. Primero, la intersección de este símbolo junto con el no terminal asociado al Conj determinará la producción aplicada para este caso.

Si el Conj. Primero contiene algún símbolo lamba entonces se considerarán los Conj Siguiente y el mismo no terminal pero en este caso la intersección contendrá la producción derivada en lambda.

Una vez que se han contemplado todos los Conj. Primeros se procede a completar la tabla con error el las celdas vacías.

Page 25: Proy_Compiladores

25

Algoritmo del Analizador LL(1)

Se carga la pila con el símbolo final de la cadena y el axioma y en la cima podemos tener:

a) un no terminal en cuyo caso se consulta a la tabla entrando a la misma con:

Tabla(NT, componente léxico) Si en ella existe un producción se saca este no terminal y se lo reemplaza por el lado derecho de la producción y en el caso de que haya un error podemos afirmar que la frase no pertenece a la gramática y se acude a la rutina de recuperación de error.

b) si en la cima de la pila tenemos un terminal y este coincide con la entrada avanzamos en la secuencia y se saca de la pila. Si no se lo encuentra entonces tenemos un error con lo que la frase no pertenece a la gramática

Todo esto se repite hasta que la pila quede vacía Si la pila esta vacía y la entrada también entonces se ha reconocido la

frase sino se ha encontrado un error, aunque este error no suele darse ya que este analizador lo detecta antes.

Page 26: Proy_Compiladores

26

Rutina de Recuperación de Errores en el LL(1)

Modo de Pánico: Se crea un conjunto de sincronización (formado por

componentes léxicos que podrían recuperar el análisis) En el caso de error:

Se omite el error Desecha el componente hasta que encuentre uno del conjunto

Se eliminan los elementos de la pila hasta que coincide con la entrada y pueda proseguir el análisis y puede ocurrir que

Si se encuentra el análisis se recupera u sigue de forma normal

Sino no hay recuperación

Inconveniente de la Rutina: trabaja de forma independiente a la pila de entrada.

Page 27: Proy_Compiladores

27

Analizador Sintáctico Ascendente LR

Características

No existe el retroceso Esta dirigido por tablas Su acción la decide con leer un componente

léxico (por ello se dice que es predictivo) Se basa en el Pivote o Mango

Page 28: Proy_Compiladores

28

Método del Pivote o Mango…

Primero encontrar en la pila de Análisis un

Prefijo viable

Es la forma de frase Símbolo final no coincide con el final de la

parte derecha de una producción de la gramática

El prefijo contiene todos los símbolo de parte derecha de la producción.

Page 29: Proy_Compiladores

29

Método del Pivote o Mango…

En cada forma de frase detectamos un mango, una pareja

[Producción, posición de la forma de frase]

S

Indica a partir de que punto es aplicable el mango en la producción

abbcde aAbcde aAcBe aAcde [2,2]

[3,2]*[1,1]

[2,2]

[3,2]

[4,4]*

[2,2]*

Page 30: Proy_Compiladores

30

Analizador LR

Elementos de un analizador

RUTINA DE RECUPERACIÓN DE

ERRORES

ANALIZADORLR

ENTRADACOMPONENTES LÉXICOS

SALIDA Lista de Producciones o

Representación implicita del árbol

PILA DE ANÁLISIS(símbolo, estado) TABLA LR

Page 31: Proy_Compiladores

31

Tabla LR

Terminales No Terminales

ACCION Ir A

ESTADOS

Page 32: Proy_Compiladores

32

Tabla de Simbolo LR

Acción dn: Desplazar el símbolo de la entrada la pila

desplazar rn: Reducción por la producción n Aceptar: esta acción detecta el final del

análisis e indica que acepta la frase ($) Error: detecta el error sintactico

Ir A n: desplazar a la pila el estado n Error: error detectado

Page 33: Proy_Compiladores

33

Construcción del Analizador LR (1)

1. Construir el autómata LR(0)

2. Construir la tabla LR

3. Se compacta la tabla cuando se puede (número de estado tiene que ser lo menor posible, + rápido)

Page 34: Proy_Compiladores

34

Construcción del Autómata LR(0)Construcción del Autómata LR(0)

El LR(0) tiene, en primer lugar los estados

Estados LR(0)

EstadoEstado

Núcleo

Resto

Page 35: Proy_Compiladores

35

Algoritmo para la construcción del Autómata

1. Ampliar la Gramática S añadiendo S’S2. Se construye el núcleo del estado 0: S’S

a) Para cada núcleo n: se fijan los símbolos cerradura, (no terminal a al derecha de un punto en AA·Bc, B seria el símbolo cerradura)

b) Para cada símbolo de cerradura se introduce en un nuevo estado.3. Para cada nuevo elemento se repite a y b, hasta que no se puedan

introducir nuevos elementos4. Para cada estado cerrado nuevo (n) construyó los nucleos de nuevos

estados mediante transicionesa) Realizo una particion del estado con una parte para cada simbolo con

estado t y otra parte con los elemtos LR(0)b) Para cada parte de la particion correspondiente a t, se crea un nuevo

nucleo, desplazando el punto de la derecha c) Si n es nucleo nuevo se traza una arista de n a m etiquetado con t .

Page 36: Proy_Compiladores

36

EjemploG=({a,b}, {S,B},S,P) para

P={ 0. S’S

1. SBB

2. BaB

3. Bb}

SBB BaB Bb

S’S

S’S

BaB Bb

SBB

BaB Bb

SaB

Bb

SaB

SBB

S

B

a

bb

b

B

a

B

a

0

1

2

3

4

5

6

Page 37: Proy_Compiladores

37

Analizadores Ascendentes(LR, LALR)

Algunos problemas no se pueden resolver de forma descendente ya que no es tán fácil quitar la ambigüedad. En algunos casos es más fácil demostrar algo ya existente.

Analizador ascendente El analizador trata de reducir la cadena de entrada w

al símbolo inicial S. En un proceso que recorre el árbol de derivación en sentido inverso que se llama reducción.

No sólo es necesario una gramática que no presente ambigüedades sino que también tenga el valor de k más pequeño.

Page 38: Proy_Compiladores

38

SLR(1): aplica las búsquedas hacia delante después de construir el autómata de elementos LR(0)

– Mismo autómata que LR(0), sólo cambia la construcción de la tabla.

– El autómata ignora la búsqueda hacia delante.

• La capacidad de los métodos LR(k) radica en la construcción de un autómata que integra las búsquedas hacia delante.

• Se utilizan nuevos elementos, denominados LR(1).

Analizadores Ascendentes(LR, LALR)

Page 39: Proy_Compiladores

39

Análisis sintáctico LR(1) simple o SLR(1)Capaz de analizar prácticamente todas las

construcciones que se presentan en un lenguaje No obstante, hay situaciones en las que no sirve y por

tanto no es analizable. Un estado puede tener tanto reducciones como

desplazamientos Utiliza el autómata finito determinista del LR(0) con

mayor potencia, impleando el token siguiente en la entrada para guiar sus acciones:

Consulta el token de entrada antes de cada desplazamiento para asegurar que existe una transición adecuada

Utiliza el conjunto siguiente de un no terminal para decidir si se debería realizar una reducción o no.

Page 40: Proy_Compiladores

40

Análisis sintáctico LR(1) simple o SLR(1)• Una gramática es SLR(1) si es posible construir una

tabla de análisis SLR sin entradas múltiples.

• Gramática LR(1) – No es usada en la práctica debido al gran número de estados que produce, sino que se utiliza una gramática simplificada, LALR(1); más potente que LR(0) pero menos que LR(1). .

• Una gramática es LALR(1) si no incluye conflictos de análisis. Es la más importante y la que implementan la mayoría de los generadores como CUP, Bison, y Yacc reconocen gramáticas LALR(1).

 

Page 41: Proy_Compiladores

41

Gramáticas de Atributos

Una gramática de atributos es una gramática libre de contexto cuyos símbolos pueden tener asociados atributos y las producciones pueden tener asociadas reglas de evaluación de los atributos

En la creación de compiladores se utilizan ecuaciones de atributos o reglas semánticas como método para expresar la relación entre el cálculo de los atributos y las reglas del lenguaje.

Cada producción (regla sintáctica) tiene asociada una acción semántica que se aplica cuando se realiza una reducción en el análisis sintáctico ascendente.

Page 42: Proy_Compiladores

42

Tipos de Atributos

Sintetizados: Su valor se calcula en función de atributos de nodos hijos en el árbol de análisis sintáctico.

Heredados: Para un hijo se calculan a través de los atributos del padre y hermanos en el árbol de análisis sintáctico.

Page 43: Proy_Compiladores

43

Sistema de Tipos

Sistema de tipos: reglas de un lenguaje que permiten asignar tipos a las distintas partes de un programa y verificar su corrección

Formado por las definiciones y reglas que permiten comprobar el dominio de un identificador, y en qué contextos puede ser usado.

Cada lenguaje tiene un sistema de tipos propio, aunque puede variar de una a otra implementación.

La comprobación de tipos es parte del análisis semántico.

Page 44: Proy_Compiladores

44

Sistema de Tipos Funciones principales

– Inferencia de tipos: calcular y mantener la información sobre los tipos de datos.

– Verificación de tipo: asegurar que las partes de un programa tienen sentido según las reglas de tipo del lenguaje.

• La información de tipos puede ser estática o dinámica:– LISP, CAML o Smalltalk utilizan información de tipos dinámica.– En ADA, Pascal o C la información de tipos es estática.– También puede ser una combinación de ambas formas.

• Cuantas más comprobaciones puedan realizarse en la fase decompilación, menos tendrán que realizarse durante la ejecución

– Mayor eficiencia del programa objeto.

Page 45: Proy_Compiladores

45

Sistema de Tipos

• Es parte de la comprobación de tipos:– Conversión de tipos explícita: transformación del tipo de una expresión

con un propósito determinado.– Coerción: conversión de tipos que realiza de forma implícita el

compilador.

• Conversión de tipos explícita: el programador indica el tipo destino.– Funciona como una llamada a función: recibe un tipo y devuelve otro.

• Conversión de tipos implícita: el compilador convierte automáticamente elementos de un tipo en elementos de otro.– La conversión se lleva a cabo en la acción semántica de la regla donde

se realiza.

Page 46: Proy_Compiladores

46

Sistema de Tipos

• Comprobador de tipos seguro: Durante la compilación (comprobación estática) detecta todos los posibles errores de tipo.

• Lenguaje fuertemente tipado: Si un fragmento de código compila es que no se van a producir errores de tipo.

• En la práctica, ningún lenguaje es tan fuertemente tipado que permita una completa comprobación estática.

Page 47: Proy_Compiladores

47

Sistema de Tipos

Información de tipos dinámica: El compilador debe generar código que realice la inferencia y verificación de tipos durante la ejecución del programa que se está compilando.

• Información de tipos estática:– Se utiliza para verificar la exactitud del programa antes

de la ejecución.

– Permite determinar la asignación de memoria necesaria para cada variable.

Page 48: Proy_Compiladores

48

Sistema de Tipos

Un lenguaje de programación contiene un conjunto de tipos predefinido denominados tipos simples

Algunos lenguajes permiten definir nuevos tipos simples: enumerado, subrango.

Todos los lenguajes permiten crear nuevos tipos complejos a partir de otros más simples mediante constructores de tipos:

Matrices, productos, registros, punteros, funciones, … En Pascal: array, set, record, ... En C++: struct, class, union, ...

Page 49: Proy_Compiladores

49

Generación de Código Intermedio

Después de los análisis sintácticos y semánticos, algunos compiladores generan una representación intermedia explicita del programa fuente. Se puede considerar esta representación intermedia como un programa para una maquina abstracta. Esta representación intermedia debe tener dos propiedades importantes, debe ser fácil de producir y fácil de traducir al programa objeto.

Page 50: Proy_Compiladores

50

Generación de Código Intermedio

El código intermedió es particularmente utilizado cuando el objetivo de compilador es producir código muy eficiente, ya que para hacerlo así se requiere una cantidad importante del análisis de las propiedades del código objetivo, y esto se facilita mediante el uso del código intermedio.

Page 51: Proy_Compiladores

51

Generación de Código Intermedio

El código intermedio también puede ser útil al hacer que un compilador sea mas fácilmente re dirigible: si el código intermedio es hasta cierto punto independiente de la maquina objetivo, entonces genera código para una maquina objetivo diferente solo requiere volver a escribir el traductor de código intermedio a código objetivo, y por lo regular esto es mas fácil que volver a escribir todo un generador de código.

Page 52: Proy_Compiladores

52

Generación de Código Intermedio

La representación intermedia tiene varias propiedades.

Primera cada Instrucción de tres direcciones tiene a lo sumo un operador, además de la asignación. Por tanto, cuando se generan esas instrucciones, el compilador tiene que decidir el orden en que deben efectuarse las operaciones; la multiplicación precede ala adición.

Segunda, el compilador debe generar un nombre temporal para guardar los valores calculados por cada instrucción.

Tercera, algunas instrucciones de "tres direcciones“ tienen menos de tres operandos, por ejemplo, la primera y la última instrucción.

Page 53: Proy_Compiladores

53

Lenguajes Intermedios

Árboles sintácticos abstractos (ASA)

El código se representa en forma de árbol donde-Cada nodo no terminal representa un operador

-Cada nodo terminal representa un operando

Más próximo al lenguaje fuente

Page 54: Proy_Compiladores

54

Lenguajes Intermedios

Grafos dirigidos acíclicos (GDA) El código se representa en forma de grafo

-Cada nodo no terminal representa un operador

-Cada nodo terminal representa un operando

-Se reutilizan los nodos Más próximo al lenguaje fuente

Page 55: Proy_Compiladores

55

Optimización de Código

La fase de optimización de código trata de mejorar el código intermedio, de modo que resulte un código de Maquina más rápido de ejecutar. Algunas optimizaciones son triviales.

Hay mucha variación en la cantidad de optimización de código que ejecutan los distintos compiladores, una parte significativa del tiempo del compilador se ocupa en esta fase. Sin embargo, hay optimizaciones sencillas que mejoran sensiblemente el tiempo de ejecución del programa objeto sin retardar demasiado la compilación

Page 56: Proy_Compiladores

56

Generación de Código

La fase final de un compilador es la generación de código objeto, que por lo general consiste en código máquina relocalizable o código ensamblador. Las posiciones de memoria se seleccionan para cada una de las variables usadas por el programa. Después cada una de las instrucciones intermedias se traduce a una secuencia de instrucciones de máquina que ejecutan la misma tarea. Un aspecto decisivo es la asignación de variables a registros.