You are on page 1of 9

4o Ingenier a Inform atica

II26 Procesadores de lenguaje


Estructura de los compiladores e int erpretes Esquema del tema
1. Introducci on 2. Etapas del proceso de traducci on 3. La interpretaci on 4. La arquitectura real de compiladores e int erpretes 5. Resumen del tema

1.

Introducci on

Tanto los compiladores como los int erpretes son programas de gran complejidad. Afortunadamente, se sabe suciente acerca de c omo estructurarlos y hay sucientes herramientas formales para que la complejidad se reduzca a niveles razonables. En este tema veremos en qu e fases se divide un compilador o un int erprete. Veremos tambi en qu e tienen en com un y c omo dieren entre s compiladores e int erpretes.

2.

Etapas del proceso de traducci on

Podemos modelar el proceso de traducci on entre dos lenguajes como el resultado de dos etapas. En la primera etapa se analiza la entrada para averiguar qu e es lo que se intenta comunicar. Esto es lo que se conoce como an alisis. El fruto de esta etapa es una representaci on de la entrada que permite que la siguiente etapa se desarrolle con facilidad. La segunda etapa, la s ntesis, toma la representaci on obtenida en el an alisis y la transforma en su equivalente en el lenguaje destino. En el caso de la interpretaci on, se utiliza la representaci on intermedia para obtener los resultados deseados.

2.1.

An alisis

El objetivo de esta etapa es obtener una representaci on de la entrada que nos permita realizar la s ntesis o la interpretaci on con comodidad. La representaci on que nosotros utilizaremos es la que se llama arbol de sintaxis abstracta. Un ejemplo ser a la traducci on siguiente: asignaci on

valor= valor+inc; /* Actualizamos */

idvalor suma

idvalor idinc El paso de la entrada al arbol de sintaxis abstracta no es trivial. Para facilitarlo, se divide la tarea en varias partes. Sup on que tuvieras que describir un lenguaje de programaci on. Una manera de hacerlo ser a comenzando por describir cu ales son las unidades elementales tales como identicadores, palabras reservadas, operadores, etc. que se encuentran en la entrada. Despu es podr as describir c omo se pueden combinar esas unidades en estructuras mayores tales como expresiones, asignaciones, bucles y dem as. Finalmente, especicar as una serie de normas que deben cumplirse para que el programa, adem as de estar bien escrito, tenga signicado. Estas normas se reeren

II26 Procesadores de lenguaje

a aspectos tales como que las variables deben declararse o las reglas que se siguen para decidir los tipos de las expresiones. Las tres fases que hemos mencionado tienen su reejo en las tres fases en que se divide el an alisis: An alisis l exico: se encarga de la divisi on de la entrada en componentes l exicos. An alisis sint actico: se encarga de encontrar las estructuras presentes en la entrada. An alisis sem antico: se encarga de comprobar que se cumplen las restricciones sem anticas del lenguaje. 2.1.1. An alisis l exico

En esta fase se analiza la entrada car acter a car acter y se divide en una serie de unidades elementales: los componentes l exicos. Cada uno de estos componentes se clasica en una categor a y puede recibir uno o m as atributos con informaci on relevante para otras fases (por ejemplo un entero tendr a una etiqueta indicando su valor). El criterio que se emplea para clasicar cada componente es su pertenencia o no a un lenguaje (generalmente regular). Esta fase adem as se encarga de ltrar elementos tales como los blancos y los comentarios. En nuestro ejemplo, tendr amos como categor as los identicadores, la suma, la asignaci on y el punto y coma. Podemos suponer que los identicadores son secuencias de letras y d gitos que comienzan por una letra. Adem as, hay otros componentes que se ltran o, m as formalmente, son omitidos: los blancos y los comentarios. Teniendo en cuenta esto, nuestro analizador l exico ve:
v a a m l o o s r = * / v a l o r + i n c ; / * A c t u a l i z

Y lo que pasa al sint actico es:


idvalor asig idvalor suma idinc pyc

Donde hemos asumido que id es el componente l exico que representa los identicadores; asig representa la asignaci on; suma, las sumas y pyc, el punto y coma. Como puedes ver, han desaparecido tanto los blancos como los comentarios. 2.1.2. An alisis sint actico

Partiendo de lo que ha recibido del analizador l exico, la tarea del analizador sint actico consiste en ir descubriendo las estructuras presentes en el c odigo de acuerdo con una gram atica incontextual. A partir de las estructuras que ha encontrado, el analizador sint actico construye un arbol sint actico (que no hay que confundir con el arbol de sintaxis abstracta comentado antes). Para especicar las construcciones que se permiten, se suelen emplear gram aticas incontextuales, que veremos luego. En nuestro caso podemos pensar que las reglas que se siguen son que una asignaci on se compone de un identicador, seguido de un s mbolo de asignaci on, seguido de una expresi on y de un punto y coma. Esto se escribe en la gram atica en forma de regla: Asig id asig Expr pyc. An alogamente, podemos decir que una expresi on es bien un identicador, bien la suma de dos expresiones. En reglas: Expr Expr id Expr suma Expr

El arbol sint actico nos permite expresar c omo se puede fabricar (formalmente, derivar) la entrada a partir de las reglas. En nuestro caso, el arbol tiene un aspecto similar a:

Estructura de los compiladores e int erpretes

Asig Expr Expr


idvalor asig idvalor suma

Expr
idinc pyc

Es interesante darse cuenta de que, tanto en las reglas como en la construcci on del arbol, se hace caso omiso de los posibles atributos de los componentes l exicos; u nicamente se tiene en cuenta su categor a. 2.1.3. An alisis sem antico

La u ltima fase del an alisis, el an alisis sem antico, toma como entrada el arbol sint actico y comprueba si, adem as de las restricciones sint acticas, se cumplen otras restricciones impuestas por el lenguaje y que no pueden ser comprobadas mediante una gram atica incontextual. Algunos ejemplos de estas restricciones son la necesidad de declarar las variables antes de usarlas, las reglas de tipos o la coincidencia entre los par ametros de las funciones en las deniciones y las llamadas. Como salida de esta fase, se obtiene una representaci on sem antica, por ejemplo el arbol de sintaxis abstracta comentado antes. Adem as, se ha comprobado que tanto valor como inc est an declaradas y con tipos compatibles.

2.2.

S ntesis

Una vez analizado el programa de entrada, es necesario generar c odigo, a ser posible eciente, para la m aquina objetivo. Supongamos que tenemos L lenguajes fuente y queremos escribir compiladores para M m aquinas distintas. La aproximaci on inmediata, escribir un compilador para cada par lenguaje-m aquina, supone escribir L M compiladores. Sin embargo, si los lenguajes son razonablemente parecidos (como Pascal y C), existe una aproximaci on mejor: escribir L traductores desde los lenguajes fuente a un lenguaje intermedio y despu es escribir M traductores de este lenguaje intermedio a los lenguajes m aquina correspondientes:
Java Sparc ML PowerPC Pascal Pentium C Alpha C++ C++ C Alpha Pascal L. interm. Pentium ML PowerPC Java Sparc

Esta aproximaci on tiene diversas ventajas. La m as obvia es la reducci on del n umero de traductores que se necesitar an. Adem as, si se quiere a nadir un nuevo lenguaje a nuestra colecci on, no es necesario crear M compiladores para el, basta con un traductor al lenguaje intermedio. Esto permite que se desarrollen nuevos lenguajes con comodidad. M as importante, si aparece una nueva arquitectura, basta con desarrollar un traductor del lenguaje intermedio a esta nueva m aquina. Otro aspecto de gran importancia es que la representaci on intermedia suele elegirse de modo que no necesite el gran nivel de detalle que exige el c odigo m aquina y permita abstraer problemas como el n umero limitado de registros disponibles o la gran variedad de instrucciones de m aquina donde elegir. Esto simplica notablemente la generaci on de c odigo desde el AST.
c Universitat Jaume I 2008-2009

II26 Procesadores de lenguaje

Desgraciadamente, esta aproximaci on no es gratis ni universal. Encontrar un lenguaje intermedio que sea adecuado para todas las arquitecturas y lenguajes no es tarea sencilla y probablemente no sea posible. En la pr actica se emplea para lenguajes similares y m aquinas destino que compartan una serie de caracter sticas comunes. Por otro lado, determinadas caracter sticas del par (lenguaje fuente, m aquina destino) pueden no aprovecharse. Por ejemplo, si sabemos que la m aquina destino tiene instrucciones especializadas para saltos mediante una tabla, el c odigo generado para las estructuras switch-case deber a reejarlo. Esto no es posible si el lenguaje intermedio no recoge este tipo de construcciones. Pese a todo, las ventajas superan a los inconvenientes y la generaci on de c odigo se divide habitualmente en dos etapas: Generaci on de c odigo intermedio. Generaci on de c odigo objeto: se traduce el c odigo intermedio a c odigo de m aquina. 2.2.1. Generaci on de c odigo intermedio

En esta etapa se traduce la entrada a una representaci on independiente de la m aquina pero f acilmente traducible a lenguaje ensamblador. Esta representaci on puede tomar diversas formas que pueden entenderse como visiones idealizadas del lenguaje ensamblador de una m aquina virtual. Algunas de las representaciones m as comunes son: Arboles de representaci on intermedia (distintos de los arboles de sintaxis abstracta), c odigo de tres direcciones, c odigo de dos direcciones, c odigo de pila, representaciones en forma de grafo, mixtas, etc. . . En nuestro caso, usando la m aquina virtual de las pr acticas, la sentencia valor= valor+inc; puede traducirse por algo similar a: lw $r0, -2($fp) lw $r1, -1($fp) add $r0, $r0, $r1 sw $r0, -2($fp) 2.2.2. # # # # Carga valor en $r0 Carga inc en $r1 Hace la suma Guarda el resultado en valor

Generaci on de c odigo objeto

Una vez obtenido el c odigo intermedio, es necesario generar el c odigo objeto. Lo habitual es que no se genere el c odigo objeto directamente sino que se genere c odigo en ensamblador y despu es se utilice un ensamblador. De cualquier forma, esta fase es totalmente dependiente de la arquitectura concreta para la que se est e desarrollando el compilador. En particular, hay que enfrentarse a problemas como: Selecci on de instrucciones teniendo en cuenta su eciencia. Elecci on de los modos de direccionamiento adecuados. Utilizaci on eciente de los registros. Empleo eciente de la cach e. Otros. . . Las instrucciones que genera gcc para nuestro ejemplo son:

Estructura de los compiladores e int erpretes

movl leal addl

-8(%ebp), %edx -4(%ebp), %eax %edx, (%eax)

Como ves, se tiene en cuenta el tama no de las variables (por eso se emplea 4 y 8 en lugar de 2 y 1), se utilizan registros de la m aquina concreta y se emplean instrucciones especiales como leal para aprovechar mejor el procesador. 2.2.3. Optimizaci on

Tanto a la hora de generar c odigo intermedio como c odigo objeto es habitual encontrarse con que el resultado de la traducci on es muy ineciente. Esto es debido a que la traducci on se realiza de manera local, lo cual provoca la aparici on de c odigo redundante. Por ejemplo, la sentencia a[i]=a[i]+1 genera el siguiente c odigo intermedio: addi $r0, $zero, 0 lw $r1, 3($zero) add $r0, $r0, $r1 lw $r0, 0($r0) addi $r1, $zero, 1 add $r0, $r0, $r1 addi $r1, $zero, 0 lw $r2, 3($zero) add $r1, $r1, $r2 sw $r0, 0($r1) # # # # # # # # # # Direcci on de a Acceso a i Sumamos i a la direcci on de a Valor de a[i] Valor entero (1) Hacemos la suma Direcci on de a Acceso a i Sumamos i a la direcci on de a Guardamos el resultado

Sin embargo, es f acil darse cuenta de que no hace falta calcular dos veces la direcci on de a[i], con lo que se pueden ahorrar, al menos, tres instrucciones.
Ejercicio 1

Escribe el c odigo de menor longitud que se te ocurra para el ejemplo anterior. No puedes utilizar instrucciones distintas de las mostradas. En otras ocasiones, es posible utilizar instrucciones especializadas para mejorar la velocidad. Por ejemplo, si la instrucci on anterior a valor= valor+inc; es inc=1;, gcc -O genera incl %ebx Por esto, es habitual incluir m odulos encargados tanto de la optimizaci on del c odigo intermedio como del c odigo objeto.

2.3.

Otros m odulos del compilador

Aunque en principio ser a posible escribir el compilador como la concatenaci on de las distintas fases que se han descrito, existen dos m odulos que no forman parte de esta secuencia pero tienen un papel fundamental para el proceso de compilaci on: la tabla de s mbolos y el m odulo de gesti on de errores. 2.3.1. La tabla de s mbolos

A lo largo del proceso de an alisis se va generando gran cantidad de informaci on que se puede considerar ligada a los objetos que se van descubriendo en el programa: variables, constantes, funciones, etc. El acceso a esta informaci on se realiza mediante los nombres de estos objetos. Esto hace necesario tener alguna manera de, a partir de un identicador, encontrar sus propiedades. La estructura de datos que guarda esta informaci on se denomina tabla de s mbolos y puede interactuar con pr acticamente todas las fases de la compilaci on. Algunos ejemplos de la informaci on guardada son:
c Universitat Jaume I 2008-2009

II26 Procesadores de lenguaje

Constantes: tipo, valor. Variables: tipo, direcci on en memoria, tama no. Funciones: n umero y tipo de los argumentos, tipo devuelto, direcci on. Es importante tener en cuenta que la informaci on asociada con un identicador puede variar a lo largo del programa. As , por ejemplo, el identicador i se reere a dos variables distintas en el siguiente c odigo:
int main() { int i=1; { float i=2.0; printf("%f\n", i); /* i es un float */ } printf("%d\n", i); /* i es un int */ }

Una cuesti on de gran importancia ser a encontrar una estructura de datos eciente para acceder a los elementos de la tabla. 2.3.2. Gesti on de errores

Es un hecho que al programar se cometen errores. Es m as, se puede decir casi con total seguridad que un compilador encuentra m as programas err oneos que correctos. As pues, es importante que el compilador ayude en la detecci on y correcci on de errores. Para ello, el compilador debe, ante un error: Diagnosticarlo de la manera m as clara posible. Detener la generaci on de c odigo. Intentar recuperarse para poder continuar el an alisis. Veremos que, en general, no es posible detectar los errores, s olo sus s ntomas. Por ejemplo, ante la entrada a:= b 1; no es posible saber si falta un + entre la b y el 1 o si sobra un espacio o si sobra el uno. . . Sin embargo, ser a posible asegurar que la presencia de un error ha sido detectada lo antes posible; en nuestro ejemplo, detectaremos el error al ver el 1.

2.4.

M odulos externos al compilador

Aunque con lo que hemos visto hasta ahora podr amos considerar que tenemos el compilador completo, hay otros m odulos que tambi en se utilizan en el proceso de construcci on de programas y que en muchos casos son programas independientes invocados por el propio compilador. Comentaremos brevemente tres: el preprocesador, en enlazador y el soporte en ejecuci on. 2.4.1. El preprocesador

En algunos lenguajes (probablemente el m as conocido es C), existe una fase anterior al an alisis l exico: el preproceso. En esta fase se realizan acciones tales como expansi on de macros o inclusi on de cheros. Es interesante darse cuenta de que el preprocesador se comporta como un compilador muy restringido en sus capacidades y que tiene sus propias fases de an alisis y s ntesis. 2.4.2. El enlazador

En muchos casos, el resultado de la compilaci on no es un programa completo sino una parte de el: un chero objeto. Una vez se han compilado todas las partes del programa, hay que unirlas, probablemente tambi en empleando alguna biblioteca, para crear el programa nal. El programa encargado de esto es el enlazador (linker en ingl es).

Estructura de los compiladores e int erpretes

2.4.3.

Soporte en ejecuci on

Adem as de las acciones especicadas por el programador, el c odigo nal tiene que hacer una serie de acciones necesarias para el buen funcionamiento del programa. La parte a nadida al programa para hacer esto es lo que se conoce como soporte en ejecuci on. Algunas de sus funciones son preparar la memoria al comienzo de la ejecuci on, gestionar la memoria o la pila durante la ejecuci on y preparar la nalizaci on de la ejecuci on de una manera razonable. Seg un los casos, este c odigo puede estar contenido en funciones de la biblioteca est andar del lenguaje, puede ser a nadido al programa o generado autom aticamente.

3.

La interpretaci on

Mientras que el objetivo de los compiladores es obtener una traducci on del programa fuente a otro lenguaje, los int erpretes tienen como objeto la obtenci on de los resultados del programa. Para ello deben realizar dos tareas: analizar su entrada y llevar a cabo las acciones especicadas por ella. La parte de an alisis puede realizarse de manera id entica a como se lleva a cabo en los compiladores. Es la parte de s ntesis la que se diferencia sustancialmente. En el caso de la interpretaci on, se parte del arbol de sintaxis abstracta y se recorre, junto con los datos de entrada, para obtener los resultados. En el caso del arbol asignaci on

idvalor suma idvalor idinc El recorrido consistir a en: Analizar el nodo asignaci on. Visitar su hijo derecho (la suma) para obtener el valor que hay que asignar: Visitar el hijo izquierdo de la suma, recuperar el valor actual de valor. Visitar el hijo derecho de la suma, recuperar el valor actual de inc. Hacer la suma. Guardar el resultado de la suma en valor. Actualmente es habitual encontrar h bridos entre la compilaci on y la interpretaci on que consisten en compilar a un lenguaje intermedio para una m aquina virtual y despu es interpretar este lenguaje. Esta aproximaci on es la que se sigue, por ejemplo, en Java, Python o la plataforma .NET.

4.

La arquitectura real de compiladores e int erpretes

Siguiendo la descripci on de las fases hecha m as arriba, vemos que la estructura de un compilador es similar a la siguiente:
c Universitat Jaume I 2008-2009

II26 Procesadores de lenguaje

Programa fuente An alisis An alisis l exico An alisis sint actico An alisis sem antico

Arbol de sintaxis abstracta S ntesis Generaci on de c odigo intermedio Optimizaci on de c odigo intermedio Generaci on de c odigo objeto Optimizaci on de c odigo objeto

Programa objeto

De manera an aloga, un int erprete tendr a esta estructura:


Programa fuente An alisis An alisis l exico An alisis sint actico An alisis sem antico

Arbol de sintaxis abstracta S ntesis Generaci on de resultados

Resultados

O, si utiliz aramos una m aquina virtual, el int erprete tendr a esta estructura:
Programa fuente An alisis An alisis l exico An alisis sint actico An alisis sem antico

Arbol de sintaxis abstracta S ntesis Generaci on de c odigo intermedio Optimizaci on de c odigo intermedio

C odigo intermedio

Int erprete de m aquina virtual

Resultados

Estructura de los compiladores e int erpretes

Sin embargo, en la pr actica, la separaci on entre las distintas fases no est a tan marcada. Lo habitual es que el analizador sint actico haga las veces de maestro de ceremonias, pidiendo al analizador l exico los componentos l exicos a medida que los va necesitando y pasando al analizador sem antico la informaci on que va obteniendo. De hecho, lo m as normal es que este u ltimo (el analizador sem antico) no exista como un m odulo separado sino que est e integrado en el sint actico. As se elimina la necesidad de crear un arbol de an alisis. Esta organizaci on suele llamarse traducci on dirigida por la sintaxis. Si la memoria disponible es escasa, puede resultar imposible mantener una representaci on de todo el programa. En estos casos, se unen las fases de an alisis y de s ntesis. De esta manera, se va generando c odigo al mismo tiempo que se analiza el programa fuente. Esta forma de trabajar era habitual en compiladores m as antiguos y exige ciertas caracter sticas especiales al lenguaje, como las declaraciones forward de Pascal.

5.

Resumen del tema


Dos etapas en la traducci on: an alisis y s ntesis. An alisis: L exico: de caracteres a componentes. Sint actico: de componentes a arboles de an alisis. Sem antico: de arboles de an alisis a AST. S ntesis: En compilaci on: Generaci on de c odigo intermedio. Generaci on de c odigo objeto. Optimizaci on (mezclada con las anteriores). En interpretaci on, dos opciones: Generaci on directa de resultados. Generaci on de c odigo intermedio e interpretaci on del c odigo intermedio.

c Universitat Jaume I 2008-2009

You might also like