estructura de un compilador 2

31
ESTRUCTURA DE UN ESTRUCTURA DE UN COMPILADOR COMPILADOR La estructura de un compilador, esta dividida en cuatro grandes módulos:

Upload: perlallamas

Post on 13-Jun-2015

1.310 views

Category:

Education


1 download

TRANSCRIPT

Page 1: Estructura de un compilador 2

ESTRUCTURA DE UN ESTRUCTURA DE UN COMPILADORCOMPILADOR

La estructura de un compilador, esta dividida en cuatro grandes módulos:

Page 2: Estructura de un compilador 2

PREPROCESADORPREPROCESADOREs el encargado de transformar el

código fuente de entrada original en el código fuente puro.

Es decir en expandir las macros, incluir las librerías, realizar un preprocesado racional

Extender el lenguaje y todo aquello que en el código de entrada sea representativo de una abreviatura para facilitar la escritura del mismo.

Page 3: Estructura de un compilador 2

COMPILACIONCOMPILACIONRecibe el código fuente puro,

este es él modulo principal de un compilador, pues si ocurriera algún error en esta etapa el compilador no podría avanzar.

Se somete al código fuente puro de entrada a un análisis léxico gráfico, a un análisis sintáctico, a un análisis semántico

construyen la tabla de símbolos, se genera un código intermedio al cual se optimiza para así poder producir un código de salida generalmente en algún lenguaje ensamblador.

Page 4: Estructura de un compilador 2

ENSAMBLADOENSAMBLADOEs otro compilador pues recibe un código

fuente de entrada escrito en ensamblador, y produce otro código de salida, llamado código binario no enlazado.

Proceso de compilación son los mismos.

En su interior realiza como su antecesor un análisis léxico gráfico, un análisis sintáctico, un análisis semántico, crea una tabla de símbolos, genera un código intermedio lo optimiza y produce un código de salida llamado código binario no enlazado.

Es un compilador que carece de los módulos de preprocesado y enlazado, y donde los módulos de compilación y ensamblado son los mismos.

Page 5: Estructura de un compilador 2

ENLAZADOENLAZADOEs el encargado de realizar

el enlazado del código de fuente de entrada (código maquina relocalizable) con las librerías que necesita

También de proveer al código de las rutinas necesarias para poder ejecutarse y cargarse a la hora de llamarlo para su ejecución, modifica las direcciones relocalizables y ubica los datos en las posiciones apropiadas de la memoria.

Es el que produce como salida el código binario enlazado.

Page 6: Estructura de un compilador 2

FASE DE ANALISISFASE DE ANALISIS ANALISIS LEXICO

El compilador revisa y controla que las "palabras" estén bien escritas y pertenezcan a algún tipo de token (cadena) definido dentro del lenguaje.

Como por ejemplo que sea algún tipo de palabra reservada, o si es el nombre de una variable que este escrita de acuerdo a las pautas de definición del lenguaje.

En esta etapa se crea la tabla de símbolos, la cual contiene las variables y el tipo de dato al que pertenece, las constantes literales, el nombre de funciones y los argumentos que reciben etc.

Page 7: Estructura de un compilador 2

FASE DE ANALISISFASE DE ANALISIS ANALISIS SINTACTICO

Se encarga de revisar que los tokens estén ubicados y agrupados de acuerdo a la definición del lenguaje.

Dicho de otra manera, que los tokens pertenezcan a frases gramaticales validas, que el compilador utiliza para sintetizar la salida.

Por lo general las frases gramaticales son representadas por estructuras jerárquicas, por medio de árboles de análisis sintáctico.

En esta etapa se completa la tabla de símbolos con la dimensión de los identificadores y los atributos necesarios etc.

Page 8: Estructura de un compilador 2

FASE DE ANALISISFASE DE ANALISIS ANALISIS SEMANTICO

Se encarga de revisar que cada agrupación o conjunto de token tenga sentido, y no sea un absurdo.

En esta etapa se reúne la información sobre los tipos para la fase posterior.

En esta etapa se utiliza la estructura jerárquica de la etapa anterior y así poder determinar los operadores, y operandos de expresiones y preposiciones

Page 9: Estructura de un compilador 2

FASE DE SINTESISFASE DE SINTESIS GENERACION DE CODIGO INTERMEDIO

Aunque algunos compiladores no la tienen, es bueno saber de su existencia.

En esta etapa se lleva el código del programa fuente a un código interno para poder trabajar mas fácilmente sobre él.

Esta representación interna debe tener dos propiedades, primero debe ser fácil de representar y segundo debe ser fácil de traducir al código objeto.

Page 10: Estructura de un compilador 2

FASE DE SINTESISFASE DE SINTESIS OPTIMIZACION DE

CODIGO

Se busca obtener el código mas corto y rápido posible, utilizando distintos algoritmos de optimización.

Page 11: Estructura de un compilador 2

FASE DE SINTESISFASE DE SINTESIS GENERACION DE CODIGO

Lleva el código intermedio final a código maquina o código objeto.

Selecciona las posiciones de memoria para los datos (variables)

Se traduce cada una de las instrucciones intermedias a una secuencia de instrucciones de maquina puro.

Page 12: Estructura de un compilador 2

TABLA DE SIMBOLOS

No es una etapa del proceso de compilación, sino que una tarea, una función que debe realizar el proceso de compilación.

En ella se almacenan los identificadores que aparecen en el código fuente puro, también los atributos de los mismos, su tipo, su ámbito y en el caso de los procedimientos el número de argumentos el tipo de los mismos etc.

En otras palabras una tabla de símbolos es una estructura de datos, que contiene un registro por cada identificador, y sus atributos.

La tabla de símbolo es accedida tanto para escritura como parar lectura por todas las etapas.

Page 13: Estructura de un compilador 2

DETECTOR DE ERRORES O MANEJADOR DE ERRORES

Al igual que la tabla de símbolos no es una etapa del proceso de compilación, si no que es una función, muy importante

Al ocurrir un error esta función debe tratar de alguna forma el error para así seguir con el proceso de compilación

La mayoría de errores son detectados en las etapas de análisis léxico, análisis sintáctico, análisis semántico.

Page 14: Estructura de un compilador 2

EJEMPLOSupongamos que un compilador tiene que analizar la siguiente

preposición:

Preposición: suma= var1 + var2 + 10;

Analisis Lexico

El analizador léxico lee los caracteres del programa fuente, y verifica que correspondan a una secuencia lógica (identificador, palabra reservada etc.)

Esta secuencia de caracteres recibe el nombre componente léxico o lexema.

En este caso el analizador léxico verifica si el identificador id1 (nombre interno para "suma") encontrado se halla en la tabla de símbolos, si no esta produce un error porque todavía no fue declarado.

Si la preposición hubiese sido la declaración del identificador "suma" en lenguajes C, C++ (int suma;) el analizador léxico agregaria un identificador en la tabla de símbolos, y así sucesivamente con todos los componentes léxicos que aparezcan.

id1= id2+ id3 * 10

Page 15: Estructura de un compilador 2

EJEMPLOAnalisis Sintactico

El analizador sintáctico impone una estructura jerárquica a la cadena de componentes léxicos, generada por el analizador léxico, que es representada en forma de un árbol sintáctico.

id1= id2+ id3 * 10

    =   /  \id1  +     /   \  id2   *        /   \     id3  10

Page 16: Estructura de un compilador 2

EJEMPLOAnalisis Semantico

El analizador semántico verificara en este caso que cada operador tenga los operandos permitidos.

id1= id2+ id3 * 10    =

   /   \id1   +      /   \   id2   *         /   \      id3 tipo_ent               |             10

Page 17: Estructura de un compilador 2

EJEMPLOGenerador de codigo intermedio

En esta etapa se lleva la preposición a una representación intermedia como un programa para una maquina abstracta.

id1= id2+ id3 * 10 temp1= tipo_ent(10)

temp2= id3 * temp1temp3= id2 + tem2id1= temp3

Page 18: Estructura de un compilador 2

EJEMPLOOptimizacion de codigo

El código intermedio obtenido es representado de una forma mas optima y eficiente.

id1= id2+ id3 * 10 temp1= id3 * 10.0

id1= id2 + temp1

Page 19: Estructura de un compilador 2

EJEMPLOGenerador de codigo

Finalmente lleva el código intermedio a un código objeto que en este caso es un código relocalizable o código ensamblador (también llamado código no enlazado).

Este es el código objeto obtenido que es enviado al modulo de ensamblado.

id1= id2+ id3 * 10 MOVF id3, R2

MULT #10.0, R2MOVF id2, R1ADDF R2, R1

MOVF R1, id1

Page 20: Estructura de un compilador 2

EJEMPLOPara entender todo esto veamos un ejemplo utilizando

como lenguaje en este caso el lenguaje C .

#include<stdio.h>void main(){char* frase= " Hola Mundo...!!!";printf("%s", frase );};

En la primer línea se encuentra una directiva de preprocesador, esta línea le indica al compilador que tiene que incluir la librería stdio.h, es decir transformar el código fuente de entrada en el código fuente puro (expandido).Al pasar por él modulo de preprocesado, el código fuente queda de la siguiente manera.

Page 21: Estructura de un compilador 2

EJEMPLOAl pasar por él modulo de preprocesado, el código

fuente queda de la siguiente manera.int feof(FILE *_stream);int ferror(FILE *_stream);int fflush(FILE *_stream);int fgetc(FILE *_stream);int fgetpos(FILE *_stream, fpos_t *_pos);char * fgets(char *_s, int _n, FILE *_stream);FILE * fopen(const char *_filename, const char *_mode);int fprintf(FILE *_stream, const char *_format, ...);int fputc(int _c, FILE *_stream);int fputs(const char *_s, FILE *_stream);size_t fread(void *_ptr, size_t _size, size_t _nelem, FILE *_stream);FILE * freopen(const char *_filename, const char *_mode, FILE *_stream);int fscanf(FILE *_stream, const char *_format, ...);int fseek(FILE *_stream, long _offset, int _mode);int fsetpos(FILE *_stream, const fpos_t *_pos);long ftell(FILE *_stream);size_t fwrite(const void *_ptr, size_t _size, size_t _nelem, FILE *_stream);int getc(FILE *_stream);int getchar(void);char * gets(char *_s);void perror(const char *_s);int printf(const char *_format, ...);int putc(int _c, FILE *_stream);int putchar(int _c);int puts(const char *_s);int remove(const char *_filename);int rename(const char *_old, const char *_new);void rewind(FILE *_stream);int scanf(const char *_format, ...);void setbuf(FILE *_stream, char *_buf);int setvbuf(FILE *_stream, char *_buf, int _mode, size_t _size);

int sprintf(char *_s, const char *_format, ...);int sscanf(const char *_s, const char *_format, ...);FILE * tmpfile(void);char * tmpnam(char *_s);int ungetc(int _c, FILE *_stream);int vfprintf(FILE *_stream, const char *_format, va_list _ap);int vprintf(const char *_format, va_list _ap);int vsprintf(char *_s, const char *_format, va_list _ap);int fileno(FILE *_stream);FILE * fdopen(int _fildes, const char *_type);int pclose(FILE *_pf);FILE * popen(const char *_command, const char *_mode);extern FILE _stdprn, _stdaux;void _stat_describe_lossage(FILE *_to_where);int _doprnt(const char *_fmt, va_list _args, FILE *_f);int _doscan(FILE *_f, const char *_fmt, void **_argp);int _doscan_low(FILE *, int (*)(FILE *_get), int (*_unget)(int, FILE *), const char *_fmt, void **_argp);int fpurge(FILE *_f);int getw(FILE *_f);int mkstemp(char *_template);char * mktemp(char *_template);int putw(int _v, FILE *_f);void setbuffer(FILE *_f, void *_buf, int _size);void setlinebuf(FILE *_f);char * tempnam(const char *_dir, const char *_prefix);int _rename(const char *_old, const char *_new);# 1 "hmundo.c" 2void main(){char* frase= " Hola Mundo...!!!";printf("%s", frase );};

Page 22: Estructura de un compilador 2

EJEMPLOEl nuevo código contiene el encabezado o prototipo de la/s función/es que se encuentran en el archivo de cabecera stdio.h, y que serán posiblemente utilizadas en el código fuente original. Este código es pasado al modulo de compilación quien luego de analizarlo y verificar si se encuentra correcto, transformara el código fuente puro (expandido) en código ensamblador y lo envía al modulo de ensamblado.

.file "hmundo.c"compiler_compiled.:___compiled_c:.textLC0:.ascii " Hola Mundo...!!!\0"LC1:.ascii "%s\0".align 2.globl _main_main:pushl %ebpmovl %esp,%ebp

subl $4,%espcall ___mainmovl $LC0,-4(%ebp)movl -4(%ebp),%eaxpushl %eaxpushl $LC1call _printfaddl $8,%espL1:leaveret  

Page 23: Estructura de un compilador 2

EJEMPLOEste código será analizado por él modulo de ensamblado, que

lo llevara a código binario no enlazado, y lo enviara al modulo de enlazado. El código de salida enviado al modulo de enlazado es el siguiente.

L&#0;³Ú(7ô&#0;.text&#0;@&#0;Œ&#0;Ì&#0;&#0; &#0;..............data&#0;@&#0;@&#0;@&#0;.bss&#0;@&#0;@&#0;&#128;Hola Mundo...!!!&#0;%s&#0;v&#0;�U‰åƒìèÝÿÿÿÇEü&#0;‹EüPh&#0;èÈÿÿÿƒÄ ÉÃv&#0;.file&#0;þÿ&#0;�ghmundo.c&#0;&#0;&#0;&#0;.............._main&#0;&#0;&#0;&#0;___main&#0;&#0;_printf&#0;&#0;%&#0;_compiled.&#0;___compiled_c&#0;

Page 24: Estructura de un compilador 2

EJEMPLOFinalmente él modulo de enlazado, vincula el código binario sin

enlazar con las librerías dinámicas necesarias según sea el caso o no. Y produce como salida el código binario enlazado o código

binario ejecutable.

MZ&#0;&#0; &#0;'&#0;ÿÿ&#0;`&#0;T&#0;$Id: xxx.asm built mm/dd/aa 00:00:00 by ...asm $@(#) xxx.asm built mm/dd/aa 00:00:00 by ...asm.............]v&#0; Hola Mundo...!!!&#0;%s&#0;v&#0;� �U‰åƒìèý &#0;ÇEüx"‹EüPhŠ"è, &#0;ƒÄ ÉÃv&#0;387�No &#0;80387 detected.Warning: Coprocessor not present and DPMI setup failed!If application attempts floating operations system may hang!¸'&#0;ÉÃv&#0;¸"&#0;ÉÃCall frame traceback EIPs:�0x&#0;0x&#0;Alignment Check&#0;Coprocessor Error&#0;Page fault&#0;General Protection Fault&#0;StackFault&#0;Segment Not Present&#0;Invalid TSS&#0;Coprocessor overrun&#0;Double............Division by Zero&#0;: sel=&#0; invalid&#0; base=&#0; limit=&#0;v&#0;U‰åƒìS‹]jÿu jè?&#0;�............

Page 25: Estructura de un compilador 2
Page 26: Estructura de un compilador 2

CARACTERISTICAS DE LOS CARACTERISTICAS DE LOS INTERPRETESINTERPRETES

INTERPRETACION ITERATIVA

• La interpretación iterativa es apropiada para lenguajes sencillos, donde se analiza y ejecuta cada expresión de forma directa, como podrían ser los códigos de máquinas abstractas o lenguajes de sentencias simples.

• La interpretación consiste en un ciclo básico de búsqueda, análisis y ejecución de instrucciones.

• El esquema sería:

InicializarREPETIR

Buscar siguiente Instrucción iSI encontrada ENTONCES

Analizar iEjecutar i

HASTA (que no haya más instrucciones)

Page 27: Estructura de un compilador 2

• INTERPRETACION ITERATIVA

• Cada instrucción se busca en el almacenamiento (memoria o disco) o, en algunos casos, es introducida directamente por el usuario.

• Luego la instrucción es analizada en sus componentes y se ejecutada.

CARACTERISTICAS DE LOS CARACTERISTICAS DE LOS INTERPRETESINTERPRETES

Page 28: Estructura de un compilador 2

INTERPRETACION RECURSIVA

• El diseño de nuevos lenguajes de programación se realiza en dos fases:

• Una primera fase de especificación semántica mediante la construcción de un intérprete prototipo que actúa como una especificación ejecutable y una segunda fase de implementación del compilador de dicho lenguaje.

• Para la construcción de prototipos suele utilizarse un modelo de interpretación recursiva donde las sentencias pueden estar compuestas de otras sentencias y la ejecución de una sentencia puede lanzar la ejecución de otras sentencias de forma recursiva.

• Los intérpretes recursivos no son apropiados para aplicaciones prácticas debido a su ineficiencia y se utilizan únicamente como prototipo ejecutable del lenguaje.

• El problema de especificar un lenguaje mediante un intérprete prototipo es decidir en qué lenguaje se implementa dicho intérprete.

Page 29: Estructura de un compilador 2
Page 30: Estructura de un compilador 2
Page 31: Estructura de un compilador 2