anexosi ii iii

Upload: espinoza-diaz-andrea

Post on 10-Oct-2015

45 views

Category:

Documents


3 download

TRANSCRIPT

  • - 1 -

    COMPILADORES

    MENSAJE DEERROR

    PROGRAMAOBJETO

    PROGRAMAFUENTE

    COMPILADOR

    Fig. 1.1 Un compilador

    Un compilador es un programa que lee un programa escrito en un lenguaje, el lenguaje fuente, y lo traduce a un programa equivalente a otro lenguaje, el lenguaje objeto. Como parte importante de este proceso de traduccin, el compilador informa a su usuario de la presencia de errores en el programa fuente. Hay miles de lenguajes fuentes, desde los lenguajes de programacin tradicionales, como ser FORTRAN o Pascal, hasta los lenguajes especializados como han surgido virtualmente en todas las reas de aplicacin de la informtica. Los lenguajes objetos son igualmente variados: un lenguaje objeto puede ser otro lenguaje de programacin o el lenguaje de maquina de cualquier computador entre un microprocesador y un supercomputador. Los computadores a menudo se clasifican como de una pasada de mltiple pasadas, de carga y ejecucin, de depuracin o de optimizacin, dependiendo de como hayan sido construidos o de que funcin se supone que realizan. A pesar de esta aparente complejidad, las tareas bsicas que debe realizar cualquier compilador son esencialmente las mismas. Al comprender tales tareas, se pueden construir compiladores para una gran diversidad de lenguajes fuente y maquinas objeto utilizando las mismas tcnicas bsicas. Gran parte de los primeros trabajos de compilacin estaba relacionada con la traduccin de frmulas aritmticas a cdigo de mquina. En la dcada de 1.950, se considero a los compiladores como programas notablemente difciles de escribir. El primer compilador de FORTRAN, por ejemplo necesito para su implementacin 18 aos de trabajo en grupo. Desde entonces se han descubierto tcnicas sistemticas para manejar muchas de las importantes tareas que surgen en la compilacin. Tambin se han desarrollado buenos lenguajes de implementacin, entornos de programacin y herramientas de software.

    Modelo de anlisis y sntesis de la compilacin En la compilacin hay dos partes : anlisis y sntesis. La parte del anlisis divide al programa fuente en sus elementos componentes y crea una representacin intermedia del programa fuente. La parte de la sntesis constituye el programa objeto deseado a partir de la representacin intermedia.

  • - 2 -

    Durante el anlisis, se determinan las operaciones que implica el programa fuente y se registran en una estructura jerrquica llamada rbol. A menudo, se usa una clase especial de rbol llamado rbol sintctico, donde cada nodo representa una operacin y los hijos de un nodo son los argumentos de la operacin

    rbol sintctico para una proposicin de asignacin

    posicin

    inicial

    velocidad 60

    *

    +

    : =

    posicin : = inicial + velocidad * 60

    Fig. 1.2 Muchas herramientas que manipulan programas fuentes realizan primero algn tipo de anlisis. Algunos ejemplos de tales herramientas son : 1) Editores de estructuras : un editor de estructuras toma como entrada una secuencia de ordenes para construir un programa fuente. El editor de estructura no solo realiza las funciones de creacin y modificacin de textos de un editor de textos ordinario, sino que tambin analiza el texto del programa, imponiendo al programa fuente una estructura jerarquica apropiada. De esta manera, el editor de estructuras puede realizar tareas adicionales tiles para la preparacin de programas. Por ejemplo, puede comprobar si la entrada esta formada correctamente, puede proporcionar palabras clave de manera automtica ( por ejemplo cuando el usuario escribe while, el editor proporciona el correspondiente do y le recuerda al usuario que entre las dos palabras debe ir un condicional ) y puede saltar desde un begin o un parntesis izquierdo hasta su correspondiente end o parntesis derecho. Ademas, la salida de tal editor suele ser similar a la salida de la fase de anlisis de un compilador. 2) Impresoras estticas : una impresora esttica analiza un programa y lo imprime de forma que la estructura del programa resulte claramente visible ( por ejemplo, los comentarios pueden aparecer con un tipo de letra especial, y las proposiciones pueden aparecer con una identacin proporcional a la profundidad de su anidamiento en la organizacin jerrquica de las proposiciones. 3) Verificadores estticos : un verificador esttico lee un programa, lo analiza e intenta descubrir errores potenciales sin ejecutar el programa. As, un verificador esttico puede detectar si hay partes de un programa que nunca se podrn ejecutar o si cierta variable se usa antes de ser

  • - 3 -

    definida. Ademas, puede detectar errores de lgica, como intentar usar una variable real como apuntador. 4) Interpretes : un interprete realiza las operaciones que implica el programa fuente. Para una proposicin de asignacin, por ejemplo, un interprete podra construir un rbol ( como el de asignacin Fig. 1.2 ) y despus efectuar las operaciones de los nodos conforme "recorre" el rbol . En la raz descubrir que tiene que realizar una asignacin, y llamara a una rutina para evaluar la expresin de la derecha y despus almacenara el valor resultante en la localidad de memoria asociada con el identificador posicin. En el hijo derecho de la raz, la rutina descubrira que tiene que calcular la suma de dos expresiones. Se llamara a si misma de manera recursiva para calcular el valor de la expresin velocidad * 60. Despus sumaria ese valor al valor de la variable inicial. Algunos lenguajes de " muy alto nivel", como APL, normalmente son interpretados porque hay muchas cosas sobre los datos, como el tamao y la forma de las matrices, que no se pueden deducir en el momento de la compilacin.

    El contexto de un compilador

    Ademas de un compilador, se pueden necesitar otros programas para crear un programa objeto ejecutable. Un programa fuente se puede dividir en mdulos almacenados en archivos distintos. La tarea de reunir el programa fuente a menudo se confia a un programa distinto, llamado procesador. El preprocesador tambin puede abreviaturas, llamadas macro o preposiciones del lenguaje fuente.

  • - 4 -

    BIBLIOTECA, ARCHIVOOBJETO RELOCALIZAB

    CODIGO DE MAQUINA ABSOLUTO

    EDITOR DE CARGA YENLACE

    CODIGO DE MAQUINA RELOCALIZABLE

    ENSAMBLADOR

    PROGRAMA OBJETO EN LENGUAJE ENSAMBLADOR

    COMPILADOR

    PROGRAMA FUENTE

    PREPROCESADOR

    ESTRUCTURA DEL PROGRAMA FUENTE

    Fig. 1.3 Sistema para procesamiento de un lenguaje

    La figura 1.3 muestra una compilacin tpica: el programa objeto creado por el compilador puede requerir procesamiento adicional antes de poder ejecutar. El compilador de la figura 1.3 crea cdigo en el lenguaje ensamblador el cual es traducido por un ensamblador a cdigo de mquina

  • - 5 -

    y despus se enlaza a algunas rutinas de biblioteca para producir el cdigo que realmente se ejecuta en la mquina.

    Anlisis del programa fuente El anlisis consta de tres fases : 1) Anlisis inicial : en el que la cadena de caracteres que constituye el programa fuente se lee de izquierda a derecha y se agrupa en componentes lxicos, que son secuencias de caracteres que tienen un significado colectivo 2) Anlisis jerrquico : en el que los caracteres o los componentes lxicos se agrupan jerrquicamente en colecciones anidadas con un significado colectivo. 3) Anlisis semntico : en el que se realizan ciertas revisiones para asegurar que los componentes de un programa se ejecuten de un modo significativo.

    Anlisis lxico o anlisis lineal

    En un compilador, el anlisis lineal se llama anlisis lxico o exploracin. Por ejemplo, en el anlisis lxico los caracteres de la proposicin de asignacin posicin := inicial + velocidad * 60 Se agrupan en los componentes lxicos siguientes : 1. El identificador posicin. 2. El smbolo de asignacin : = . 3. El identificador inicial. 4. El signo de suma. 5. El identificador velocidad. 6. El signo de multiplicacin. 7. El nmero 60. Los espacios en blanco que separan los caracteres de estos componentes lxicos normalmente se eliminan durante el anlisis lxico.

    Anlisis sintctico

    El anlisis jerrquico se denomina anlisis sintctico. Este implica agrupar los componentes lxicos del programa fuente en frases gramaticales que el compilador utiliza para sintetizar la salida. Por lo general, las frases gramaticales del programa fuente se representan mediante un rbol de anlisis sintctico como el que se ilustra en la figura 1.4.

  • - 6 -

    60

    numero

    expresion*

    velocidad

    identificador

    expresion

    inicial

    identificador

    +posicion

    identificador : =

    expresion expresion

    expresion

    proposicin deasignacion

    Fig. 1.4 Arbol de analisis sintactico

    para posicin : = inicial + velocidad * 60 Explicacion de la fig. 1.4 : En la expresin inicial + velocidad * 60, la frase velocidad * 60 es una unidad lgica, porque las convenciones usuales de las expresiones aritmticas indican que la multiplicacin se hace antes que la suma. Puesto que la expresin inicial + velocidad va seguida de un *, no se agrupa en una sola frase independiente en la figura 1.4. La estructura jerarquica de un programa normalmente se expresa utilizando reglas recursivas. Por ejemplo: se pueden dar las siguientes reglas como parte de la definicin de expresiones: 1. Cualquier identificador es una expresin. 2. Cualquier numero es una expresin. 3. Si expresin1 y expresin2 son expresiones, entonces tambin lo son expresin1 + expresin2 expresin1 * expresin2 ( expresin1 ) Las reglas (1) y (2) son reglas bsicas ( no recursivas ), en tanto que la regla (3) define expresiones en funcin de operadores aplicados a otras expresiones. As, por la regla (1), inicial y velocidad son expresiones. Por la regla (2), 60 es una expresin, mientras que por la regla (3), primero podemos inferir que la velocidad * 60 es una expresin, y finalmente, que inicial + velocidad * 60 tambin es una expresin.

  • - 7 -

    De manera similar, muchos lenguajes definen recursivamente las proposiciones mediante reglas como: 1. Si identificador1 es un identificador y expresin2 es una expresin, entonces identificador1 : = expresin2 es una proposicion. 2. Si expresin1 es una expresin y proposicin2 es una proposicin, entonces while ( expresin1 ) do proposicin2 if ( expresin1 ) then proposicin2 son proposiciones. La divisin entre anlisis lxico y anlisis sintctico es algo arbitraria. Generalmente se elige una divisin que simplifique la tarea completa del anlisis. Un factor para determinar la divisin es si una construccin del lenguaje fuente es inherentemente recursiva o no. Las construcciones lxicas no requieren recursin, mientras que la construcciones sintcticas suelen requerirla ( Las gramticas independientes del contexto son una formalizacin de reglas recursivas que se pueden usar para guiar el anlisis sintctico). Por ejemplo, no se requiere recursin para reconocer los identificadores, que suelen ser cadenas de letras y dgitos que comienzan con una letra. Normalmente, se reconocen los identificadores por el simple exmen del flujo de entrada, esperando hasta encontrar un caracter que no sea ni letra ni dgito, y agrupando despus todas las letras y dgitos encontrados hasta ese punto en un componente lxico identificador. Los caracteres as agrupados se registran en una tabla, llamada tabla de smbolos, y se retiran de la entrada, para que pueda empezar el procesamiento del siguiente elemento lxico. Por otra parte, esta clase de anlisis lxico lineal no es suficientemente poderoso para analizar expresiones o proposiciones. Por ejemplo, no podemos emparejar de manera apropiada los parntesis de las expresiones, o las palabras begin y end en proposiciones sin imponer alguna clase de estructura jerrquica o de anidamiento a la entrada. \ se usa : El rbol de anlisis sintctico de la figura describe la estructura sintctica de la entrada.

    posicin

    inicial

    velocidad 60

    *

    +

    : =

    60

    posicin

    inicial

    velocidad entareal

    *

    +

    : =

    (a) (b)

  • - 8 -

    Fig. 1.5 El analisis semantico inserta una conversion de entero a real

    Anlisis semntico La fase de anlisis semntico revisa el programa fuente para tratar de encontrar errores semnticos y rene la informacin sobre los tipos para la fase posterior de generacin de cdigo. En ella se utiliza la estructura jerarquica determinada por la fase de anlisis sintctico para identificar los operadores y operandos de expresiones y proposiciones. Un componente importante del anlisis semntico es la verificacin de tipos. Aqu, el compilador verifica si cada operador tiene operadores permitidos por la especificacin del lenguaje fuente. Por ejemplo, las definiciones de muchos lenguajes de programacin requieren que el compilador indique un error cada vez que se use un nmero real como ndice de una matriz. Sin embargo las especificaciones del lenguaje pueden permitir ciertas coerciones a los operandos, por ejemplo, cuando un operador aritmtico binario se aplica a un numero real. En este caso, el compilador puede necesitar convertir el numero entero a real. Ejemplo 1.1. Por ejemplo, supongamos que todos los identificadores de la figura 1.5 se han declarado reales y que tan solo 60 se supone entero. La verificacin de tipos de la figura 1.5 ( a ) revela que * se aplica a un real, velocidad, y a un entero, 60. El tratamiento general es convertir el entero a real. Esto se ha logrado en la figura 15 (b) creando un nodo extra para el operador entareal que de manera explcita convierte un entero a real. Por otra parte, como el operando de entareal es una constante, el compilador podra reemplazar la constante entera por una constante real equivalente

    Anlisis en formadores de textos

    Es til considerar que la entrada de un formador de textos especifica una jerarqua de cajas, regiones rectangulares que se van a llenar con algn patrn de bits, representando pixeles claros y oscuros para ser impresos por el dispositivo de salida. Por ejemplo, el sistema TEX considera su entrada de esta manera. Cada caracter que no sea parte de una orden representa una caja que contiene el patrn de bits de ese caracter con el tipo y tamao apropiados. Los carcteres consecutivos no separados por " espacios en blanco " se agrupan en palabras, que consisten en una secuencia de cajas dispuestas horizontalmente, mostradas en la figura 1.6 . El agrupamiento de caracteres en palabras es el aspecto linel o lxico del anlisis en un formador de textos.

    sarbalapsod

    Fig. 1.6 Agrupamiento de caracteres y palabras en cajas

  • - 9 -

    La caja TEX se puede construir a partir de cajas mas pequeas en combinaciones arbitrarias horizontales y verticales. Por ejemplo, \hbox{ } Agrupa la lista de cajas yuxtaponindolas horizontalmente, mientras que el operador \ybox agrupa de manera similar una lista de cajas por yuxtaposicin vertical. As si se indica en TEX \hbox{\vbox{! 1} \vbox{@ 2}} Se obtiene la disposicin de cajas que se muestra en la siguiente figura 1.7. Determinar la disposicin jerarquica de las cajas implicadas en las entradas es parte del anlisis sintctico en TEX

    21

    @!

    Fig. 1.7 Jerarquia de cajas en TEX Como otro ejemplo, el preprocesador EQN para matemticas, o el procesador matemtico de TEX, constituye expresiones matemticas a partir de operadores como sub y sup para subndices y superndices. Si EQN encuentra un texto de entrada de la forma CAJA sub caja Reduce el tamao de caja y la une a CAJA cerca de la esquina inferior derecha, como se ilustra en la figura 1.8. De manera similar, el operador ssup une caja a la esquina superior derecha.

    cajaCAJA

    Fig. 1.8 Construccin de la estructura de subindice en texto matematico Estos operadores se pueden aplicar recursivamente, as que por ejemplo, el texto en EQN a sub {i sup 2} Da como resultado ai 2. Agrupar los operadores sub y sup en componentes lxico es parte del anlisis lxico del texto en EQN. Sin embargo se necesita la estructura sintctica del texto para determinar el tamao y la posicin de las cajas.

  • - 10 -

    LAS FASES DE UN COMPILADOR Conceptualmente, un compilador opera en fases, cada una de las cuales transforma al programa fuente de una representacin en otra. En la practica se pueden agrupar algunas fases, y las representaciones intermedias entre las fases agrupadas no necesitan ser construidas explcitamente

    ADMINISTRADOR DE LATABLA DE SIMBOLOS

    MANEJADOR DEERRORES

    PROGRAMA OBJETO

    GENERADOR DECODIGO

    OPTIMADOR DECODIGO

    GENERADOR DECODIGO INTERMEDIO

    ANALIZADORSEMANTICO

    ANALIZADORSINTACTICO

    ANALIZADORLEXICO

    PROGRAMA FUENTE

  • - 11 -

    Fig. 1.9 Fases de un compilador Las tres primeras fases, que conforman la mayor parte de la porcin de anlisis de un compilador, se describieron anteriormente. La administracin de la tabla de smbolos y el manejo de errores, se muestran en interaccin con las seis fases de anlisis lxico, anlisis sintctico, anlisis semntico, generacin de cdigo intermedio, optimizacin de cdigo y generacin de cdigo. De modo informal, tambin se llaman "fases" al administrador de la tabla de smbolos y al manejador de errores.

    Administrador de la tabla de smbolos Una funcin escencial de un compilador es registrar los identificadores utilizados en el programa fuente y reunir la informacin sobre los distintos atributos de cada identificador. Estos atributos pueden proporcionar informacin sobre la memoria asignada a un identificador, su tipo, su mbito ( la parte del programa donde tiene validez ) y, en el caso de nombres de procedimientos, cosas como el nombre y tipos de sus argumentos, el mtodo de pasar de cada argumento ( por ejemplo, por referencia ) y el tipo que devuelve, si lo hay. Una tabla de smbolos es una estructura de datos que contiene un registro por cada identificador, con los campos para los atributos del identificador. La estructura de datos permite encontrar rpidamente el registro de cada identificador y almacenar o consultar rpidamente datos de ese registro. Cuando el analizador lxico detecta un identificador en el programa fuente, el identificador se introduce en la tabla de smbolos. Sin embargo, normalmente los atributos de un identificador no se pueden determinar durante el anlisis lxico. Por ejemplo, en una declaracin en Pascal como var posicin, inicial, velocidad : real ; el tipo real no se conoce cuando el analizador lxico encuentra posicin, inicial, y velocidad. Las fases restantes introducen informacin sobre los identificadores en la tabla de smbolos y despus la utiliza de varias formas. Por ejemplo, cuando se esta haciendo el anlisis semntico y la generacin de cdigos intermedios, se necesita saber cuales son los tipos de los identificadores, para poder comprobar si el programa fuente los usa de una forma valida y as poder generar las operaciones apropiadas con ellos. El generador de cdigo, por lo general, introduce y utiliza informacin detallada sobre la memoria asignada a los identificadores.

    Deteccin e informacin de errores

    Cada fase puede encontrar errores. Sin embargo, despus de detectar un error, cada fase debe tratar de alguna forma ese error, para poder continuar la compilacin, permitiendo la deteccin de mas errores en el programa fuente. Las fases de anlisis sintctico y semntico por lo general manejan una gran porcin de los errores detectables por el compilador. La fase lxica puede detectar errores donde los caracteres restantes de la entrada no forman ningn componente lxico del lenguaje. Los errores

  • - 12 -

    donde la cadena de componentes lxicos violan las reglas de estructura (sintaxis) del lenguaje son determinados por la fase de anlisis sintctico. Durante el anlisis semntico el compilador intenta detectar construcciones que tengan la estructura sintctica correcta, pero que no tengan significado para la operacin implicada, por ejemplo, si se intenta sumar dos identificadores, uno de los cuales es el nombre de una matriz, y el otro, el nombre de un procedimiento.

    Las fases de anlisis Conforme avanza la traduccin, la representacin interna del programa fuente que tiene el compilador se modifica. Para ilustrar esas representaciones, considrese la traduccin de la proposicin posicin : = inicial + velocidad * 60 ( 1.1 ) La figura 1.10 muestra la representacion de esta proposicion despues de cada fase. La fase de anlisis lxico lee los caracteres en el programa fuente y los agrupa en una cadena de componentes lxicos en los que cada componente representa una secuencia lgicamente coherente de caracteres, como un identificador una palabra clave ( if, while, etc.), un caracter de puntuacin, o un operador de varios caracteres como : = . La secuencia de caracter que forma un componente lxico se denomina lexema del componente. A ciertos componentes lxicos se le agrega un " valor lxico ". As, cuando se encuentra un identificador como velocidad, el analizador lxico no solo genera un componente lxico, por ejemplo id, sino que tambin introduce el lexema velocidad en la tabla de smbolos, si no esta aun all. El valor lxico asociado con esta operacin de id seala la entrada de la tabla de smbolos correspondiente a velocidad. Por lo tanto usaremos, id1, id2 e id3 para posicin, inicial, velocidad, respectivamente, para enfatizar que la representacin interna de un identificador es diferente de la secuencia de caracteres que forman el identificador. Por lo tanto la representacin de ( 1.1 ) despus del anlisis lxico queda sugerida por : id1 : = id2 + id3 * 60 ( 1.2 ) El anlisis sintctico impone una estructura jerarquica a la cadena de componentes lxicos, que se representan por medio de arboles sintcticos ,como se muestra en la figura 1.11 ( b ), en la que un nodo interior es un registro con un campo para el operador y dos campos que contienen apuntadores a los registros hijos izquierdo y derecho. Una hoja es un registro con dos o mas campos, uno para identificar al componente lxico de la hoja, y los otros para registrar informacin sobre el componente lxico. Se puede tener informacin adicional sobre las construcciones del lenguaje aadiendo mas campo a los registros de los nodos.

    Generacin de cdigo intermedio

  • - 13 -

    Fig. 1.10 Traduccion de una proposicion ( Pag. anterior )

    id1

    id2

    id3 60

    *

    +

    : =

    (a)

    60num

    2id

    3id

    *

    1id

    +

    +

    (b)

    Fig. 1.11 La estructura de datos en (b) corresponde al arbol en (a)

    Despus de los anlisis sintctico y semntico, algunos compiladores generan una representacin intermedia explcita del programa fuente. Se puede considerar esta representacin intermedia como un programa para una maquina abstracta. Esta representacin intermedia debe tener dos propiedades importantes; debe ser fcil de producir y fcil de traducir al programa objeto.

  • - 14 -

    La representacin intermedia puede tener diversas formas. El cdigo de tres direcciones consiste en una secuencia de instrucciones, cada una de las cuales tiene como mximo tres operandos. El programa fuente de ( 1.1 ) puede aparecer en cdigo de tres direcciones como temp1 : = entareal (60) temp2 : = id3 * temp1 (1.3) temp3 : = id2 + temp2 id1 : = temp3 Esta representacin intermedia tiene varias propiedades : 1) cada instruccin de tres direcciones tiene a lo sumo un operador, ademas de la asignacin. Por lo tanto, cuando se generan esas instrucciones, el compilador tiene que decidir el orden en que deben efectuarse las operaciones: la multiplicacion precede a la adicion en el programa fuente de ( 1.1 ). 2) El compilador debe generar un nombre temporal para guardar los valores calculados por la instruccin. 3) Algunas instrucciones de "tres direcciones" tienen menos de tres operadores, por ejemplo, la primera y la ultima instruccin.

    Optimizacin de cdigo La fase de optimizacin de cdigo trata de mejorar el cdigo intermedio, de modo que resulte un cdigo de maquina mas rpido de ejecutar. Ejemplo temp1 : = id3 * 60.0 (1.4) id1 : = id2 + temp1 Este sencillo algoritmo no tiene nada de malo, puesto que el problema se puede solucionar en la fase de optimizacin de cdigo. Esto es el compilador puede deducir que la conversin de 60 de entero a real se puede hacer de una vez por todas en el momento de la compilacin, de modo que la operacin entareal se puede eliminar. Ademas temp3 se usa una sola vez para transmitir su valor a id1. Entonces resulta seguro sustituir id1 por temp3, a partir de lo cual la ultima proposicion de ( 1.3 ) no se necesita y se obtiene el cdigo (1.4). Hay mucha variacin en la cantidad de optimizacin de cdigos que ejecutan los distintos compiladores. En los que hacen mucha optimizacin, llamados "compiladores optimadores" , una parte significativa del tiempo del compilador se ocupa en esta fase. Sin embargo, hay opciones sencillas que mejoran sensiblemente el tiempo de ejecucin del programa objeto sin retardar demasiado la compilacin.

    Generacin de cdigo La fase de un compilador es la generacin de cdigo objeto, que por lo general consiste en cdigo de maquina relocalizable o cdigo ensamblador. Las posiciones de memoria se seleccionan para cada una de las variables usadas por el programa.

  • - 15 -

    Despus, cada una de las instrucciones intermedias se traduce a una secuencia de instrucciones de maquina que ejecuta la misma tarea. Por ejemplo: utilizado los registros 1 y 2, la traduccin del cdigo de (1.4) podra convertirse en : MOVF id3, R2 ( 1.5 ) MULF #60.0, R2 MOVF id2, R1 ADDF R2, R1 MOVF R1, id1 El primero y segundo operandos de cada instruccin especifican una fuente y un destino, respectivamente. La F de cada instruccin indica que las instrucciones trabajan con numeros de punto flotante. Este cdigo traslada el contenido de la direccin id3 al registro 2, despus lo multiplica por la constante real 60.0 . El signo # significa que 60.0 se trata como una constante. La tercera instruccin pasa id2 al registro1. La cuarta instruccin le suma el valor previamente calculado en el registro 2. Por ultimo, el valor del registro 1 se pasa a la direccin de id1, de modo que el cdigo aplica la asignacin de la fig 1.10.

    PROGRAMAS DE SISTEMAS RELACIONADOS CON UN COMPILADOR La entrada para un compilador puede producirse por uno o varios preprocesadores, y puede necesitarse otro procesamiento de la salida que produce el compilador antes de obtener un cdigo maquina ejecutable. En esta seccin se analiza el contexto en el que suele funcionar un compilador.

    Preprocesadores Los preprocesadores producen la entrada para un compilador, y pueden realizar las funciones siguientes: 1) Procesamiento de macros : Un preprocesador puede permitir a un usuario definir macros que son abreviaturas de construcciones ms grandes. 2) Inclusin de archivos : Un preprocesador puede insertar archivos de encabezamiento en el texto del programa. Por ejemplo, el preprocesador de C hace que el contenido del archivo < globa1.h > reemplace a la proposicin # include < globa1.h > cuando procesa un archivo que contenga a esa proposicin. 3) Preprocesadores "racionales " : Estos preprocesadores enriquecen los lenguajes antiguos con recursos ms modernos de flujo de control y de estructuras de datos. Por ejemplo, un preprocesador de este tipo podra proporcionar al usuario macros incorporadas para construcciones, como proposiciones while o if, en un lenguaje de programacin que no las tenga. 4) Extensin a lenguajes : Estos procesadores tratan de crear posibilidades al lenguaje que equivalen a macros incorporadas. Por ejemplo, el lenguaje Equel es un lenguaje de consulta de base de datos integrado en C. El preprocesador considera las preposiciones que empiezan con # # como proposiciones de acceso a la base de datos, sin relacin con C, y se traduce a llamadas de procesamiento a rutinas que realizan el acceso a la base de datos.

  • - 16 -

    Los procesadores de macro tratan dos clase de proposiciones: definicin de macros y uso de macros. Las definiciones normalmente se indican con algn caracter exclusivo o palabra clave, como define o macro. Constan de un nombre para la macro que se esta definiendo y de un cuerpo, que constituye su definicin. A menudo, los procesadores de macros admiten parmetros formales en su definicin, esto es, smbolos que se reemplazan por valores ( en este contexto, un " valor " es una cadena de caracteres ). El uso de una macro consiste en dar nombre a la macro y proporcionar parmetros reales, es decir, valores para sus parmetros formales. El procesador de macro sustituye los parmetros reales por los parmetros formales del cuerpo de la macro; despus, el cuerpo transformado reemplaza el uso de la propia macro. Ejemplo 1.2 : El sistema de composicin tipogrfica TEX mencionado anteriormente, contiene un recurso de macro general. Las definiciones de macros son de la forma \define {} El nombre de una macro es cualquier cadena de letras precedida por una diagonal invertida. La plantilla es cualquier cadena de caracteres en donde las cadenas de la forma #1, #2,...,#9 se consideran parmetros formales. Estos smbolos, tambin pueden aparecer en el cuerpo las veces que se quiera. Por ejemplo, la siguiente macro define una cita del Journa of the ACM. \define\JACM # 1; # 2 ; # 3 . {{\ s1 J. ACM} {\bf # 1}: # 2 , pags. # 3 .} El nombre de la macro es JACM, y la planilla es " # 1; # 2 ; # 3 ." '; los smbolos de punto y coma separan los parmetros y despus del ultimo parmetro se pone un punto. Un uso de esta macro debe tomar la forma de la plantilla, excepto que se puede sustituir cadenas arbitrarias por los parmetros formales(*). As, se puede escribir \JACM 17; 4; 715 - 728. y se espera que aparezca J. ACM 17:4, pags. 715-728. La parte del cuerpo {\s1 J. ACM} pide "J. ACM" en cursiva (si es por slantedd. "inclinado" en ingles). La expresin{bf # 1} indica que el primer parmetro real se escribir en negritas (bf es por boldface, "negrita" en ingles); este parmetro es el numero de volumen. TEX admite cualquier puntuacin o cadena de texto para separar el volumen, el nmero del ejemplar y los nmeros de pgina de la definicin de la macro \ JACM. Incluso se podra haber prescindido totalmente de la puntuacin, en cuyo caso TEX tomara cada parmetro real como un solo caracter o una cadena encerrada entre { } (*) Bueno, cadena casi arbitrarias, puesto que solo se hace un simple anlisis lxico de izquierda a derecha del uso de la macro, y tan pronto como se encuentre un smbolo que concuerde con el texto que sigue a un smbolo # i de la plantilla, se considera que la cadena precedente concuerda con # i. Por tanto, si se intenta sustituir ab; cd por # 1, resultara que solo ab concuerda con # 1 y que cd concuerda con # 2.

    Ensambladores Algunos compiladores producen cdigo ensamblador , como en el caso ( 1.5 ), que se pasa , a un ensamblador para su procesamiento. Otros compiladores realizan el trabajo del

  • - 17 -

    ensamblador produciendo cdigo mquina relocalizable que se puede pasar directamente al editor de carga y enlace. Se supone que el lector tiene cierta familiaridad sobre como es un lenguaje ensamblador y que hace el ensamblador, aqu se revisara la relacin entre el cdigo ensamblador y el cdigo de mquina. El cdigo ensamblador es una versin mnemotcnica del cdigo de mquina, donde se usan nombres en lugar del cdigos binarios para operaciones, y tambin se usan nombres para las direcciones de memoria. Una secuencia tpica de instrucciones en ensamblador puede ser MOV a, R1 ADD # 2, R1 (1.6) MOV R1, b Este cdigo pasa el contenido de la direccin a al registro 1; despus le suma la constante 2, tratando el contenido del registro 1 como un numero de punto fijo, y por ltimo almacena el resultado en la posicin de memoria que presenta b. De ese modo calcula b: = a + 2. Es comn que los lenguajes ensambladores tengan recursos para macros que son similares a las consideradas antes para los procesadores de macros.

    Ensambladores de dos pasadas

    La forma mas simple de un ensamblador hace dos pasadas sobre la entrada, en donde una pasada consiste en leer una vez un archivo de entrada. En la primera pasada, se encuentran todos los identificadores que denotan posiciones de memoria y se almacenan en una tabla de smbolos ( distinta de la del compilador). Cuando se encuentran por primera vez los identificadores, se les asigna posiciones de memoria, de modo que despus de leer (1.6), por ejemplo la tabla de smbolos contendra las entradas que aparecen en la figura 1.12. En esa figura, se supone que se reserva una palabra, que consta de cuatro byte, para cada identificador, y que las direcciones se asignan empezando a partir del byte 0.

    Figura 1.12. Tabla de smbolos de un ensamblador con los identificadores de (1.6)

    IDENTIFICADOR

    DIRECCIN

    a 0 b 4

    En la segunda pasada, el ensamblador examina el archivo de entrada de nuevo. Esta vez traduce cada cdigo de operacin a la secuencia de bits que representa esa operacin en lenguaje de mquina, y traduce cada identificador que representa una posicin de memoria a la direccin dada por ese identificador en la tabla de smbolos. El resultado de la segunda pasada normalmente es cdigo de mquina relocalizable, lo cual significa que puede cargarse empezando en cualquier posicin L de la memoria; es decir, si la suma L a todas las direcciones del cdigo, entonces todas las referencias sern correctas. Por tanto, la salida del ensamblador debe distinguir aquellas partes de intrucciones que se refieren a direcciones que se pueden realizar. Ejemplo 1.3 :

  • - 18 -

    El siguiente es un cdigo de mquina hipottico al que se pueden traducir las instrucciones en ensamblador (1.6). 0001 01 00 00000000 * 0011 01 10 00000010 (1.7) 0010 01 00 00000100 * Se concibe una pequea palabra de instruccin, en la que los cuatro primeros bits son el cdigo de la instruccin, donde 0001,0010 y 0011 representan las instrucciones LOAD, STORE y ADD, respectivamente. LOAD y STORE significan trasladar de memoria a un registro y viceversa. Los dos bits siguientes designan un registro y 01 se refiere al registro 1 de cada una de las tres instrucciones anteriores. Los dos bits siguientes representan un marcador, donde 00 es el modo de direccionamineto ordinario, y los ltimos ocho bits se refieren a una direccin de memoria. El marcador 10 es el modo " inmediato ", donde los ltimos ocho bits se toman literalmente como el operando. Este modo aparece en la segunda instruccin (1.7). En (1.7) tambin se ve un * asociado con la primera y la tercera instrucciones. Este * representa el bit de relocalizacin que se asocia con cada operando en cdigo de mquina relocalizable. Supngase que el espacio de direcciones que contiene los datos se va a cargar empezando en la posicin L. La presencia del * significa que se debe sumar L a la direccin de la instruccin. Por tanto, si L = 00001111, esto es, 15, entonces a y b estaran en la posicin 15 y 19, respectivamente, y las instrucciones de (1.7) apareceran como 0001 01 00 00001111 0011 01 10 00000010 (1.8) 0010 01 00 00000100 en cdigo de maquina absoluto o no relocalizable. Ntese que no hay ningn * asociado con la segunda instruccin de (1.7), de modo que L no se sumo a su direccin en (1.8), lo cual es correcto, porque los bits representan la constante 2 y no la posicin 2.

    Cargadores y editores de enlace Por lo general, un programa llamado cargador realiza las dos funciones de carga y edicin de enlaces. El proceso de carga consiste en tomar el cdigo de mquina relocalizable, modificar las direcciones relocalizables, como se indica en el ejemplo 1.3, y ubicar las instrucciones y los datos modificados en las posiciones apropiadas de la memoria. El editor de enlace permite formar un slo programa a partir de varios archivos de cdigo de mquina relocalizable. Estos archivos pueden haber sido el resultado de varias compilaciones distintas, y uno o varios de ellos pueden ser archivos de biblioteca de rutinas proporcionadas por el sistema y disponibles para cualquier programa que las necesite. Si los archivos se van a usar juntos de manera til, puede haber algunas referencias externas, en las que el cdigo de un archivo hace referencia a una posicin de otro archivo. Esta referencia puede ser a una posicion de datos definida en un archivo y utilizada en otro, o puede ser el punto de entrada de un procedimiento que aparece en el cdigo de un archivo y se llama desde otro. El archivo con el cdigo de mquina relocalizable debe conservar la informacin de la tabla de smbolos para cada posicin de datos o etiqueta de instruccin a la que hace referencia externamente. Si no se sabe por anticipado a qu se va a hacer referencia, es preciso incluir completa la tabla de smbolos del ensamblador como parte del cdigo de mquina relocalizable.

  • - 19 -

    Por ejemplo, el cdigo de (1.7) ira precedido de a 0 b 4 Si un archivo cargado con (1.7) hiciera referencia a b, entonces esa referencia se reemplazara por 4 ms el desplazamiento con el que se localizaron las posiciones del archivo (1.7).

    EL AGRUPAMIENTO DE LAS FASES El estudio de las fases, trata la organizacin lgica de un compilador. En una implantacin, a menudo se agrupan las actividades en dos o mas fases. Con frecuencia, las fases se agrupan en una etapa inicial y una etapa final. Etapa inicial : Comprende aquellas fases, o partes de fases, que dependen principalmente del lenguaje fuente y que son en gran parte independientes de la mquina objeto. Ah normalmente se incluyen los anlisis lxicos y sintcticos, la creacin de la tabla de smbolos, el anlisis semntico y la generacin de cdigo intermedio. La etapa inicial tambin puede hacer cierta optimizacin de cdigo. La etapa inicial incluye, ademas, el manejo de errores correspodiente a cada una de esas fases. Etapa final : Incluye aquellas partes del compilador que dependen de la mquina objeto y, en general, esas partes no dependen del lenguaje fuente, sino slo del lenguaje intermedio. En la etapa final se encuentran aspectos de la fase de optimizacin de cdigo, ademas de la generacin de cdigo, junto con el manejo de errores y las operaciones con la tabla de smbolos. Se ha convertido en rutina el tomar la etapa inicial de un compilador y rehacer su etapa final asociada para producir un compilador para el mismo lenguaje fuente en una mquina distinta. Si la etapa final se disea con cuidado, incluso puede no ser necesario redisearla demasiado. Tambin resulta tentador compilar varios lenguajes distintos en el mismo lenguaje intermedio y usar una etapa final comn para distintas etapas iniciales, obtenindose as varios compiladores para una mquina. Sin embargo, dadas las sutiles diferencias en los puntos de vista de los distintos lenguajes, slo se ha obtenido un xito limitado en ese aspecto. Pasadas : Normalmente se aplican varias fases de la compilacin en una sola pasada, que consiste en la lectura de un archivo de entrada y en la escritura de un archivo de salida. En la prctica hay muchas formas de agrupar en pasadas las fases de un compilador, as que es preferible organizar el anlisis de la compilacin por las fases, en lugar de por las pasadas. Es comn agrupar varias fases en una pasada, y entrelazar la actividad de estas fases durante la pasada. Por ejemplo, el anlisis lxico, el anlisis sintctico, el anlisis semntico y la generacin de cdigo intermedio pueden agruparse en una pasada. En ese caso, la cadena de componentes lxicos despus del anlisis lxico puede traducirse directamente a cdigo intermedio. Con mas detalle, el analizador sintctico puede considerarse como el " encargado " del control. Este obtiene los componentes lxicos cuando los necesita, llamando al analizador lxico para que le proporcione el siguiente componente lxico. A medida que se descubre la

  • - 20 -

    estructura gramatical, el analizador sintctico llama al generador de cdigo intermedio para que haga el anlisis semntico y genere una parte del cdigo.

    Reduccin del nmero de pasadas

    Es deseable tener relativamente pocas pasadas, dado que la lectura y escritura de archivos intermedios lleva tiempo. Adems si se agrupan varias fases dentro de una pasada, pueden ser necesarios tener que mantener el programa completo en memoria, porque una fase puede necesitar informacin en un orden distinto al que produce una fase previa. La forma interna del programa puede ser considerablemente mayor que el programa fuente o el programa objeto, de modo que este espacio no es un tema trivial. Para algunas fases, el agrupamiento en una pasada presenta pocos problemas. Por ejemplo, como se menciono antes, la interfaz entre los analizadores lxicos y sintcticos a menudo puede limitarse a un solo componente lxico. Por otra parte, muchas veces resulta muy difcil generar cdigo hasta que se haya generado por completo la representacin intermedia. Por ejemplo, los lenguajes como PL/I y ALGOL 68 permiten usar las variables antes de declararlas. No se puede generar el cdigo objeto para una construccin si no se conocen los tipos de las variables implicadas en esa construccin. De manera similar, la mayora de los lenguajes admiten construcciones goto que saltan hacia adelante en el cdigo. No se puede determinar la direccin objeto de dichos saltos hasta haber visto el cdigo fuente implicado y haber generado cdigo objeto para el. En algunos casos, es posible dejar un segmento en blanco para la informacin que falta, y llenar la ranura cuando la informacin esta disponible. En particular, la generacin de cdigo intermedio y de cdigo objeto a menudo se pueden fusionar en una sola pasada utilizando la llamada tcnica " relleno de retroceso " ( backpatching ). Recurdese que ya se analizo un ensamblador de dos pasadas, en el que la primera pasada descubra todos los identificadores que representaban posiciones de memoria y deduca sus direcciones al descubrirlas. Despus, en una segunda pasada sustitua las direcciones por identificadores. Se puede combinar la accin de las pasadas como sigue. Al encontrar una proposicin en ensamblador que sea una referencia hacia adelante, por ejemplo, GOTO destino Se genera la estructura de una instruccin, con el cdigo de operacin de mquina para GOTO y se dejan espacios en blanco para la direccin. Todas las instrucciones con espacio en blanco para la direccin de destino se guardan en una lista asociada con la entrada de destino en la tabla de smbolos. Los espacios se llenan cuando por fin se encuentran una instruccin como destino : MOV algo , R1 Y se determina el valor de destino; es la direccin de la instruccin en curso. Entonces se hace el relleno de retroceso, recorriendo la lista de destino de todas las instrucciones que necesitan su direccin, sustituyendo la direccin de destino en los espacios en blanco que aparecen en los campos de direccin de esas instrucciones. Este enfoque es fcil de implantar si las instrucciones se pueden guardar en memoria hasta que se hayan determinado todas las direcciones de destino. Este enfoque es razonable para un ensamblador que pueda guardar toda una salida en memoria. Como las representaciones intermedia y final del cdigo para un ensamblador son

  • - 21 -

    aproximadamente iguales, y con seguridad casi de la misma longitud, el relleno de retroceso en toda la longitud del programa ensamblador no es inviable. Sin embargo, en un compilador, con un cdigo intermedio que consuma mucho espacio, habr que tener cuidado con la distancia en que se hace el relleno de retroceso.

    HERRAMIENTAS PARA LA CONSTRUCCION DE COMPILADORES El escritor del compilador, como cualquier programador, puede usar con provecho herramientas de software tales como depuradores, administradores de versiones, analizadores, etc. Adems se han creado herramientas mas especializadas para ayudar a implantar varias fases de un compilador. Poco despus de escribirse el primer compilador, aparecieron sistemas para ayudar en el proceso de escritura de compiladores. A menudo se hace referencia a estos sistemas como compiladores de compiladores, generadores de compiladores o sistemas de generadores de traductores. En gran parte, se orientan en torno a un modelo particular de lenguaje, y son ms adecuados para generar compiladores de lenguajes similares al del modelo. Por ejemplo, es tentador suponer que los analizadores lxicos para todos los lenguajes son en esencia iguales, excepto por las palabras clave y signos particulares que se reconocen. Muchos compiladores de compiladores de hecho producen rutinas fijas de anlisis lxico para usar en el compilador generado. Estas rutinas solo difieren en la lista de palabras clave que reconocen, y esta lista es todo lo que debe proporcionar el usuario. El planteamiento es valido, pero puede no ser funcional si se requiere que reconozca componentes lxicos no estndar, como identificadores que pueden incluir ciertos caracteres distintos de letras y dgitos. Se han creado algunas herramientas generales para el diseo automtico de componentes especficos de compilador. Estas herramientas utilizan lenguajes especializados para especificar e implantar el componente, y puede utilizar algoritmos bastantes complejos. Las herramientas ms efectivas son las que ocultan los detalles del algoritmo de generacin y producen componentes que se pueden integrar con facilidad al resto del compilador. La siguiente es una lista de algunas herramientas tiles para la construccin de compiladores: 1) Generadores de analizadores sintcticos. Estos generadores producen analizadores sintcticos, normalmente a partir de una entrada fundamentada en una gramtica independiente del contexto. En los primeros compiladores, el anlisis sintctico consuma no slo gran parte del tiempo de ejecucin del compilador, sino gran parte del esfuerzo intelectual del escritor. Esta fase se considera ahora una de las mas fciles de aplicar. Muchos de los generadores de analizadores sintcticos utilizan poderosos algoritmos de anlisis sintctico, y son demasiado complejos para realizarlos manualmente. 2) Generadores de analizadores lxicos. Estas herramientas generan automticamente analizadores lxicos, por lo general a partir de una especificacin basada en expresiones regulares. La organizacin bsica del analizador lxico resultante es en realidad un autmata finito. 3) Dispositivos de traduccin dirigida por la sintaxis. Estos producen grupos de rutinas que recorren el rbol de anlisis sintctico, generando cdigo intermedio. La idea bsica es que se asocian una o ms " traducciones " con cada nodo del rbol de anlisis sintctico, y cada traduccin se define partiendo de traducciones en sus nodos vecinos en el rbol.

  • - 22 -

    4) Generadores automticos de cdigo. Tales herramientas toman un conjunto de reglas que definen la traduccin de cada operacin del lenguaje intermedio al lenguaje de mquina para la mquina objeto. Las reglas deben incluir suficiente detalle para poder manejar los distintos mtodos de acceso posibles a los datos; por ejemplo, las variables pueden estar en registros, en una posicin fija (esttica) de memoria o pueden tener asignada una posicin en una pila. La tcnica fundamental es la de " concordancia de plantillas. Las proposiciones de cdigo intermedio se reemplazan por " plantillas " que representan secuencias de instrucciones de mquina, de modo que las suposiciones sobre el almacenamiento de las variables concuerden de plantilla a plantilla. Como suele haber muchas opciones en relacin con la ubicacin de las variables (por ejemplo, en uno o varios registros de memoria), hay muchas formas posibles de " cubrir " el cdigo intermedio con un conjunto dado de plantillas, y es necesario seleccionar una buena cobertura sin una explosin combinatoria en el tiempo de ejecucin del compilador. 5) Dispositivos para anlisis de flujo de datos. Mucha de la informacin necesaria para hacer una buena optimizacin de cdigo implica hacer un " anlisis de flujo de datos ", que consiste en la recoleccin de informacin sobre la forma en que se transmiten los valores de una parte de un programa a cada una de las otras partes. Las distintas tareas de esta naturaleza se pueden efectuar esencialmente con la misma rutina, en la que el usuario proporciona los detalles relativos a la relacin que hay entre las proposiciones en cdigo intermedio y la informacin que se esta recolectando.

    UN COMPILADOR SENCILLO DE UNA PASADA

    Aqu se hace nfasis en la etapa inicial de un compilador, esto es, en el anlisis lxico, el anlisis sintctico y la generacin de cdigo intermedio.

    Perspectiva

    Se puede definir un lenguaje de programacin describiendo el aspecto de sus programas (la sintaxis del lenguaje) y el significado de sus programas (la semntica del lenguaje). Para especificar la sintaxis de un lenguaje, se presenta una notacin muy usada llamada gramticas independientes del contexto o BNF (abreviatura en ingles de forma de Backus-Naur). Con las notaciones disponibles hoy es mucho ms difcil describir la semntica de un lenguaje que su sintaxis. Adems, se puede usar de apoyo una gramtica independiente del contexto para guiar la traduccin de programas. Una tcnica de compilacin orientada a la gramtica, conocida como traduccin dirigida por la sintaxis, es muy til para organizar la etapa inicial de un compilador. Durante el estudio de la traduccin dirigida por la sintaxis, se construir un compilador que traduce expresiones infijos a la forma posfijo, una notacin en la que los operadores aparecen despus de sus operndoos. Por ejemplo, la forma postfija de la expresin 9 - 5 + 2 es 95 - 2 +. La notacin postfija puede ser convertida directamente en cdigo por un computador que haga todos sus clculos utilizando una estructura de datos de pila (stack). Se empieza a construir un programa sencillo para traducir expresiones consistentes en dgitos separados por los signos ms y menos en la forma postfija. Cuando las ideas bsicas resulten evidentes, se extender el programa para poder manejar construcciones de lenguajes de programacin ms generales. Cada traductor se forma por la extensin sistemtica del traductor anterior.

  • - 23 -

    En este compilador, el analizador lxico convierte la cadena de caracteres de entrada en una cadena de componentes lxicos que se convierte en la entrada para la siguiente fase, como se muestra en la figura 2.1. El " traductor dirigido por la sintaxis" de la figura es una combinacin de un analizador sintctico y un generador de cdigo intermedio. Una razn para empezar con expresiones formadas por dgitos y operadores consiste en hacer que el analizador lxico sea en un principio muy fcil; cada carcter de entrada forma un componente lxico nico. Ms adelante, se ampla el lenguaje para incluir construcciones lxicas, como nmeros, identificadores y palabras clave.

    CADENA DECOMPONENTES

    LEXICOS

    REPRESENTACIOINTERMEDIA

    TRADUCTORDIRIGIDO PORLA SINTAXIS

    CADENA DECARACTERES ANALIZADOR

    LEXICO

    Fig. 2.1 Estructura de la etapa inicial del compilador

    DEFINICIN DE LA SINTAXIS En esta seccin se introduce una notacin, llamada gramtica independiente del contexto (para abreviar, gramtica), para especificar la sintaxis de un lenguaje. Una gramtica describe la forma natural la estructura jerrquica de muchas construcciones de los lenguajes de programacin. Por ejemplo, una proposicin if else en C tiene la forma. if ( expresin ) proposicin else proposicin Esto es, la proposicin es la concatenacin de la palabra clave if, un parntesis que abre, una expresin, un parntesis que cierra, una proposicin, la palabra clave else y otra proposicin. ( En C no existe la palabra clave then ). Empleando la variable expr para denotar una expresin, y la variable prop, para una proposicin, esta regla de estructuracin se expresa prop if ( expr ) prop else prop Donde es posible leer la flecha como " puede tener la forma ". Dicha regla se denomina produccin. En una produccin, los elementos lxicos, como la palabra clave if y los parntesis, se llaman componentes lxicos. Las variables expr y prop representan secuencias de componentes lxicos y se llaman no terminales. Una gramtica independiente del contexto tiene cuatro componentes : 1) Un conjunto de componentes lxicos, denominados smbolos terminales. 2) Un conjunto de no terminales. 3) Un conjunto de producciones, en el que cada produccin consta de un no terminal, llamado lado izquierdo de la produccin, una flecha y una secuencia de composicin de lxicos y no terminales, o ambos, llamado lado derecho de la produccin. 4) La denominacin de uno de los no terminales como smbolo inicial.

  • - 24 -

    Se sigue la regla convencional de especificar las gramticas dando una lista de sus producciones, donde las producciones del smbolo inicial se listan primero. Se supone que los dgitos, los signos como

  • - 25 -

    a) 9 es una lista de la produccin (2.4), dado que 9 es un dgito. b) 9 - 5 es una lista de la produccin (2.3), dado que 9 es una lista y 5 es un dgito. c) 9 - 5 + 2 es una lista de la produccin (2.2), dado que 9 - 5 es una lista y 2 es un dgito. Este razonamiento se ilustra en la figura 2.2. Cada nodo en el rbol est etiquetado con un smbolo de gramtica. Un nodo interior y sus hijos corresponden a una produccin; el nodo interior corresponde al lado izquierdo de la produccin, los hijos, al lado derecho. Estos rboles se conocen con el nombre de rboles de anlisis sintctico.

    +

    lista

    2

    digito

    5-9

    digito

    lista digito

    lista

    Fig. 2.2 rbol de anlisis sintctico para 9-5+2 segn la gramtica del ejemplo 2.1

    Ejemplo 2.3 : Una clase algo distinta de listas es la secuencia de proposiciones separadas por los smbolos de punto y coma que se encuentran en los bloques begin end de Pascal. Una caracterstica de estas listas es que una lista vaca de proposiciones puede encontrarse entre los componentes lxicos begin y end. Se puede empezar a desarrollar una gramatica para los bloques begin-end incluyendo las producciones: bloque begin props_opc end props_opc lista_props | E lista_props lista_props ; prop | prop Obsrvese que el segundo lado derecho posible para props_opc ( " lista de proposiciones opcional " ) es E , que representa la cadena de smbolos vaca. Esto es, props_opc se puede representar por la cadena vacia, de modo que un bloque puede estar formado por la cadena de dos componentes lxicos begin end. Fjese que las producciones para lista_props son anlogas a las de lista del ejemplo 2.1, con un punto y coma en lugar de un operador aritmtico, y prop, en lugar de dgito.

    Arboles de anlisis sintctico

  • - 26 -

    Un rbol de anlisis sintctico indica grficamente como el smbolo inicial de una gramtica deriva una cadena del lenguaje. Si el no terminal A tiene una produccin : A XYZ, entonces un rbol de anlisis sintctico puede tener un nodo interior etiquetado con A y tres hijos etiquetados con X, Y y Z, de izquierda a derecha :

    +expresion expresion

    expresion

    Formalmente, dada una gramtica independiente del contexto, un rbol de anlisis sintctico es un rbol con las propiedades siguientes : 1) La raz esta etiquetada con el smbolo inicial. 2) Cada hoja etiquetada con un componente lxico o con E 3) Si A es el no terminal que etiqueta a algn nodo interior y X1,X2,...,Xn son las etiquetas de los hijos de ese nodo, de izquierda a derecha, entonces A X1,X2,...,Xn es una produccin. Aqu X1,X2,...,Xn representa un smbolo que es un terminal o un no terminal. Como caso especial, si A E , entonces un nodo etiquetado con A tiene solo un hijo etiquetado con E . Ejemplo 2.4 : En la fig. 2.2 la raz esta etiquetada con lista, que es el smbolo inicial de la gramatica del ejemplo 2.1. Los hijos de la raz estn etiquetados, de izquierda a derecha, lista, +, y dgito. Obsrvese que lista lista + dgito es una produccin de la gramtica del ejemplo 2.1. El mismo patrn con - se repite en el hijo izquierdo de la raz, y cada uno de los tres nodos etiquetados con dgito tiene un hijo de la raz, y cada uno de los tres nodos etiquetados con dgito tiene un hijo que esta etiquetado con un dgito. Las hojas de un rbol de anlisis sintctico, ledas de izquierda a derecha, forman la produccin del rbol, que es la cadena generada o derivada del no terminal de la raz del rbol de anlisis sintctico. En la fig. 2.2 la cadena generada es 9 - 5 + 2, y todas las hojas se muestran en el nivel inferior. A partir de aqu, las hojas no se alinearan de esa forma. Cualquier rbol imparte un orden natural, de izquierda a derecha, a sus hojas, basndose en la idea de que si a y b son dos hijos con el mismo padre, y a esta a la izquierda de b, entonces todos los descendientes de a estn a la izquierda de los descendientes de b. Otra definicin del lenguaje generado por una gramatica es el conjunto de cadenas que pueden ser generadas por un rbol de anlisis sintctico. El proceso de bsqueda de un rbol de anlisis sintctico para una cadena dada de componentes lxicos se denomina anlisis sintctico de esa cadena.

    Ambigedad

    Se ha de tener cuidado al considerar la estructura de una cadena segn una gramtica. Aunque es evidente que cada rbol de anlisis sintctico deriva exactamente la cadena que se lee en sus hojas, una gramatica puede tener mas de un rbol de anlisis sintctico que genere una cadena dada de componentes lxicos. Esta clase de gramatica se dice que es ambigua. Como una

  • - 27 -

    cadena que cuenta con mas de un rbol de anlisis sintctico suele tener mas de un significado, para aplicaciones de compilacin es necesario disear gramticas no ambiguas o utilizar gramticas ambiguas con reglas adicionales para resolver las ambigedades. Ejemplo 2.5 : Supngase que no se hizo la definicin entre dgitos y listas segn el ejemplo 2.1. Se podra haber escrito la gramatica cadena cadena + cadena | cadena - cadena |0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |8 | 9 Combinando la nocin de dgito y lista en el no terminal cadena parece tener sentido superficial, porque un solo dgito es un caso especial de una lista. Sin embargo, en la figura 2.3 se muestra la expresin 9 - 5 + 2 tiene ahora ms de un rbol de anlisis sintctico. Los dos rboles de 9 - 5 + 2 corresponden a dos formas de agrupamiento entre parntesis de la expresin : ( 9 - 5 ) + 2 y 9 - ( 5 + 2 ). Esta segunda forma de agrupamiento entre parntesis da a la expresin el valor 2, en lugar del valor acostumbrado 6. La gramatica del ejemplo 2.1 no permite esta interpretacin.

    Asociacin de operadores Por conversin, 9 + 5 + 2 es equivalente a ( 9 + 5 ) + 2, y 9 - 5 - 2 es equivalente a (9- 5 ) - 2. Cuando un operando con 5 tiene operadores a su izquierda y derecha, se necesitan convenciones para decidir que operador considera ese operando. Se dice que el operador + asocia a la izquierda, porque un operando que tenga un signo mas a ambos lados es tomado por el operador que est a su izquierda. En la mayora de los lenguajes de programacin, los cuatro operadores aritmticos, adicin, sustraccin, multiplicacin y divisin son asociativos por la izquierda.

    2

    5

    cadena-

    9

    cadena

    +cadena cadena

    cadena

    25

    +9

    Cadena -

    cadena cadena

    cadena

    Cadena

    Fig. 2.3 Dos rboles de anlisis sintctico para 9-5+2 Algunos operadores comunes, como la exponenciacin, son asociativos por la derecha. Otro ejemplo anlogo, el operador de asignacin = en C es asociativo por la derecha; en C, la expresin a = b = c se trata igual que la expresin a = ( b = c ).

  • - 28 -

    Las cadenas como a = b = c, con un operador asociativo por la derecha, son generadas por la siguiente gramtica : derecha letra = derecha | letra letra a | b | . . . | z El contraste entre un rbol de anlisis sintctico para un operador asociativo por la izquierda como -, y un rbol de anlisis sintctico para un operador asociativo por la derecha como =, se muestra la figura 2.4. Adviertase que el rbol de anlisis sintctico para 9 - 5 - 2 desciende hacia la izquierda, mientras que el rbol de anlisis sintctico para a = b = c desciende hacia la derecha.

    -

    lista

    2

    digito

    5

    -

    9

    digito

    lista digito

    lista

    c

    letrab

    =a

    letra =

    letra derecha

    derecha

    derecha

    Fig. 2.4 Arboles de analisis sintactico para operadores asociativos por la izquierda y por la

    derecha

    Precedencia de operadores

  • - 29 -

    Considrese la expresin 9 + 5 * 2 . Hay dos interpretaciones posibles de esta expresin: ( 9 + 5 ) * 2 o 9 + ( 5 * 2 ). La asociacin de + y * no resuelve esa ambigedad. Por esta razn, se necesita conocer la precedencia relativa de los operadores cuando este presente mas de una clase de operadores. Se dice que * tiene mayor precedencia que + si * considera sus operandos antes de que lo haga +. En aritmtica elemental, la multiplicacin y divisin tienen mayor precedencia que la adicin y la sustraccin. Por tanto, 5 es considerado por * en 9 + 5 * 2 y en 9 * 5 + 2; es decir, las expresiones son equivalentes a 9 + ( 5 * 2 ) y ( 9 * 5 ) + 2, respectivamente. Sintaxis de expresiones Utilizando una tabla que muestre la asociatividad y precedencia de operadores se puede construir una gramtica para expresiones aritmticas. Se empieza con los cuatro operadores aritmticos bsicos y una tabla de precedencias, mostrando los operadores en orden de precedencia creciente, con los operadores de la misma precedencia en la misma linea : Asociativos por la izquierda + - Asociativos por la izquierda * / Se crean dos no terminales expr y termino paro los dos niveles de precedencia, y un no terminal adicional factor para generar unidades bsicas en las expresiones. Las unidades bsicas de las expresiones son de momento dgitos y expresiones entre parntesis. factor dgito | ( expr ) Ahora, considrese los operadores binarios * y /, que tienen mayor precedencia. Como estos operadores asocian por la izquierda, las producciones son similares a las de las listas que asocian por la izquierda. termino termino * factor | termino | factor | factor De manera similar, expr genera listas de trminos separados por los operadores aditivos. expr expr + termino | expr - termino | termino Por lo tanto, la gramatica resultante es expr expr + termino | expr - termino | termino termino termino * factor | termino * factor | factor factor dgito | ( expr ) Esta gramatica considera una lista de trminos separados por los signos + o -, y un termino, como una lista de factores separados por los signos * o /. Advirtase que cualquier expresin entre parntesis es un factor, de manera que con los parentesis se pueden desarrollar expresiones que tengan anidamiento de profundidad arbitraria ( y tambin arboles de profundidad arbitraria ).

    Sintaxis de proposiciones

  • - 30 -

    Las palabras clave permiten reconocer proposiciones en la mayora de los lenguajes. Todas las proposiciones de Pascal comienzan con una palabra clave, excepto las asignaciones y las llamadas a procedimientos. Algunas proposiciones de Pascal se definen por medio de la siguiente gramatica ( ambigua ) en la que el componente lxico id representa un identificador. prop id : = expr | if expr then prop | if expr then prop else prop | while expr do prop | begin props_opc end El no terminal props_opc genera una lista de proposiciones, posiblemente vaca, separada por los smbolos de punto y coma, utilizando las producciones del ejemplo 2.3.

    TRADUCCIN DIRIGIDA POR LA SINTAXIS Para traducir una construccin de un lenguaje de programacin, un compilador puede necesitar tener en cuenta muchas caractersticas, adems del cdigo generado por la construccin. Por ejemplo, puede ocurrir que el compilador necesite conocer el tipo de la construccin, la posicin de la primera instruccin del cdigo objeto o el nmero de instrucciones generadas. Por tanto, los atributos asociados con las construcciones se mencionan de manera abstracta. Un atributo puede representar cualquier cantidad, por ejemplo, un tipo, una cadena, una posicin de memoria o cualquier otra cosa. En esta seccin, se presenta un formalismo llamado definicin dirigida por la sintaxis para especificar las traducciones para las construcciones de lenguajes de programacin. Una definicin dirigida por la sintaxis especifica la traduccin de una construccin en funcin de atributos asociados con sus componentes sintcticos. Para especificar traducciones, se introduce tambin una notacin mas orientada a procedimientos, denominada esquema de traduccin. Utilizaremos esquemas de traduccin para producir expresiones infijas a la forma posfija.

    Notacin posfija

    La notacin posfija de una expresin E se puede definir de manera inductiva como sigue : 1. Si E es una variable o una constante, entonces la notacin posfija E es tambin E. 2. Si E es una expresin de la forma E1 op E2, donde op es cualquier operador binario, entonces la notacin posfija de E es E1' E2' op, donde E1' y E2' son las notaciones posfijas de E1 y E2, respectivamente. 3. Si E es una expresin de la forma ( E1 ), entonces la notacin posfija de E1 es tambin la notacin posfija E.

  • - 31 -

    La notacin posfija no necesita parntesis, porque la posicin y la ariedad ( nmero de argumento ) de los operadores permiten solo una descodificacin de una expresin posfija por ejemplo, la notacion posfija de ( 9 - 5 ) + 2 es 95 - 2 + y la notacin posfija de 9 - ( 5 + 2 ) es 952 +-.

    Definiciones dirigidas por la sintaxis

    Una definicin dirigida por la sintaxis utiliza una gramtica independiente del contexto para especificar la estructura sintctica de la entrada. A cada smbolo de la gramatica le asocia un conjunto de atributos y a cada produccin, un conjunto de reglas semnticas para calcular los valores de los atributos asociados con los smbolos que aparecen en esa produccin. La gramatica y el conjunto de reglas semnticas constituyen la definicin dirigida por la sintaxis. Una traduccin es una transformacin de una entrada en una salida. La salida para cada entrada x se especifica de la forma siguiente. Primero, se construye un rbol de anlisis sintctico para x. Supngase que un nodo n del rbol de anlisis sintctico esta etiquetado con el smbolo X de la gramatica. Se describe X.a para indicar el valor del atributo a de X en ese nodo. El valo X.a en n se calcula por la regla semantica para el atributo a asociado con la produccion de X utilizada en el nodo n. Al rbol de anlisis sintctico que muestre los valores de los atributos en cada nodo se dice que es un rbol de anlisis sintctico con anotaciones.

    Atributos sintetizados

    Se dice que un atributo esta sintetizado si su valor en un nodo del rbol de anlisis sintctico se determina a partir de los valores de atributos de los hijos del nodo. Los atributos sintetizados tienen la atractiva propiedad de que se pueden calcular durante un solo recorrido ascendente del rbol de anlisis sintctico. Ejemplo 2.6 : En la figura 2.5 se muestra una definicin dirigida por la sintaxis para traducir expresiones formadas por dgitos separados por los signos ms o menos, a notacin posfija. A cada no terminal est asociado un atributo t con un valor de la cadena que representa la notacin posfija de la expresion ( produccin ) generada por ese no terminal en un rbol de anlisis sintctico.

    Produccin Regla Semntica expr expr1 + trmino expr expr1 - trmino expr trmino trmino 0 trmino 1 . . . trmino 9

    expr.t : = expr1.t || trmino.t || '+' expr.t : = expr1.t || trmino.t || '-' expr.t : = trmino.t trmino.t : = '0' trmino.t : = '1' . . . trmino.t : = '9'

  • - 32 -

    FIG. 2.5 Definicin dirigida por la sintaxis para traduccin de infija a posfija La forma posfija de un dgito es el propio dgito; por ejemplo, la regla semntica asociada con la produccin termino 9 define que termino.t es 9 cuando esta produccin se use en un nodo de un rbol de anlisis sintctico. Cuando se aplica la produccin expr trmino, el valor de trmino.t se transforma en el valor de expr.t. La produccin expr expr1 + termino deriva una expresin con un operador ms ( el subindice en expr1 distingue el caso de expr en el lado derecho de aquel que est en el lado izquierdo ). El operando izquierdo del operador ms est dado por expr1, y el operando derecho, por trmino. La regla semntica expr.t : = expr1.t|| trmino.t || '+' asociada con esta produccin define el valor del atributo expr.t mediante la concatenacin de las formas posfijas expr1.t y trmino.t de los operandos izquierdo y derecho, respectivamente, y despus agregando el signo ms. El operador || en las reglas semnticas representa la concatenacin de cadenas. La figura 2.6 comprende el rbol de anlisis sintctico con anotaciones correspondientes al rbol de la figura 2.2. El valor del atributo t en cada nodo se calcul por la regla semntica asociada con la produccin empleada en ese nodo. El valor del atributo en la raz es la anotacin posfija de la cadena generada por el rbol de anlisis sintctico.

    +

    expr.t = 95-2+

    2

    termino.t = 2

    5-9

    termino.t = 9

    expr.t = 9 termino.t = 5

    expr.t = 95-

    Fig. 2.6 Valores de atributos en los nodos de un rbol de anlisis sintctico Ejemplo 2.7 : Supngase que un robot se puede instruir para moverse un paso al este, norte, oeste o sur desde su posicin inicial. Una secuencia de estas instrucciones se genera con la gramtica siguiente: sec sec instr | comienza instr este | norte | oeste | sur

  • - 33 -

    En la figura 2.7 se muestran los cambios en la posicin del robot si se le proporciona la entrada comienza oeste sur este este este norte norte

    X

    Y

    .

    norte

    sur norte

    esteesteeste

    oeste

    En la figura, una posicin se marca con un par ( x,y ), donde x e y representan el numero de pasos al este y al norte, respectivamente, desde la posicin inicial. ( Si x es negativo, entonces el robot se encuentra al oeste de la posicin inicial; de manera similar, si y es negativo, entonces el robot se encuentra al sur de la posicin inicial ). Para traducir una secuencia de instrucciones a una posicin del robot, se construir una definicin dirigida por la sintaxis. Se usaran dos atributos, sec.x y sec.y para seguir la posicin que resulta de una secuencia de instrucciones generada por el no terminal sec. Al principio, sec genera comienza, asignado el valor inicial 0 a sec.x y sec.y, segn se indica en el nodo interior del rbol de anlisis sintctico de comienza oeste sur, situado en el extremo izquierdo de la figura 2.8.

    sec.x = - 1sec.y = - 1

    sur

    instr.dx = 0instr.dy = - 1

    oestecomienza

    sec.x = 0sec.y = 0

    instr.dx = - 1instr.dy = 0

    sec.x = - 1sec.y = 0

    Fig. 2.8 rbol de anlisis sintctico con anotaciones para comienza oeste sur.

  • - 34 -

    El cambio en la posicin a causa de una instruccin individual derivada de instr se da por los atributos instr.dx e instr.dy. Por ejemplo, si instr deriva oeste, entonces instr.dx = -1 e instr.dy = 0. Supngase que una secuencia sec se forma con una secuencia sec1 seguida de una nueva instruccin instr. Entonces, la nueva posicin del robot esta dada por las reglas sec.x : = sec1.x + instr.dx sec.y : = sec1.y + instr.dy En la figura 2.9 se muestra una definicin dirigida por la sintaxis para traducir una secuencia de instrucciones a una posicin del robot.

    Produccin Regla Semntica sec comienza sec.x : = 0

    sec.y : = 0 sec sec1 instr sec.x : = sec1.x + instr.dx

    sec.y : = sec1.y + instr.dy instr este instr.dx : = 1

    instr.dy : = 0 instr norte instr.dx : = 0

    instr.dy : = 1 instr oeste instr.dx : = -1

    instr.dy : = 0 instr sur instr.dx : = 0

    instr.dy : = -1

    Fig. 2.9 Definicin dirigida por la sintaxis de la posicin del robot

    Recorridos en profundidad Una definicin dirigida por la sintaxis no impone ningn orden especfico a la evaluacin de atributos en un rbol de anlisis sintctico; cualquier orden de evaluacin que calcule un atributo a, despus de haber calculado todos los dems atributos de los que a depende es aceptable. En general, es posible que haya que evaluar algunos atributos cuando se llega por primera vez a un nodo durante un recorrido del rbol de anlisis sintctico, otros, despus de haber visitado todos sus hijos o en algn punto entre las visitas a los hijos del nodo. Todas las traducciones de esta seccin se pueden hacer evaluando las reglas semnticas de los atributos en un rbol de anlisis sintctico en un orden predeterminado. Un recorrido de un rbol comienza en la raz y visita cada nodo del rbol en un orden indeterminado. Nosotros mediante el recorrido en profundidad que se define en la figura 2.10 evaluaremos las reglas semnticas. Este recorrido empieza en la raz y visita recursivamente a los hijos de cada nodo en orden de izquierda a derecha, como se muestra en la figura 2.11. Las reglas semnticas en un nodo dado se evalan cuando todos los descendentes de ese nodo hayan sido visitados. Se llama " en profundidad " porque siempre que pueda, visita a un hijo no visitado de un nodo, de modo que intenta visitar los nodos mas alejados de la raz lo antes posible.

  • - 35 -

    procedure visita (n: nodo); begin for cada hijo m de n, de izquierda a derecha do visita (m); evala reglas semnticas en el nodo n end

    Fig. 2.10 Un recorrido en profundidad de un rbol

    Esquema de traduccin En el resto de este captulo, se usa una especificacin orientada a procedimientos para definir una traduccin. Un esquema de traduccin es una gramtica independiente del contexto en la que se encuentran intercalados, en los lados derechos de las producciones, fragmentos de programa llamados acciones semnticas. Un esquema de traduccin es como una definicin dirigida por la sintaxis, con la exencin de que el orden de evaluacin de las reglas semnticas se muestra explcitamente. La posicin en la que se ejecuta alguna accin se da entre llaves y se escribe en el lado derecho de una produccin, por ejemplo, resto + trmino { print ('+')} resto1

    Fig. 2.11. Ejemplo de recorrido en profundidad de un rbol Un esquema de traduccin genera una salida para cada frase x generada por la gramtica subyacente mediante la ejecucin de las acciones en el orden en que aparecen durante un recorrido en profundidad de un rbol de anlisis sintctico para x. Sea el caso de un rbol de anlisis sintctico con un nodo etiquetado con resto que represente a esta produccin. La accin {print ('+') } se efectuara despus de recorrer el subrbol de termino, pero antes de visitar al hijo resto1.

  • - 36 -

    resto1+ termi { print ('+')}

    resto

    Fig. 2.12. Construccin de una hoja adicional correspondiente a una secuencia semntica

    Cuando se dibuja un rbol de anlisis sintctico de un esquema de traduccin, se indica una accin construyendo un hijo adicional, conectado al nodo para su produccin por una lnea de puntos. Por ejemplo, la parte del rbol de anlisis sintctico para la produccin y la accin anterior se representan en la figura 2.12. El nodo para una accin semntica no tiene hijos, de modo que la accin se realiza cuando se ve por primera vez ese nodo.

    Emisin de una traduccin En este captulo, las acciones semnticas en los esquemas de traduccin escribirn la salida de una traduccin en un archivo, una cadena o un carcter a la vez. Por ejemplo, se traduce 9 - 5 + 2 a 95 - 2 + imprimiendo cada carcter de 9 - 5 + 2 justo una vez, sin usar ningn almacenamiento para la traduccin de subexpresiones. Cuando la salida se crea incrementalmente de este modo, es importante el orden en que se imprimen los caracteres. Advirtase que las definiciones dirigidas por las sintaxis mencionadas hasta ahora tienen la siguiente propiedad importante. La cadena que representa la traduccin del no terminal del lado izquierdo de cada produccin es la concatenacin de las traducciones de los no terminales de la derecha, en igual orden que en la produccin, con algunas cadenas adicionales ( tal vez ninguna ) intercaladas. Con esta propiedad, una definicin dirigida por la sintaxis se denomina simple. Por ejemplo, considrense la primera produccin y la regla semntica de la definicin dirigida por la sintaxis de la figura 2.5 : Ejemplo 1 :

    Produccin

    Regla Semntica

    expr expr1 + trmino

    expr.t : = expr1.t || trmino.t || '+' (2.6)

    Aqu, la traduccin expr.t es la concatenacin de las traducciones de expr1 y termino, seguida del smbolo +. Advirtase que expre1 aparece antes que termino en el lado derecho de la produccin. Entre termino.t y resto1.t aparece una cadena adicional en Ejemplo 2 :

    Produccin

    Regla Semntica

  • - 37 -

    resto + trmino resto1

    resto.t : = trmino.t || '+' || resto1.t (2.7)

    pero de nuevo, el no terminal trmino aparece antes que resto1 en el lado derecho. Las definiciones simples dirigidas por la sintaxis se pueden implantar con esquemas de traduccin en los que las acciones impriman las cadenas adicionales en el orden en que aparecen en la definicin. Las acciones de las siguientes producciones imprimen las cadenas adicionales de (2.6) y (2.7), respectivamente: expr.t expr1 + trmino { print ('+') } resto.t + trmino { print ('+') } resto1 Ejemplo 2.8 La figura 2.5 contiene una definicin simple para traducir expresiones a la forma posfija. En la figura 2.13 se da un esquema de traduccin derivado de esta definicin y en la figura 2.14 se muestra un rbol de anlisis sintctico con acciones para 9 - 5 + 2. Obsrvese que aunque las figuras 2.6 y 2.14 representan la misma transformacin de entrada a salida, la traduccin se construye de manera distinta en los dos casos; la figura 2.6 vincula la salida a la raz del rbol de anlisis sintctico, mientras que la figura 2.14 imprime la salida de forma incremental. La raz de la figura 2.14 representa la primera produccin de la figura 2.13. expr expr + trmino { print ('+') } expr expr - trmino { print ('-') } expr trmino trmino 0 { print ('0') } trmino 1 { print ('1') } . . . trmino 9 { print ('9') }

    Fig. 2.13. Acciones que traducen expresiones a la notacin posfija En un recorrido en profundidad, primero se realizan todas las acciones del subrbol para el operando izquierdo expr cuando se recorre el subrbol situado ms a la izquierda de la raz, despus se visita la hoja +, en la que no hay ninguna accin, a continuacin realizan las acciones del subrbol para el operando derecho trmino y, por ultimo, se realiza la accin semntica { print ('+') } en el nodo adicional. Como las producciones para trmino tienen solo un dgito en el lado derecho, ese dgito se imprime por medio de las acciones para las producciones. No se necesita ninguna salida para la produccin expr trmino, y solo se requiere imprimir el operador en las dos primeras producciones. Cuando se ejecutan durante un recorrido en profundidad del rbol de anlisis sintctico, las acciones de la figura 2.14 imprimen 95 - 2 +.

  • - 38 -

    { print ('9')}9

    termino{ print ('5')}

    { print ('-')} { print ('2')}

    { print ('+')}

    +

    expr

    2

    termino

    5

    -expr termino

    expr

    Fig. 2.14 Acciones que traducen 9 - 5 + 2 a 95 - 2 + Como regla general, la mayora de los mtodos de anlisis sintctico procesan su entrada de izquierda a derecha de forma " voraz ; esto es, construyendo el mximo posible de un rbol de anlisis sintctico antes de leer el siguiente componente lxico de la entrada. En un esquema de traduccin simple ( obtenido de una definicin simple dirigida por la sintaxis ) las acciones se efectan tambin de izquierda a derecha. Por lo tanto, para implementar un esquema de traduccin simple se pueden ejecutar las acciones semnticas durante el anlisis sintctico; no es necesario construir el rbol de anlisis sintctico.

    ANLISIS SINTCTICO

    El anlisis es el proceso de determinar si una cadena de componentes lxicos puede ser generada por una gramtica. En el estudio de este problema, es til pensar en construir un rbol de anlisis sintctico, aunque de hecho, un compilador no lo construya. Sin embargo, un analizador sintctico deber poder construir el rbol, pues de otro modo, no se puede garantizar que la traduccin sea correcta. En esta seccin se introduce un mtodo de anlisis sintctico que puede aplicarse en la construccin de traductores dirigidos por la sintaxis. La mayora de los mtodos de anlisis sintcticos estn comprendidos en dos clases, llamadas descendentes y ascendentes. Estos trminos hacen referencia al, orden en que se construyen los nodos del rbol de anlisis sintctico. El anlisis sintctico ascendente puede manejar una clase mayor de gramticas y esquemas de traduccin, de modo que las herramientas de software para generar analizadores sintcticos directamente a partir de las gramticas tienden a utilizar mtodos ascendentes. Anlisis sintctico descendente La siguiente gramtica genera un subconjunto de los tipos de Pascal. Se utiliza el componente lxico punto para enfatizar que la secuencia de caracteres se trata como una unidad.

  • - 39 -

    tipo simple | ID | array [ simple ] of tipo simple integer (2.8) | char | nm puntopunto nm La construccin descendente de un rbol de anlisis sintctico se hace empezando por la raz, etiquetada con el no terminal inicial, y realizando de forma repetida los dos pasos siguientes

    E )

    D )

    C )

    B )

    A )

    integer

    num simplenumpuntopunto

    array simple tipo]

    tipo

    of[

    num simplenumpuntopunto

    array simple tipo]

    tipo

    of[

    numpuntopuntonum

    array simple tipo]

    tipo

    of[

    tipo

    array simple tipo]

    tipo

    of[

  • - 40 -

    Fig. 2.15. Pasos en la construccin descendente de un rbol de anlisis sintctico. 1. En el nodo n, etiquetado con el no terminal A, seleccinese una de las producciones para A y constryase los hijos de n para los smbolos del lado derecho de la produccin. 2. Encuntrese el siguiente nodo en el que ha de construirse un subrbol. Para algunas gramticas, los pasos anteriores se aplican durante un examen sencillo, de izquierda a derecha, de la cadena de entrada. Muchas veces, el componente lxico en curso analizado en la entrada se denomina smbolo de preanlisis. Inicialmente, el smbolo de preanlisis es el primero, es decir, el componente lxico situado ms a la izquierda de la cadena de entrada. La figura 2.16 ilustra el anlisis sintctico de la cadena. array [ nm puntopunto nm ] of integer Inicialmente, el componente lxico array es el smbolo de preanlisis y la parte conocida del rbol de anlisis sintctico consiste en la raz, etiquetada con el no terminal inicial tipo en la figura 2.16 (a). El objetivo es construir el resto del rbol de anlisis de modo que la cadena generada por l concuerde con la cadena de entrada. Para que ocurra una concordancia, el no terminal tipo de la figura 2.16 (a) debe derivar una cadena que empiece con el smbolo del preanlisis array. En la gramtica (2.8) hay exactamente una produccin para tipo que deriva tal cadena, por lo que se elige, y se construyen los hijos de la raz etiquetados con los smbolos del lado derecho de la produccin. Cada una de las tres imgenes de la figura 2.16 tiene flechas que indican el smbolo de preanlisis de la entrada y el nodo que se esta considerando. Cuando se han construido los hijos de un nodo, despus se considera el hijo que esta mas a la izquierda. En la figura 2.16 (b), se han construido los hijos de la raz, y se est considerando el hijo situado ms a la izquierda, etiquetado con array. cuando el nodo que se esta considerando en el rbol de anlisis sintctico es el de un terminal y el terminal concuerda con el smbolo de preanlisis, se avanza en el rbol de anlisis sintctico y en la entrada. El siguiente componente lxico de la entrada se convierte en el nuevo smbolo de preanlisis y se considera el siguiente hijo del rbol de anlisis sintctico. En la figura 2.16 (c), la flecha del rbol de anlisis sintctico avanza hasta el siguiente hijo de la raz y la flecha de la entrada avanza hasta el siguiente componente lxico. Despus del siguiente avance, la flecha del rbol de anlisis sintctico apuntara al hijo etiquetado con el no terminal simple. Cuando se considera un nodo etiquetado con un no terminal, se repite el proceso de seleccionar una produccin para el no terminal. En general, la seleccin de una produccin para un no terminal puede implicar un proceso de prueba y error, esto es, se puede probar con una produccin y retroceder para hacer el intento con otra produccin si la primera resulta inadecuada. Una produccin es inadecuada cuando, despus de usar las producciones, no se puede completar el rbol para que concuerde con la cadena de entrada. Sin embargo, hay un caso de especial importancia, llamado analizador sintctico predictivo, en el que no hay retroceso.

  • - 41 -

    rbol de anlisis tipo sintctico a) array [ num puntopunto ] of integer entrada

    Arbol de analisis sintacticob) array simple tipo]

    tipo

    of[

    array [ num puntopunto num ] of integer entrada

    Arbol de analisis sintacticoc ) array simple tipo]

    tipo

    of[

    array [ num puntopunto num ] of integer entrada

    Fig. 2.16 Anlisis sintctico descendente durante el examen de la entrada de izquierda a derecha

    Anlisis sintctico predictivo

    El anlisis sintctico descendente recursivo es un mtodo descendente en el que se ejecuta un conjunto de procedimientos recursivos para procesar la entrada. A cada no terminal de una gramtica se asocia un procedimiento. Aqu, se considera una forma especial de anlisis sintctico descendente recursivo, llamado anlisis sintctico predictivo, en el que el smbolo de preanlisis determina sin ambigedad el procedimiento seleccionado para cada no terminal. La secuencia de procedimientos llamados en el procesamiento de la entrada define implcitamente un rbol de anlisis sintctico para la entrada. El analizador sintctico predictivo de la figura 2.17 consta de procedimientos para los no terminales tipo y simple de la gramtica (2.8) y un procedimiento adicional. parea. Se usa parea para simplificar el cdigo de tipo y simple; si su argumento t concuerda con el smbolo de preanlisis, avanza hacia el siguiente componente lxico de entrada. De ese modo, parea modifica a la variable preanlisis, que es el componente lxico en curso que acaba de entregar el anlisis lxico.

  • - 42 -

    El anlisis sintctico con una llamada al procedimiento del no terminal inicial tipo de esta gramtica. Con la misma entrada que en la figura 2.16, preanlisis es inicialmente el primer componente lxico array. El procedimiento tipo ejecuta el cdigo. parea (array); parea ('['); simple; parea (']') parea (of); tipo (2.9) que corresponde al lado derecho de la produccin tipo array [ simple ] of tipo Obsrvese que cada terminal del lado derecho se parea con el smbolo de preanlisis y que cada no terminal de la derecha proporciona una llamada a su procedimiento. Con la entrada de la figura 2.16, despus de