You are on page 1of 13

Rx de un Compilador.

Por Gustavo Daniel Yapura

Este Documento esta disponible en formato Word 97 el ftp de la UTN Facultad Crdoba e ftp://ftp.frc.utn.edu.ar/pub/BBS/Documentos/Labsis/rxc.do

Introduccin:

En un mundo informatizado como en el que vivimos, en el que cada da que pasa dependemos ms y ms de un sistema informtico eficiente, el cual debe estar preparado para brindarnos la ms alta calidad de servicios prestaciones. Adems de ser sencillo en su manejo y sobre todo confiable, siendo estas caractersticas indispensables para el usuario final. Quien no se fija, ni pregunta como se realiza determinada tarea, pero si es buen critico a la hora de ver resultados, pero hay otros que contrarios a estos, se hace la pregunta del milln, "Cmo se logra hacer tal y tal cosa? ,"Cmo es posible que un graficador trabaje tan rpido?, Cmo es posible que un procesador de palabra a la hora de usar un diccionario sea tan eficiente?, Cmo es posible llevar los resultados de una aplicacin a otra?, o Cmo es posible que un programa que fue creado por una empresa puede trabajar con los datos de obtenidos de otro programa, echo por otra empresa?. Muchas pueden ser las respuestas, algunos argumentaran que es el sistema operativo, otros dirn que son las normas y estndares establecidos, otros dirn irnicamente que es ms sencillo de lo que se piensa, dirn que se hace cla con la rata aqu, se arrastra y se lleva a donde se quiere. Todos ellos tienen razn, sin embargo si indagamos mas a fondo. Surgirn preguntas ms directas como por ejemplo "Cmo se logra tal velocidad, con tan buen manejo de grfico?", claro que a todas ellas se puede responder diciendo, que todo se logra gracias al Hardware, y no estaramos totalmente errados, porque un buen Hardware conlleva a un buen resultado, a una buena calidad de impresin en caso de volcado al papel, una buena imagen si hablamos de grficos, o un buen tiempo de respuesta a la hora de realizar algn calculo matemtico, pero siempre el Hardware ser una parte, solo una parte. Es en este punto donde surge el Software, los programas, o como el modismo denota hoy en da, las aplicaciones. Es decir que para obtener un buen resultado no solo hace falta un buen Hardware acorde a los requerimientos de la tarea que se quiere realizar, sino que calidad, eficiencia, velocidad, y confiabilidad hoy en da son sinnimos de un buen trabajo en conjunto de la dupla Hardware y Software. Dejando de lado lo que es el Hardware, y profundizando lo que representa su par, palabra ya adoptada en nuestro idioma, y muy usada en el mundo de la informtica, deducimos que para obtener un buen software, ante todo esta el aspecto creador de quien lo realiza, luego hay que ver cual ser el entorno de trabajo en que actuara, cuales sern los requerimientos del mismo, hay que saber elegir que paradigma de programacin se usara. Despus de formuladas estas preguntas y de haber respondido a las mismas de manera apropiada. Hay que

elegir cual es el lenguaje de programacin ms conveniente para realizar dicha tarea. Y cuando digo lenguaje me refiero a la definicin del mismo segn el diccionario de la real academia espaola, " lenguaje. m. Conjunt de sonidos articulados con el que el hombre manifiesta lo que piensa y lo que siente. 2 lengua sistema de comunicacin y expresin verbal propio de un pueblo o nacin, o comn a varios..." si nos detenemos a analizar esta definicin dentro del mbito de la informtica, veremos que no se puede aplicar la misma en su totalidad. Pues bien, primero que nada, para que halla comunicacin deben existir por lo menos dos partes, si decimos que una de ellas es el ordenador y la otra el hombre, vemos que solamente una de ella cuenta con la capacidad del poder hablar, (hago notar que me refiero al hombre), mientras que la otra parte, el ordenador, si bien podra llegar a hablar con un "Hardware apropiado" y por supuesto con el correspondiente "software" capaz de manipular dicho hardware. Pero no nos salgamos del tema, si seguimos nuestro anlisis descubrimos que en la segunda parte de esta definicin hay un pequeo trozo de la misma que tiene mas sentido para nosotros lo informticos, " sistema de comunicacin y expresin...", si nos fijamos en la seccin 7. Informtica del mismo diccionario encontramos lo siguiente " Conjunto de signos y reglas que permite la comunicacin co un ordenador", podramos decir entonces que un lenguaje de programacin es un sistema de comunicacin y expresin, que utiliza signos y reglas que permiten la comunicacin entre un hombre y un ordenador". Un lenguaje de programacin o ms genricamente de computacin, es el medio por el cual el hombre interactua con un ordenador. Pero el lenguaje de computacin no es lo nico que se necesita para que se produzca la comunicacin, hace falta otro componente importante para completar el medio de comunicacin, es en este punto donde surge la palabra "interprete", cuya definicin dice "persona que explica a otra en lengua que entienda" en el mbito informtico, olvidmonos por un instante de la palabra persona, e "interpretemos" su significado. Se puede decir entonces que a travs de un interprete podramos pedir a un ordenador que realice una tarea determinada sin preocuparnos de los detalles. Claro que este interprete no es ms que una aplicacin (programa), que realiza la traduccin de lo que pedimos que comunique a un ordenador, por lo tant un interprete es capaz de conocer dos lenguajes el del emisor y el del receptor. En el mundo de la informtica existen muchos lenguajes de programacin, que trabajan con uno o varios paradigmas de programacin (estilos, formas, mtodos de programacin), por lo tanto es de suponer que existen distintas reglas de sintaxis y semntica para cada lenguaje de programacin como lo existe en cualquie otro lenguaje, sea cualquiera el tipo y contexto al que pertenezca. En tiempos ya muy remotos segn cuentan los que saben proliferaban los interpretes, quienes tomaban la peticin del usuario (hombre) e "interpretaban" misma y se la comunicaban al ordenador quien la ejecutaba, y esperaba una nueva peticin. La peticin era declarada dentro los parmetros de definicin del lenguaje usado. Con el tiempo se vio que el estar realizando una interpretacin y traduccin cada vez que se necesita realizar algo era poco efectivo, en cuanto a tiempo de trabajo del Hardware se refiere, y ms aun si se trataba de un conjunto grande de instrucciones (peticiones), es aqu donde entraron en juego los compiladores, quien al igual que sus antecesores realizan una traduccin de los programas (conjunto de intrusiones de un lenguaje) revisando que este dentro del marco de definicin del lenguaje de programacin utilizado. Con la diferencia que la traduccin se realiza una sola vez y de todo el programa. Despus de todos estos tpicos previos, podemos decir que la calidad de un buen software es producto de un lenguaje de computacin verstil, flexible y veloz, todo sinnimo de buen compilador, claro sin dejar de lado l capacidad creadora del programador (usuario, nosotros). "Cmo funciona un compilador? ", es la pregunta de todo aquel que se hace llamar programador, a grandes rasgos un compilador toma un programa escrito en un lenguaje de programacin con una gramtica, sintaxis y semntica definida, revisa que este dentro de las pautas de definicin del lenguaje, y lo traduce en programa d salida escrito en lenguaje binario, el cual es entendido por el ordenador y por lo tanto puede ser ejecutado por mismo (recordar que un interprete a diferencia de un compilador no traduce todo el programa sino que va realizando la traduccin e interpretacin de la misma paso a paso, sin crear ningn programa de salida ejecutable). Las partes del proceso de compilacin se dividen en dos: una llamada fase de Anlisis y otra

llamada fase de Sintaxis, las cuales interactuan entre si para la creacin de la tabla de smbolos y el control del manejador de errores, dentro del anlisis hay tres etapas llamadas anlisis lexicogrfico, anlisis sintctico, anlisis semntico. Dentro de la fase de Sntesis existen las etapas de generacin de cdigo intermedio, optimizacin de cdigo intermedio, y generacin de cdigo. Al tener que describir como funciona un compilador tenemos que tener en claro en no confundir los trmino compilador y compilacin, se debe entender que al decir compilador nos referimos al programa, y al decir compilacin al proceso en s. En esencia ambos trminos cumplen con la definicin ms simple de un compilador, es decir, sea el programa compilador o el proceso de compilacin, ambos reciben como entrada u cdigo escrito en algn lenguaje y producen como salida otro cdigo escrito en otro lenguaje.

Estructura de un Compilador:

La estructura de un compilador, esta dividida en cuatro grandes mdulos, cada uno independiente del otro, s podra decir que un compilador esta formado por cuatros mdulos mas a su vez.

El primero de ellos es el preprocesador, es el encargado de transformar el cdigo fuente de entrada original en el cdigo fuente puro. Es decir en expandir las macros, incluir las libreras, realizar un preprocesado racion

(capacidad de enriquecer a un lenguaje antiguo con recursos ms modernos), extender el lenguaje y todo aquello que en el cdigo de entrada sea representativo de una abreviatura para facilitar la escritura del mismo.

El segundo modulo es el de compilacin que recibe el cdigo fuente puro, este es l modulo principal de un compilador, pues si ocurriera algn error en esta etapa el compilador no podra avanzar. En esta etapa se somete al cdigo fuente puro de entrada a un anlisis lxico grfico, a un anlisis sintctico, a un anlisis semntico, que construyen la tabla de smbolos, se genera un cdigo intermedio al cual se optimiza para as poder producir un cdigo de salida generalmente en algn lenguaje ensamblador.

El tercer modulo es el llamado modulo de ensamblado, este modulo no es ni ms mi menos que otro compilador pues recibe un cdigo fuente de entrada escrito en ensamblador, y produce otro cdigo de salida, llamado cdigo binario no enlazado. Si por un momento viramos a este modulo como un programa independiente, veramos que en este caso los trminos programa compilador y proceso de compilacin son los mismos. Pues este modulo no es mas que un compilador, que en su interior realiza como su antecesor un anlisis lxico grfico, un anlisis sintctico, un anlisis semntico, crea una tabla de smbolos, genera un cdigo intermedio lo optimiza y produce un cdigo de salida llamado cdigo binario no enlazado, y a todo est conjunto de tares se los denomina proceso de compilacin. Como se puede ver este compilador (llamado ensamblador) a diferencia de los dems compiladores no realiza una expansin del cdigo fuente original(cdigo fuente de entrada), tiene solamente un proceso de compilacin y por supuesto no enlaza el cdigo fuente. Es un compilador que carece de los mdulos de preprocesado y enlazado, y donde los mdulos de compilacin y ensamblado son los mismos.

El cuarto y ultimo modulo es el encargado de realizar el enlazado del cdigo de fuente de entrada (cdigo maquina relocalizable) con las libreras que necesita, como as tambin de proveer al cdigo de las rutinas necesarias para poder ejecutarse y cargarse a la hora de llamarlo para su ejecucin, modifica las direcciones

relocalizables y ubica los datos en las posiciones apropiadas de la memoria. Este ultimo modulo es el que produce como salida el cdigo binario enlazado. Ya sea dinmico o esttico, al decir dinmico se refiere a que el cdigo producido utiliza libreras dinmicas (libreras ya cargadas en el sistema), esto implica que se obtendr un cdigo ms corto y que se actualizara automticamente si aparece alguna nueva versin de las libreras, mientras que el esttico se refiere al echo que no se realiza enlace con ninguna librera y por lo tanto se obtendr un cdigo mas largo con una copia de las rutinas de librera que necesita.

Estructura del proceso de Compilacin:

Analizando en detalle el proceso de compilacin, se divide en dos grandes fases, una de Anlisis y la otra de Sntesis. Fase de Anlisis:

En el llamado anlisis lexicogrfico o lxico, el compilador revisa y controla que las "palabras" estn bien escritas y pertenezcan a algn tipo de token (cadena) definido dentro del lenguaje, como por ejemplo que sea algn tipo de palabra reservada, o si es el nombre de una variable que este escrita de acuerdo a las pautas de definicin del lenguaje. En esta etapa se crea la tabla de smbolos, 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. En el anlisis sintctico como su nombre lo indica se encarga de revisar que los tokens estn ubicados y agrupados de acuerdo a la definicin 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 jerrquicas, por medio de rboles de anlisis sintctico. En esta etapa se completa la tabla de smbolos con la dimensin de los identificadores y los atributos necesarios etc. El anlisis semntico se encarga de revisar que cada agrupacin o conjunto de token tenga sentido, y no sea un absurdo. En esta etapa se rene la informacin sobre los tipos para la fase posterior, en esta etapa se utiliza la estructura jerrquica de la etapa anterior y as poder determinar los operadores, y operandos de expresiones preposiciones. Fase de Sntesis:

Etapa de generacin de cdigo intermedio, aunque algunos compiladores no la tienen, es bueno saber de su existencia, en esta etapa se lleva el cdigo del programa fuente a un cdigo interno para poder trabajar mas fcilmente sobre l. Esta representacin interna debe tener dos propiedades, primero debe ser fcil de representar y segundo debe ser fcil de traducir al cdigo objeto. En la etapa de optimizacin de cdigo, se busca obtener el cdigo mas corto y rpido posible, utilizando distintos algoritmos de optimizacin. Etapa de generacin de cdigo, se lleva el cdigo intermedio final a cdigo maquina o cdigo objeto, que po lo general consiste en un cdigo maquina relocalizable o cdigo ensamblador. Se selecciona las posiciones de

memoria para los datos (variables) y se traduce cada una de las instrucciones intermedias a una secuencia de instrucciones de maquina puro. La tabla de smbolos no es una etapa del proceso de compilacin, sino que una tarea, una funcin que debe realizar el proceso de compilacin. En ella se almacenan los identificadores que aparecen en el cdigo fuente puro, como as tambin los atributos de los mismos, su tipo, su mbito y en el caso de los procedimientos el nmero de argumentos el tipo de los mismos etc. En otras palabras una tabla de smbolos es una estructura de datos, que contiene un registro por cada identificador, y sus atributos. La tabla de smbolo es accedida tanto para escritura como parar lectura por todas las etapas. Detector de errores o manejador de errores, al igual que la tabla de smbolos no es una etapa del proceso de compilacin, si no que es una funcin, muy importante, pues al ocurrir un error esta funcin debe tratar de alguna forma el error para as seguir con el proceso de compilacin (la mayora de errores son detectados en la etapas de anlisis lxico, anlisis sintctico, anlisis semntico).

Supongamos que un compilador tiene que analizar la siguiente preposicin: Preposicin: suma= var1 + var2 + 10; Anlisis Lxico

El analizador lxico lee los caracteres del programa fuente, y verifica que correspondan a una secuencia lgica (identificador, palabra reservada etc.). Esta secuencia de caracteres recibe el nombre componente lxico o lexema. En este caso el analizador lxico verifica si el identificador id1 (nombre interno para "suma") encontrado se halla en la tabla de smbolos, si no esta produce un error porque todava no fue declarado, si la

preposicin hubiese sido la declaracin del identificador "suma" en lenguajes C, C++ (int suma;) el analizador lxico agregaria un identificador en la tabla de smbolos, y as sucesivamente con todos los componentes lxicos que aparezcan. id1= id2+ id3 * 10 Anlisis Sintctico El analizador sintctico impone una estructura jerrquica a la cadena de componentes lxicos, generada por analizador lxico, que es representada en forma de un rbol sintctico. = / \ id1 + / \ id2 + / \ id3 10 Anlisis Semntico El analizador semntico verificara en este caso que cada operador tenga los operandos permitidos. = / \ id1 + / \ id2 + / \ id3 tipo_ent | 10 Generador de cdigo intermedio En esta etapa se lleva la preposicin a una representacin intermedia como un programa para una maquina abstracta. temp1= tipo_ent(10) temp2= id3 * temp1 temp3= id2 + tem2 id1= temp3 Optimizacin de cdigo El cdigo intermedio obtenido es representado de una forma mas optima y eficiente. temp1= id3 * 10.0 id1= id2 + temp1

Generador de cdigo

Finalmente lleva el cdigo intermedio a un cdigo objeto que en este caso es un cdigo relocalizable o cdig ensamblador (tambin llamado cdigo no enlazado). MOVF id3, R2 MULT #10.0, R2 MOVF id2, R1 ADDF R2, R1 MOVF R1, id1

Este el cdigo objeto obtenido que es enviado al modulo de ensamblado. Para entender todo esto veamos un ejemplo utilizando como lenguaje en este caso al popular lenguaje de programacin C creado por Kernighan y Ritchie. El siguiente cdigo esta definido de acuerdo al standard ANSI C.

#include<stdio.h> void main() { char* frase= " Hola Mundo...!!!"; printf("%s", frase );
}; En la primer lnea se encuentra una directiva de preprocesador, esta lnea le indica al compilador que tiene que incluir la librera stdio.h, es decir transformar el cdigo fuente de entrada en el cdigo fuente puro (expandido). Al pasar por l modulo de preprocesado, el cdigo fuente queda de la siguiente manera.

# 1 "hmundo.c" # 1 "c:/compilador/include/stdio.h" 1 3 # 1 " c:/compilador/include/sys/types.h" 1 3 # 12 " c:/compilador/include/stdio.h" 2 3 typedef void *va_list; typedef long unsigned int size_t; typedef struct { int _cnt; char *_ptr; char *_base; int _bufsiz; int _flag; int _file; char *_name_to_remove; } FILE; typedef unsigned long fpos_t; extern FILE __stdin, __stdout, __stderr; void clearerr(FILE *_stream);

int fclose(FILE *_stream); 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" 2 void main() { char* frase= " Hola Mundo...!!!"; printf("%s", frase ); };
El nuevo cdigo contiene el encabezado o prototipo de la/s funcin/es que se encuentran en el archivo de cabecera stdio.h, y que sern posiblemente utilizadas en el cdigo fuente original. Este cdigo es pasado al modulo de compilacin quien luego de analizarlo y verificar si se encuentra correcto, transformara el cdigo fuente puro (expandido) en cdigo ensamblador y lo enva al modulo de ensamblado.

.file "hmundo.c" compiler_compiled.: ___compiled_c: .text LC0: .ascii " Hola Mundo...!!!\0" LC1: .ascii "%s\0" .align 2 .globl _main _main: pushl %ebp

movl %esp,%ebp subl $4,%esp call ___main movl $LC0,-4(%ebp) movl -4(%ebp),%eax pushl %eax pushl $LC1 call _printf addl $8,%esp L1: leave ret
Este cdigo ser analizado por l modulo de ensamblado, que lo llevara a cdigo binario no enlazado, y lo enviara al modulo de enlazado. El cdigo 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; UE&#0;EPh&#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;
Finalmente l modulo de enlazado, vincula el cdigo binario sin enlazar con las libreras dinmicas necesarias segn sea el caso o no. Y produce como salida el cdigo binario enlazado o cdigo 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;Ex"EPh", &#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;Stack Fault&#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;US]j j?&#0; ............
Este es el cdigo final conocido como cdigo maquina.

e-mail: gdit@bbs.frc.utn.edu.ar

You might also like