compiladores

89
Curso de Estructura de Compiladores Texto recopilado de: Compiladores, principios, técnicas y herramientas – “El Libro del Dragon” - Aho, Sethi,Ullman Louden, K.C. (1997), Compiler Construction: Principles and Practice Slides de PowerPoint – Compiladores - Oscar Bonilla (slides preparados por el Prof. Saman Amarasinghe del Massachusets Institute of Technology) Louden, K.C. (1997), Compiler Construction: Principles and Practice, Tema 2. Mg(e) Ing René Sánchez Vera 1

description

estructura de compiladores

Transcript of compiladores

  • Curso de Estructura de Compiladores

    Texto recopilado de:

    Compiladores, principios, tcnicas y herramientas El Libro del Dragon - Aho, Sethi,Ullman Louden, K.C. (1997), Compiler Construction: Principles and Practice

    Slides de PowerPoint Compiladores - Oscar Bonilla (slides preparados por el Prof. Saman Amarasinghe del Massachusets Institute of Technology)

    Louden, K.C. (1997), Compiler Construction: Principles and Practice, Tema 2.

    Mg(e) Ing Ren Snchez Vera

    1

  • 1. Introduccin

    Para iniciar tenemos que contestar las siguientes preguntas:

    Qu es un lenguaje de programacin?

    Cmo le damos instrucciones a una computadora?

    Cmo hacemos que la computadora lleve a cabo las instrucciones eficientemente?

    1.1 Lenguaje de Programacin Para que un computador (hardware) funcione es necesario utilizar programas (software), los cuales le indican cul es la tarea que se tiene que hacer. Un lenguaje de programacin es el que se utiliza para escribir dichos programas.

    Posteriormente estos se introducirn en la memoria del computador y ste ltimo ejecutar todas las operaciones que se incluyen.

    Pueden ser usados para describir cualquier accin. Hay muchas formas de describir la misma accin

    Un lenguaje de programacin o ms genricamente de computacin, es el medio por el cual el hombre interacta con un ordenador

    2

  • 1.1.1. Caractersticas de los Lenguajes de Programacin Deben ser no ambiguos Deben ser precisos Deben ser concisos Deben ser expresivos Deben estar a alto nivel (muchas abstracciones)

    1.1.2. Cmo instruir a la computadora Escribimos un programa usando un lenguaje de programacin Descripcin

    abstracta de alto nivel

    Teora de lenguajes de programacin

    La teora de lenguajes de programacin (comnmente conocida como PLT) es una rama de la informtica que se encarga del diseo, implementacin, anlisis, caracterizacin y clasificacin de lenguajes de programacin y sus caractersticas. Es un campo multi-disciplinar, dependiendo tanto

    de (y en algunos casos afectando) matemticas, ingeniera del software, lingstica, e incluso ciencias cognitivas. Es una rama bien reconocida de la informtica, y a fecha de 2006, un rea activa

    de investigacin, con resultados publicados en un gran nmero de revistas dedicadas a la PLT, as como en general en publicaciones de informtica e ingeniera. La mayora de los programas de los

    estudiantes de informtica requieren trabajar en este tema.

    Un smbolo no oficial de la teora de lenguajes de programacin es la letra griega lambda en minsculas. Este uso deriva del clculo lambda, un modelo computacional ampliamente usado por investigadores de

    lenguajes de programacin.

    El clculo lambda, desarrollado por Alonzo Church, Max HL. Solis Villareal y Stephen Cole Kleene en la dcada de 1930, es considerado ser uno de los primeros lenguajes de programacin del mundo

    3

  • Los microprocesadores hablan en lenguaje ensamblador Detalles de implementacin de bajo nivel

    Input: lenguaje de programacin de alto nivel

    Output: instrucciones de assembler de bajo nivel

    Compilador tiene que:

    leer y entender el programa

    precisamente determinar que acciones se requieren

    encontrar cmo llevar a cabo esas acciones

    instruir a la computadora a lleva a cabo las acciones

    Ejemplo (programa de entrada)

    Int expr(int n) { int d; d = 4 * n * n * (n + 1) * (n + 1); return d; }

    Ejemplo (Assembler de salida) lda $30,-32($30) stq $26,0($30) stq $15,8($30) bis $30,$30,$15 bis $16,$16,$1 stl $1,16($15) lds $f1,16($15) sts $f1,24($15) ldl $5,24($15) bis $5,$5,$2 s4addq $2,0,$3 ldl $4,16($15) mull $4,$3,$2

    ldl $3,16($15) addq $3,1,$4 mull $2,$4,$2 ldl $3,16($15) addq $3,1,$4 mull $2,$4,$2 stl $2,20($15) ldl $0,20($15) br $31,$33 $33: bis $15,$15,$30 ldq $26,0($30) ldq $15,8($30) addq $30,32,$30

    4

  • ret $31,($26),1 Primeros Lenguajes

    (1954 -1957) Fortran (1958 -1959) LISP (1958 -1960) Algo60 (1959 -1960) COBOL

    Otros Lenguajes (1972) C (1986) C++ (1994) Java

    Compiladores optimizan cdigo para...

    Velocidad / Rendimiento Tamao de cdigo Consumo de Poder Compilacinrpida / eficiente Seguridad / Confiabilidad Debugging

    Paradigmas

    Es el conjunto de ideas, modelos o patrones que forman una percepcin sobre algn objeto, situacin, cosa persona.

    Un cambio de paradigma en la ciencia significa un gran cambio. Paradigmas de Programacin

    Un paradigma de programacin es una propuesta tecnolgica que es adoptada por una comunidad de programadores cuyo ncleo central es incuestionable en cuanto a que unvocamente trata de resolver uno o varios problemas claramente delimitados.

    La resolucin de estos problemas debe suponer consecuentemente un avance significativo en al menos un parmetro que afecte a la ingeniera de software. Tiene una estrecha relacin con la formalizacin de determinados lenguajes en su momento de definicin. Un paradigma de programacin est delimitado en el tiempo en cuanto a aceptacin y uso ya que nuevos paradigmas aportan nuevas o mejores soluciones que la sustituyen parcial o totalmente.

    Paradigmas de programacin

    Programacin imperativa Programacin lgica Programacin funcional Programacin declarativa Programacin estructurada Programacin dirigida por eventos Programacin modular Programacin orientada a aspectos Programacin orientada a objetos Programacin con restricciones Programacin a nivel funcional (John Backus) Programacin a nivel de valores (John Backus) Programacin orientada a componentes

    5

  • 1.2 Conceptos Bsicos

    Un traductor es un programa que traduce o convierte desde un texto o programa escrito en un lenguaje fuente hasta un texto o programa escrito en un lenguaje destino produciendo, si cabe, mensajes de error. Los traductores engloban tanto al compilador como al intrprete.

    El cdigo fuente de un programa informtico (o software) es un conjunto de lneas de texto que son las instrucciones que debe seguir la computadora para ejecutar dicho programa. Por tanto, en el cdigo fuente de un programa est descrito por completo su funcionamiento.

    Un lenguaje de programacin de alto nivel se caracteriza por expresar los algoritmos de una manera adecuada a la capacidad cognitiva humana, en lugar de a la capacidad ejecutora de las mquinas.

    Lenguaje de mquina es el sistema de cdigos directamente interpretable por un circuito microprogramable, como el microprocesador de una computadora o el microcontrolador de un autmata. Este lenguaje est compuesto por un conjunto de instrucciones que determinan acciones a ser tomadas por la mquina.

    El lenguaje ensamblador, o assembler (assemblylanguage en ingls) es un lenguaje de programacin de bajo nivel para los computadores, microprocesadores, microcontroladores, y otros circuitos integrados programables. Implementa una representacin simblica de los cdigos de mquina binarios y otras constantes necesarias para programar una arquitectura dada de CPU y constituye la representacin ms directa del cdigo mquina especfico para cada arquitectura legible por un programador.

    En informtica, un ejecutable o archivo ejecutable, es tradicionalmente un o como se le conoce mayormente archivo binario cuyo contenido se interpreta por el ordenador como un programa.

    6

  • 1.3 Traductores y Compiladores

    1.3.1. Traductores de un Lenguaje de Programacin Los traductores son programas que traducen los programas en cdigo fuente, escritos en lenguajes de alto nivel, a programas escritos en lenguaje mquina.

    Los traductores pueden ser de dos tipos: compiladores e intrpretes

    7

  • 1.3.2. Interprete Los intrpretes no producen un lenguaje objetivo como en los compiladores. Un intrprete lee el cdigo como est escrito e inmediatamente lo convierte en acciones; es decir, lo ejecuta en ese instante.

    Existen lenguajes que utilizan un intrprete (como por ejemplo JAVA,PHP) que traduce en el instante mismo de lectura el cdigo en lenguaje mquina para que pueda ser ejecutado. La siguiente figura muestra el funcionamiento de un intrprete.

    Ilustracin 1-1 - Esquema General de un Interprete

    Dependiendo de la complejidad del cdigo a analizar, el intrprete puede contener mdulos similares a los de un compilador tradicional: Anlisis lxico, Sintctico y Semntico. Durante la evaluacin, el intrprete interacta con los recursos del sistema como la memoria, discos, etc. Muchos sistemas interpretados liberan al programador del manejo explcito de memoria mediante tcnicas de recoleccin de basura.

    A la hora de evaluar la representacin interna, existen dos mtodos fundamentales: la interpretacin iterativa y la interpretacin recursiva.

    Ventaja Los intrpretes, por definicin, realizan la fase de anlisis y ejecucin a la vez, lo

    cual imposibilita optimizaciones. Por esta razn, los sistemas interpretados suelen ser menos eficientes que los compilados. No obstante, los nuevos avances informticos aumentan la velocidad de procesamiento y capacidad de memoria de

    8

  • los ordenadores. Actualmente, la eficiencia es un problema menos grave y muchas veces se prefieren sistemas que permitan un desarrollo rpido de aplicaciones que cumplan fielmente la tarea encomendada.

    Desventajas Los intrpretes, en general, son ms sencillos de implementar.

    Proporcionan una mayor flexibilidad que permite modificar y ampliar caractersticas del lenguaje fuente.

    No es necesario contener en memoria todo el cdigo fuente. Esto permite su utilizacin en sistemas de poca memoria o en entornos de red.

    Facilitan la meta-programacin. Un programa puede manipular su propio cdigo fuente a medida que se ejecuta. Esto facilita la implementacin de sistemas de aprendizaje automatizado y reflectividad [AtKaci 91].

    Aumentan la portabilidad del lenguaje: Para que el lenguaje interpretado funcione en otra mquina slo es necesario que su intrprete funcione en dicha mquina.

    Puesto que no existen etapas intermedias de compilacin, los sistemas interpretados facilitan el desarrollo rpido de prototipos, potencian la utilizacin de sistemas interactivos y facilitan las tareas de depuracin.

    Aplicaciones de los sistemas basados en intrpretes Los sistemas interpretados han tenido una gran importancia desde la aparicin de los primeros ordenadores. En la actualidad, la evolucin del hardware abre nuevas posibilidades a los sistemas interpretados. La preocupacin ya no es tanto la eficiencia como la capacidad de desarrollo rpido de nuevas aplicaciones. Las principales aplicaciones podran resumirse en:

    Intrpretes de Comandos: Los sistemas operativos cuentan con intrpretes de comandos como el Korn-Shell, C-Shell, JCL, etc. Estos intrpretes toman un lenguaje fuente que puede incluir sentencias de control (bucles, condiciones, asignaciones, etc.) y ejecutan los diferentes comandos a medida que aparecen en el lenguaje.

    Lenguajes basados en Escritos (Scripting Languages), diseados como herramientas que sirvan de enlace entre diferentes sistemas o aplicaciones. Suelen ser interpretados con el fin de admitir una mayor flexibilidad a la hora de afrontar las peculiaridades de cada sistema. Podran destacarse Perl, Tcl/Tk, JavaScript, WordBasic[Ousterhout 97]

    9

  • Entornos de Programacin: Existen ciertos lenguajes que contienen caractersticas que impiden su compilacin o cuya compilacin no es efectiva. Estos lenguajes suelen disponer de un complejo entorno de desarrollo interactivo con facilidades para la depuracin de programas. Entre estos sistemas pueden destacarse los entornos de desarrollo para Lisp, Visual Basic, Smalltalk, etc.

    Lenguajes de Propsito Especfico: Ciertos lenguajes incluyen sentencias que realizan tareas complejas en contextos especficos. Existe una gran variedad de aplicaciones en las que se utilizan este tipo de lenguajes como consultas de Bases de Datos, simulacin, descripcin de hardware, robtica, CAD/CAM, msica, etc.

    Sistemas en Tiempo Real: Entornos que permiten modificar el cdigo de una aplicacin en tiempo de ejecucin de forma interactiva.

    Intrprete de Cdigo Intermedio: Una tendencia tradicional en el diseo de compiladores es la generacin de un cdigo intermedio para una mquina abstracta, por ejemplo, el P-Code de Pascal o los bytecodesde Java. El siguiente paso puede ser: generacin del cdigo objeto a partir del cdigo intermedio para una mquina concreta, finalizando el proceso de compilacin o interpretar dicho cdigo intermedio en una mquina concreta. La tendencia habitual es definir un lenguaje intermedio independiente de una mquina concreta. Para ello, suele definirse una mquina virtual que contenga las instrucciones definidas por el lenguaje intermedio, permitiendo una mayor portabilidad. Un ejemplo sera la Mquina Virtual de Java, que es simulada en la mayora de los visualizadores Web.

    Tipos de intrpretes A continuacin se va a realizar una clasificacin de los diferentes mtodos de interpretacin segn la estructura interna del intrprete. Es conveniente observar que algunos mtodos podran considerarse hbridos, ya que mezclan los procesos de compilacin e interpretacin.

    Intrpretes puros Intrpretes avanzados Intrpretes incrementales

    10

  • 1.3.3. Compilador Un compilador es un programa que lee el cdigo escrito en un lenguaje (lenguaje origen), y lo traduce en un programa equivalente escrito en otro lenguaje (lenguaje objetivo). Como una parte fundamental de este proceso de traduccin, el compilador le hace notar al usuario la presencia de errores en el cdigo fuente del programa. Vea la siguiente figura.

    Los lenguajes C y C++ son lenguajes que utiliza un compilador. El trabajo del compilador y su funcin es llevar el cdigo fuente escrito en C/C++ a un programa escrito en lenguaje mquina. Entrando en ms detalle, un programa en cdigo fuente es compilado obteniendo un archivo parcial (un objeto) que tiene extensin obj. Luego el compilador invoca al linker que convierte al archivo objeto en un ejecutable con extensin exe; este ltimo archivo es un archivo en formato binario (ceros y unos) y puede funcionar por s slo.

    Adems, el compilador al realizar su tarea realiza tambin una comprobacin de errores en el programa; es decir, revisa que todo est en orden. Por ejemplo, variables y funciones bien definidas, todo lo referente a cuestiones sintcticas, etc. Est fuera del alcance del compilador que, por ejemplo, el algoritmo utilizado en el problema funcione bien.

    Ilustracin 1-2 - Esquema General de un Compilador

    11

  • Ilustracin 1-3 , Visin General de un Compilador

    12

  • Partes de un compilador La construccin de un compilador involucra la divisin del proceso en una serie de fases que variar con su complejidad. Generalmente estas fases se agrupan en dos tareas: el anlisis del programa fuente y la sntesis del programa objeto.

    Anlisis: Se trata de la comprobacin de la correccin del programa fuente, e incluye las fases correspondientes al Anlisis Lxico (que consiste en la descomposicin del programa fuente en componentes lxicos), Anlisis Sintctico (agrupacin de los componentes lxicos en frases gramaticales ) y Anlisis Semntico (comprobacin de la validez semntica de las sentencias aceptadas en la fase de Anlisis Sintctico).

    Sntesis: Su objetivo es la generacin de la salida expresada en el lenguaje objeto y suele estar formado por una o varias combinaciones de fases de Generacin de Cdigo (normalmente se trata de cdigo intermedio o de cdigo objeto) y de Optimizacin de Cdigo (en las que se busca obtener un cdigo lo ms eficiente posible).

    Alternativamente, las fases descritas para las tareas de anlisis y sntesis se pueden agrupar en Front-end y Back-end:

    Front-end: es la parte que analiza el cdigo fuente, comprueba su validez, genera el rbol de derivacin y rellena los valores de la tabla de smbolos. Esta parte suele ser independiente de la plataforma o sistema para el cual se vaya a compilar, y est compuesta por las fases comprendidas entre el Anlisis Lxico y la Generacin de Cdigo Intermedio.

    Back-end: es la parte que genera el cdigo mquina, especfico de una plataforma, a partir de los resultados de la fase de anlisis, realizada por el Front End.

    Esta divisin permite que el mismo Back End se utilice para generar el cdigo mquina de varios lenguajes de programacin distintos y que el mismo Front End que sirve para analizar el cdigo fuente de un lenguaje de programacin concreto sirva para generar cdigo mquina en varias plataformas distintas. Suele incluir la generacin y optimizacin del cdigo dependiente de la mquina.

    El cdigo que genera el Back End normalmente no se puede ejecutar directamente, sino que necesita ser enlazado por un programa enlazador (linker)

    Tipos de compiladores Esta taxonoma de los tipos de compiladores no es excluyente, por lo que puede haber compiladores que se adscriban a varias categoras:

    Compiladores cruzados: generan cdigo para un sistema distinto del que estn funcionando.

    13

  • Compiladores optimizadores: realizan cambios en el cdigo para mejorar su eficiencia, pero manteniendo la funcionalidad del programa original.

    Compiladores de una sola pasada: generan el cdigo mquina a partir de una nica lectura del cdigo fuente.

    Compiladores de varias pasadas: necesitan leer el cdigo fuente varias veces antes de poder producir el cdigo mquina.

    Compiladores JIT (Just In Time): forman parte de un intrprete y compilan partes del cdigo segn se necesitan.

    1.3.4. Diferencia entre compilador e intrprete

    Los compiladores difieren de los intrpretes en varios aspectos:

    Un programa que ha sido compilado puede correr por s slo, pues en el proceso de compilacin se lo transformo en otro lenguaje (lenguaje mquina).

    Un intrprete traduce el programa cuando lo lee, convirtiendo el cdigo del programa directamente en acciones. La ventaja del intrprete es que dado cualquier programa se puede interpretar en cualquier plataforma (sistema operativo). En cambio, el archivo generado por el compilador solo funciona en la plataforma en donde se le ha creado. Sin embargo, hablando de la velocidad de ejecucin, un archivo compilado es de 10 a 20 veces ms rpido que un archivo interpretado.

    1.3.5. Anatoma de un compilador

    Ilustracin 1-4 , Anatoma de un compilador

    14

  • 2. Analizador Lxico

    Ilustracin 2-1 , Analizador Lxico

    2.1 Funcin de un analizador lxico Leer los caracteres de cdigo fuente y formarlos en unidades lgicas para que lo aborden las partes siguientes de compilador (generalmente el analizador Sintctico). Las unidades lgicas que genera el analizador lxico se denominan Tokens. Los Tokens son las palabras de un lenguaje natural: cada tokens es una secuencia de caracteres que representa una unidad de informacin en el programa fuente.

    Palabras reservadas: if, while, repeat. Identificadores: Posicin, velocidad, tiempo. Operadores: = * + - / == >

  • El token de smbolo especial como MAS, no solo se tiene el valor de cadena +, sino tambin la operacin aritmtica real + que est asociada con l mismo. Es decir el smbolo del token mismo se puede ver simplemente como otro atributo.

    El analizador lxico opera bajo peticin del analizador sintctico devolviendo un componente lxico conforme el analizador sintctico lo va necesitando para avanzar en la gramtica. Los componentes lxicos son los smbolos terminales de la gramtica. Suele implementarse como una subrutina del analizador sintctico. Cuando recibe la orden obtn el siguiente componente lxico, el analizador lxico lee los caracteres de entrada hasta identificar el siguiente componente lxico.

    Otras funciones secundarias: Manejo del fichero de entrada del programa fuente: abrirlo, leer sus caracteres,

    cerrarlo y gestionar posibles errores de lectura. Eliminar comentarios, espacios en blanco, tabuladores y saltos de lnea

    (caracteres no vlidos para formar un token). Inclusin de ficheros: # include ... La expansin de macros y funciones inline: # define ... Contabilizar el nmero de lneas y columnas para emitir mensajes de error. Reconocimiento y ejecucin de las directivas de compilacin (por ejemplo, para

    depurar u optimizar el cdigo fuente). El anlisis lxico es una subrutina del anlisis sintctico que devuelve el tipo de

    componente lxico y el lexema cada vez que es llamada. En el analizador lxico debe haber una funcin que se encarga de gestionar el

    buffer de entrada. Se leera una lnea que se almacenarla en un vector de caracteres. Cuando haya sido procesada se carga de nuevo.

    Las palabras reservadas se reconocen como identificadores y antes de devolver un identificador se comprueba si es una palabra reservada o un identificador consultando en una tabla previamente inicializada con las palabras reservadas.

    Hay casos en los que es necesario reinsertar un carcter en el buffer de entrada. Adems de los componentes lxicos definidos por el lenguaje es conveniente

    aadir un par especiales para indicar el final de fichero y la deteccin de un error.

    Ventajas de separar el anlisis lxico y el anlisis sintctico:

    16

  • Facilita transportabilidad del traductor (por ejemplo, si decidimos en un momento dado cambiar las palabras reservadas begin y end de inicio y fin de bloque, por{ y}, slo hay que cambiar este mdulo.

    Se simplifica el diseo: el analizador es un objeto con el que se interacta mediante ciertos mtodos. Se localiza en un nico mdulo la lectura fsica de los caracteres, por lo que facilita tratamientos especializados de E/S.

    17

  • 2.2 Componentes Lxicos, Patrones, Lexemas Patrn: es una regla que genera la secuencia de caracteres que puede representar a un determinado componente lxico (una expresin regular).

    Lexema: cadena de caracteres que concuerda con un patrn que describe un componente lxico. Un componente lxico puede tener uno o infinitos lexemas. Por ejemplo: palabras reservadas tienen un nico lexema. Los nmeros y los identificadores tienen infinitos lexemas.

    Ilustracin 2 , Componentes Lxicos, Patrones y Lexemas

    Los componentes lxicos se suelen definir como un tipo enumerado. Se codifican como enteros. Tambin se suele almacenar la cadena de caracteres que se acaba de reconocer (el lexema), que se usar posteriormente para el anlisis semntico.

    TKN_IF, TKN_THEN, TKN_ NUM, TKN_ ID, TNK_ OPADD,...

    Es importante conocer el lexema (para construir la tabla de smbolos). Los componentes lxicos se representan mediante una estructura registro con tipo de token y lexema:

    Ilustracin 3 , Ejemplo componente lxico - lexema

    18

  • 2.3 Expresiones Regulares (especificacin de los componentes lxicos)

    Una expresin regular, a menudo llamada tambin patrn, es una expresin que describe un conjunto de cadenas sin enumerar sus elementos. Por ejemplo, el grupo formado por las cadenas Handel, Hndel y Haendel se describe mediante el patrn "H(a||ae)ndel".

    La mayora de las formalizaciones proporcionan los siguientes constructores: una expresin regular es una forma de representar a los lenguajes regulares (finitos o infinitos) y se construye utilizando caracteres del alfabeto sobre el cual se define el lenguaje. Especficamente, las expresiones regulares se construyen utilizando los operadores unin, concatenacin y clausura de Kleene.

    Los componentes lxicos se especifican haciendo uso de expresiones regulares. Para ello hay que conocer las reglas que rigen la creacin de las expresiones regulares

    Alternacin Una barra vertical separa las alternativas. Por ejemplo, "marrn|castao" casa con marrn o castao.

    Cuantificacin Un cuantificador tras un carcter especifica la frecuencia con la que ste puede ocurrir. Los cuantificadores ms comunes son +, ? y *: + , El signo ms indica que el carcter al que sigue debe aparecer al menos una

    vez. Por ejemplo, "ho+la" describe el conjunto infinito hola, hoola, hooola, hoooola, etctera.

    ? , El signo de interrogacin indica que el carcter al que sigue puede aparecer como mucho una vez. Por ejemplo, "ob?scuro" casa con oscuro y obscuro.

    , El asterisco indica que el carcter que lo precede puede aparecer cero, una, o ms veces. Por ejemplo, "0*42" casa con 42, 042, 0042, 00042, etctera.

    Agrupacin Los parntesis pueden usarse para definir el mbito y precedencia de los dems operadores. Por ejemplo, "(p|m)adre" es lo mismo que "padre|madre", y "(des)?amor" casa con amor y con desamor. Los constructores pueden combinarse libremente dentro de la misma expresin, por lo que "H(ae?|)ndel" equivale a "H(a|ae|)ndel". La sintaxis precisa de las expresiones regulares cambia segn las herramientas y aplicaciones consideradas, y se describe con ms detalle a continuacin. Su utilidad ms obvia es la de describir un conjunto de cadenas, lo que resulta de utilidad en editores de texto y aplicaciones para buscar y manipular textos. Muchos lenguajes de programacin admiten el uso de expresiones regulares con este fin.

    19

  • El Punto "." El punto es interpretado por el motor de bsqueda como cualquier otro carcter excepto los caracteres que representan un salto de lnea, a menos que se le especifique esto al motor de Expresiones Regulares. Por lo tanto si esta opcin se deshabilita en el motor de bsqueda que se utilice, el punto le dir al motor que encuentre cualquier carcter incluyendo los saltos de lnea. En la herramienta EditPad Pro esto se hace por medio de la opcin "punto corresponde a nueva lnea" en las opciones de bsqueda. En .Net Framework se utiliza la opcin RegexOptions. Singleline al efectuar la bsqueda o crear la expresin regular. El punto se utiliza de la siguiente forma: Si se le dice al motor de RegEx que busque "g.t" en la cadena "el gato de piedra en la gtica puerta de getisborogoot" el motor de bsqueda encontrar "gat", "gt" y por ltimo "get". Ntese que el motor de bsqueda no encuentra "goot"; esto es porque el punto representa un solo carcter y nicamente uno. Si es necesario que el motor encuentra tambin la expresin "goot", ser necesario utilizar repeticiones, las cuales se explican ms adelante. Aunque el punto es muy til para encontrar caracteres que no conocemos, es necesario recordar que corresponde a cualquier carcter y que muchas veces esto no es lo que se requiere. Es muy diferente buscar cualquier carcter que buscar cualquier carcter alfanumrico o cualquier dgito o cualquier no-dgito o cualquier no-alfanumrico. Se debe tomar esto en cuenta antes de utilizar el punto y obtener resultados no deseados

    La barra inversa o contrabarra "\" Se utiliza para "marcar" el siguiente carcter de la expresin de bsqueda de forma que este adquiera un significado especial o deje de tenerlo. O sea, la barra inversa no se utiliza nunca por s sola, sino en combinacin con otros caracteres. Al utilizarlo por ejemplo en combinacin con el punto "\." este deja de tener su significado normal y se comporta como un carcter literal. De la misma forma, cuando se coloca la barra inversa seguida de cualquiera de los caracteres especiales que discutiremos a continuacin, estos dejan de tener su significado especial y se convierten en caracteres de bsqueda literal. Como ya se mencion con anterioridad, la barra inversa tambin puede darle significado especial a caracteres que no lo tienen. A continuacin hay una lista de algunas de estas combinaciones:

    20

  • Los corchetes "[ ]" La funcin de los corchetes en el lenguaje de las expresiones regulares es representar "clases de caracteres", o sea, agrupar caracteres en grupos o clases. Son tiles cuando es necesario buscar uno de un grupo de caracteres. Dentro de los corchetes es posible utilizar el guin "-" para especificar rangos de caracteres. Adicionalmente, los metacaracteres pierden su significado y se convierten en literales cuando se encuentran dentro de los corchetes. Por ejemplo, como vimos en la entrega anterior "\d" nos es til para buscar cualquier carcter que represente un dgito. Sin embargo esta denominacin no incluye el punto "." que divide la parte decimal de un nmero. Para buscar cualquier carcter que representa un dgito o un punto podemos utilizar la expresin regular "[\d.]". Como se hizo notar anteriormente, dentro de los corchetes, el punto representa un carcter literal y no un metacarcter, por lo que no es

    Definicin de Expresiones Regular en Herramientas \t Representa un tabulador. \r Representa el "retorno de carro" o "regreso al inicio" o sea el lugar en

    que la lnea vuelve a iniciar. \n Representa la "nueva lnea" el carcter por medio del cual una lnea da

    inicio. Es necesario recordar que en Windows es necesaria una combinacin de \r\n para comenzar una nueva lnea, mientras que en Unix solamente se usa \n.

    \a Representa una "campana" o "beep" que se produce al imprimir este carcter.

    \e Representa la tecla "Esc" o "Escape" \f Representa un salto de pgina \v Representa un tabulador vertical \x Se utiliza para representar caracteres ASCII o ANSI si conoce su cdigo.

    De esta forma, si se busca el smbolo de derechos de autor y la fuente en la que se busca utiliza el conjunto de caracteres Latin-1 es posible encontrarlo utilizando "\xA9".

    \u Se utiliza para representar caracteres Unicode si se conoce su cdigo. "\u00A2" representa el smbolo de centavos. No todos los motores de Expresiones Regulares soportan Unicode. El .Net Framework lo hace, pero el EditPad Pro no, por ejemplo.

    \d Representa un dgito del 0 al 9. \w Representa cualquier carcter alfanumrico. \s Representa un espacio en blanco. \D Representa cualquier carcter que no sea un dgito del 0 al 9. \W Representa cualquier carcter no alfanumrico. \S Representa cualquier carcter que no sea un espacio en blanco. \A Representa el inicio de la cadena. No un carcter sino una posicin. \Z Representa el final de la cadena. No un carcter sino una posicin. \b Marca el inicio y el final de una palabra. \B Marca la posicin entre dos caracteres alfanumricos o dos no-

    alfanumricos.

    21

  • necesario antecederlo con la barra inversa. El nico carcter que es necesario anteceder con la barra inversa dentro de los corchetes es la propia barra inversa. La expresin regular "[\dA-Fa-f]" nos permite encontrar dgitos hexadecimales. Los corchetes nos permiten tambin encontrar palabras an si estn escritas de forma errnea, por ejemplo, la expresin regular "expresi[o]n" permite encontrar en un texto la palabra "expresin" aunque se haya escrito con o sin tilde. Es necesario aclarar que sin importar cuantos caracteres se introduzcan dentro del grupo por medio de los corchetes, el grupo slo le dice al motor de bsqueda que encuentre un solo carcter a la vez, es decir, que "expresi[o]n" no encontrar "expresioon" o "expresion".

    La barra "|" Sirve para indicar una de varias opciones. Por ejemplo, la expresin regular "a|e" encontrar cualquier "a" o "e" dentro del texto. La expresin regular "este|oeste|norte|sur" permitir encontrar cualquiera de los nombres de los puntos cardinales. La barra se utiliza comnmente en conjunto con otros caracteres especiales.

    El signo de dlar "$" Representa el final de la cadena de caracteres o el final de la lnea, si se utiliza el modo multi-lnea. No representa un carcter en especial sino una posicin. Si se utiliza la expresin regular "\.$" el motor encontrar todos los lugares donde un punto finalice la lnea, lo que es til para avanzar entre prrafos.

    El acento circunflejo "^ Este carcter tiene una doble funcionalidad, que difiere cuando se utiliza individualmente y cuando se utiliza en conjunto con otros caracteres especiales. En primer lugar su funcionalidad como carcter individual: el carcter "^" representa el inicio de la cadena (de la misma forma que el signo de dlar "$" representa el final de la cadena). Por tanto, si se utiliza la expresin regular "^[a-z]" el motor encontrar todos los prrafos que den inicio con una letra minscula. Cuando se utiliza en conjunto con los corchetes de la siguiente forma "[^\w ]" permite encontrar cualquier carcter que NO se encuentre dentro del grupo indicado. La expresin indicada permite encontrar, por ejemplo, cualquier carcter que no sea alfanumrico o un espacio, es decir, busca todos los smbolos de puntuacin y dems caracteres especiales. La utilizacin en conjunto de los caracteres especiales "^" y "$" permite realizar validaciones en forma sencilla. Por ejemplo "^\d$" permite asegurar que la cadena a verificar representa un nico dgito, "^\d\d/\d\d/\d\d\d\d$" permite validar una fecha en formato corto, aunque no permite verificar si es una fecha vlida, ya que 99/99/9999 tambin sera vlido en este formato; la validacin completa de una fecha tambin es posible mediante expresiones regulares, como se ejemplifica ms adelante.

    Los parntesis "() De forma similar que los corchetes, los parntesis sirven para agrupar caracteres, sin embargo existen varias diferencias fundamentales entre los grupos establecidos por medio de corchetes y los grupos establecidos por parntesis:

    22

  • Los caracteres especiales conservan su significado dentro de los parntesis. Los grupos establecidos con parntesis establecen una "etiqueta" o "punto de

    referencia" para el motor de bsqueda que puede ser utilizada posteriormente como se denota ms adelante.

    Utilizados en conjunto con la barra "|" permite hacer bsquedas opcionales. Por ejemplo la expresin regular "al (este|oeste|norte|sur) de" permite buscar textos que den indicaciones por medio de puntos cardinales, mientras que la expresin regular "este|oeste|norte|sur" encontrara "este" en la palabra "esteban", no pudiendo cumplir con este propsito.

    Utilizado en conjunto con otros caracteres especiales que se detallan posteriormente, ofrece funcionalidad adicional.

    El signo de interrogacin "?" El signo de pregunta tiene varias funciones dentro del lenguaje de las expresiones regulares. La primera de ellas es especificar que una parte de la bsqueda es opcional. Por ejemplo, la expresin regular "ob?scuridad" permite encontrar tanto "oscuridad" como "obscuridad". En conjunto con los parentesis redondos permite especificar que un conjunto mayor de caracteres es opcional; por ejemplo "Nov(\.|iembre|ember)?" permite encontrar tanto "Nov" como "Nov.", "Noviembre" y "November". Como se mencion anteriormente los parntesis nos permiten establecer un "punto de referencia" para el motor de bsqueda, sin embargo, algunas veces, no se desea utilizarlos con este propsito, como en el ejemplo anterior "Nov(\.|iembre|ember)?". En este caso el establecimiento de este punto de referencia (que se detalla ms adelante) representa una inversin intil de recursos por parte del motor de bsqueda. Para evitar se puede utilizar el signo de pregunta de la siguiente forma: "Nov(?:\.|iembre|ember)?". Aunque el resultado obtenido ser el mismo, el motor de bsqueda no realizar una inversin intil de recursos en este grupo, sino que lo ignorar. Cuando no sea necesario reutilizar el grupo, es aconsejable utilizar este formato. De forma similar, es posible utilizar el signo de pregunta con otro significado: Los parntesis definen grupos "annimos", sin embargo el signo de pregunta en conjunto con los parntesis triangulares "" permite "nombrar" estos grupos de la siguiente forma: "^(?\d\d)/(?\d\d)/(?\d\d\d\d)$"; Con lo cual se le especifica al motor de bsqueda que los primeros dos dgitos encontrados llevarn la etiqueta "Da", los segundos la etiqueta "Mes" y los ltimos cuatro dgitos llevarn la etiqueta "Ao". Nota: a pesar de la complejidad y flexibilidad dada por los caracteres especiales estudiados hasta ahora, en su mayora nos permiten encontrar solamente un carcter a la vez, o un grupo de caracteres a la vez. Los metacaracteres enumerados en adelante permiten establecer repeticiones.

    Las llaves "{} Comnmente las llaves son caracteres literales cuando se utilizan por separado en una expresin regular. Para que adquieran su funcin de metacaracteres es necesario que encierren uno o varios nmeros separados por coma y que estn colocados a la derecha de otra expresin regular de la siguiente forma: "\d{2}" Esta expresin le dice al motor de bsqueda que encuentre dos dgitos contiguos. Utilizando esta frmula podramos convertir el ejemplo "^\d\d/\d\d/\d\d\d\d$" que serva para validar un formato de fecha en "^\d{2}/\d{2}/\d{4}$" para una mayor claridad en la lectura de la expresin.

    23

  • Nota: aunque esta forma de encontrar elementos repetidos es muy til, algunas veces no se conoce con claridad cuantas veces se repite lo que se busca o su grado de repeticin es variable. En estos casos los siguientes metacaracteres son tiles.

    El asterisco "* El asterisco sirve para encontrar algo que se encuentra repetido 0 o ms veces. Por ejemplo, utilizando la expresin "[a-zA-Z]\d*" ser posible encontrar tanto "H" como "H1", "H01", "H100" y "H1000", es decir, una letra seguida de un nmero indefinido de dgitos. Es necesario tener cuidado con el comportamiento del asterisco, ya que este por defecto trata de encontrar la mayor cantidad posible de caracteres que correspondan con el patrn que se busca. De esta forma si se utiliza "\(.*\)" para encontrar cualquier cadena que se encuentre entre parntesis y se lo aplica sobre el texto "Ver (Fig. 1) y (Fig. 2)" se esperara que el motor de bsqueda encuentre los textos "(Fig. 1)" y "(Fig. 2)", sin embargo, debido a esta caracterstica, en su lugar encontrar el texto "(Fig. 1) y (Fig. 2)". Esto sucede porque el asterisco le dice al motor de bsqueda que llene todos los espacios posibles entre dos parntesis. Para obtener el resultado deseado se debe utilizar el asterisco en conjunto con el signo de pregunta de la siguiente forma: "\(.*?\)" Esto es equivalente a decirle al motor de bsqueda que "Encuentre un parntesis de apertura y luego encuentre cualquier carcter repetido hasta que encuentre un parntesis de cierre".

    El signo de suma "+" Se utiliza para encontrar una cadena que se encuentre repetida 1 o ms veces. A diferencia del asterisco, la expresin "[a-zA-Z]\d+" encontrar "H1" pero no encontrar "H". Tambin es posible utilizar este metacarcter en conjunto con el signo de pregunta para limitar hasta donde se efecta la repeticin. Expresiones regulares

    Patrn Significado exp_reg match

    Cadenas

    .

    cualquier carcter excepto EOL ("nueva lnea")

    "." cualquier carcter excepto EOL

    \ carcter especial "\*" "\\"

    "*" "\"

    x un carcter "a "A "2"

    "a" "A" "2"

    xyz varios caracteres "hola" "hola"

    x|y un carcter u "a|b" "a" o "b"

    24

  • otro

    [xyz] un carcter que est en una lista "[aeiou]" una vocal

    [a-z] un carcter que pertenezca a un rango

    "[a-z] [a-zA-Z] "[a-z][A-Z]"

    una minscula una letra una minscula seguida de una mayscula

    [x] cualquier carcter excepto "x"

    "[a]" cualquier carcter excepto "a"

    [xyz] un carcter que no est en una lista

    "[aeiou]" una consonante

    [a-z] un carcter que no pertenezca a un rango

    "[a-z]" una mayscula

    \w

    cualquier carcter alfanumrico incluyendo el guin bajo

    equivale a [a-zA-Z0-9_]

    \W cualquier carcter no alfanumrico

    equivale a [a-zA-Z0-9_]

    \d cualquier dgito equivale a [0-9]

    \D cualquier carcter no dgito

    equivale a [0-9]

    \t tabulador \r retorno de carro \n final de lnea

    \s

    cualquier carcter no visible, como tabulador, retorno o espacio

    \S cualquier carcter visible

    i

    case insensitive, con este modificador no distinguir entre maysculas y minsculas

    "/una/i" busca "una" sin distinguir entre maysculas y minsculas

    25

  • g

    global, este modificador se usa para que no se detenga un proceso de sustitucin al encontrar la primera ocurrencia

    "/a/g" encontrar todas las "a" para sustituirlas

    (xyz)

    recuerda el patrn para su posterior utilizacin con multiplicadores o referencias

    "(x).(ab)" para referencias posteriores "x"=$1 y "ab"=$2

    Anclas: posicin de la cadena

    comienzo de lnea "a" "[aeiou]" "hola"

    "a" al comienzo de una lnea una vocal al comienzo de una lnea "hola" al comienzo de una lnea

    $ final de lnea

    "a$" "[aeiou]$" "hola$" "$"

    "a" al final de una lnea una vocal al final de una lnea "hola" al final de una lnea una lnea vaca

    \b principio o final de una palabra "\bola" "ola" al principio o final de una palabra

    Multiplicadores: cuntas veces ha de aparecer la cadena

    * una cadena cero o ms veces

    "hola*" "hol(as)*" "[a-z]*"

    "hol", "hola", "holaa" "hol", "holas", "holasas" una palabra en minsculas

    + una cadena una o ms veces "hola+" "hol(as)+"

    "hola", "holaa", "holaaa" "holas", "holasas"

    ? una cadena cero o una vez "hola?" "hol(a)?"

    "hol", "hola" "hol", "holas"

    {n} una cadena n veces "a{3}" "(as){3}" "aaa" "asasas"

    {n,m} una cadena entre n y m veces "a{2,4}" "(as){2,4}"

    "aa", "aaa", "aaaa" "asas", "asasas", "asasasas"

    26

  • {n,} una cadena al menos n veces "a{2,}" "(as){2,}"

    "aa", "aaa", "aaaa" "asas", "asasas", "asasasas"

    Algunos Ejemplos Nmeros

    nat = [0-9]+ signedNat = ( +| -)? nat number = signedNat(.nat)? (E signedNat)?

    Identificadores

    letter = [a-zA-Z] digit = [0-9] identifier = letter (letter | digit)*

    Palabras Reservadas

    Tkn_ if = if tkn _while = while tkn _do = do

    2.3.1 Definicin Regular Definicin regular para el conjunto de identificadores que se definen como cadenas de letras y dgitos que comienzan con una letra. A | B | C | | Z | a | b | c | | z 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 (|)* Nmeros sin signo definidos como cadenas de la forma 4500, 34.21, 4.23E4, 1.05444E-2, 45E-23 * 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 . | E ( + | - | ) |

    2.3.2 Cmo reconocemos RE's? La expresiones regulares son tiles para describir strings, pero necesitamos

    reconocerlos. Esta es la diferencia entre conocimiento declarativo (qu es) y conocimiento

    imperativo (cmo hacerlo). As que usamos expresiones regulares para describir los strings, pero usamos

    autmatas finitos para reconocerlos.

    27

  • 2.3.3 Tratamiento de errores Nombre ilegales de identificadores: Un nombre que contiene un carcter invlido. Nmeros incorrectos: un numero que contiene caracteres invlidos o no est

    formado correctamente [3.14 en vez de 3,14 o 0.3.14]. Errores de ortografa en palabras reservadas: Caracteres omitidos, adicionales o

    cambiados de sitio, por ejemplo la palabra hwile en vez while. Fin de archivo: Se detecta el fin de un archivo a mitad de un componente lxico.

    Ejemplos

    a) Sea el vocabulario {a,b} y la expresin regular aa*bb*. Indicar el lenguaje que denota, y algunas cadenas de dicho lenguaje. Solucin: Algunas cadenas son:

    ab aab aaaab abbbb abb aaaab

    El lenguaje que se describe es L={cadenas que comienzan por una a y continan con varias o ninguna a, y siguen con una b y continuan con varias o ninguna b}

    b) Sea el vocabulario {0,1}, la expresin regular 1(01)*denota el conjunto de cadenas que empiezan por 1 y van seguidas por (01) cualquier n de veces o ninguna.

    c) Dada la expresin regular (a | b)*, el lenguaje que denota es el que se puede forma

    con todas las cadenas compuestas por a y b incluida la cadena vacia. Algunos ejemplos de sentencias de este lenguaje son :

    aaa bbb aba abaaa abbaa

    2.3.4 Ejercicios Simplificar las expresiones regulares:

    a) (01 | 10 | 0110 | 1001)* b) (0(0 | 1)*)+

    Encontrar una expresin regular correspondiente a cada uno delos siguientes subconjuntos de {0, 1}*

    28

  • a) El lenguaje de las cadenas que contienen exactamente dos 0s. b) El lenguaje de las cadenas que contienen al menos dos 0s. c) El lenguaje de las cadenas que no terminan con 01. d) El lenguaje de las cadenas que comienzan o terminan con 00 o 11.

    Encontrar una expresin regular correspondiente al lenguaje: ({ab, aab, abaabb}* U {abbba}){abb}{b, baa}*

    Considere las dos expresiones regulares: R1 = a* | b* y R2 = ab* | ba* | b*a | (a*b)*

    a) Encontrar una cadena correspondiente a R1 pero no a R2. b) Encontrar una cadena correspondiente a R2 pero no a R1. c) Encontrar una cadena correspondiente tanto a R1 como a R2.

    29

  • 2.4 Autmatas Un autmata es una construccin lgica que recibe una entrada y produce una salida en funcin de todo lo recibido hasta ese instante.

    En el caso de los Procesadores de Lenguaje un autmata es una construccin lgica que recibe como entrada una cadena de smbolos y produce una salida indicando si dicha cadena pertenece o no a un determinado lenguaje.

    2.4.1 Definicin formal de autmata Un autmata es una quntupla A = ( E, S, Q, f, g ) donde :

    E = {conjunto de entradas o vocabulario de entrada} S = {conjunto de salidas o vocabulario de salida} Q = {conjunto de estados} f: E X Q Q g: E X Q S

    E es un conjunto finito, y sus elementos se llaman entradas o smbolos de entrada. S es un conjunto finito, y sus elementos se llaman salidas o smbolos de salida. Q es el conjunto de estados posibles, puede ser finito o infinito. f es la funcin de transicin o funcin del estado siguiente, y para un par del

    conjunto E Q devuelve un estado perteneciente al conjunto Q. E Q es el conjunto producto

    cartesiano de E por Q. g es la funcin de salida, y para un par del conjunto E Q, devuelve un smbolo de

    salida del conjunto S.

    2.4.2 Representacin de autmatas Los autmatas se pueden representar mediante:

    - Tabla de transiciones - Diagrama de Moore

    2.4.2.1 Tabla de transiciones Las funciones f y g pueden representarse mediante una tabla, con tantas filas como estados y tantas columnas como entradas. As por ejemplo se puede representar el autmata A = ( E, S, Q, f, g ) donde E = {a,b}, S = {0,1}, Q = {q1, q2, q3} y las funciones f y g se pueden representar por :

    30

  • Ilustracin 4 , Tabla de transiciones - Autmatas

    2.4.2.2 Diagramas de Moore Los diagramas de Moore son otra forma de representar las funciones de transicin y salida de un autmata. El diagrama de Moore es un grafo orientado en el que cada nodo corresponde a un estado

    Ilustracin 5 , Diagrama de Moore - Autmatas

    A continuacin de muestra 2 ejemplos de autmatas para poder reconocer la palabra reservada IF y el nombre de un identificador:

    31

  • Ms ejemplos

    32

  • 2.4.3 Lenguaje Generado El lenguaje generado se obtiene partiendo del estado inicial y recorriendo todos los caminos posibles para alcanzar el estado final. As se obtiene que este autmata reconoce el lenguaje :

    LA1 = abaababbbaabb La expresin regular que denota el lenguaje es a+b+ o tambin aa*bb*. L(A1) = {anbm/n 1m 1}

    2.4.4 Ejemplo completo (diagrama de transiciones diagrama de moore)

    Construir el diagrama de Moore, y determinar el lenguaje que reconoce, denotndolocon su expresin regular.

    33

  • Solucin: Se construye el diagrama de Moore de forma anloga al ejemplo anterior

    2.4.5 Cmo transformamos una expresin regular en un autmata?

    Para expresiones regulares M y N

    34

  • 2.4.6 Equivalencia entre expresiones regulares bsicas y autmatas finitos Se muestran equivalencias entre expresiones regulares simples y autmatas finitos expresados mediante un diagrama de Moore

    Expresin regular

    35

  • Expresin regular a

    Expresin regular a*

    Expresin regular a+

    Expresin regular a b

    36

  • Expresin regular (a b)*

    Expresin regular (ac b)*

    Expresin regular (acd b)*

    37

  • 38

  • 39

  • 40

  • 41

  • 42

  • String matching

    43

  • 44

  • 45

  • Autmata finito no determinista Un autmata finito no determinista (abreviado AFND) es un autmata finito que, a diferencia de los autmatas finitos deterministas (AFD), posee al menos un estado q Q, tal que para un smbolo a del alfabeto, existe ms de una transicin (q,a) posible.

    Autmata finito determinista Un autmata finito determinista (abreviado AFD) es un autmata finito que adems es un sistema determinista; es decir, para cada estado en que se encuentre el autmata, y con cualquier smbolo del alfabeto ledo, existe siempre a lo ms una transicin posible desde ese estado y con ese smbolo.

    Conversin de un AFND a AFD Tomando en cuenta el siguiente autmata

    46

  • Cuya tabla de transicin es la siguiente

    a b {q0} {q0} {q0,q1} {q1} {q1}

    Con ello nos aseguramos que es un AFND , dado que tomando en cuenta que estamos en el estado q0 y teniendo como entrada b llegamos a los estado {qo,q1} a la vez por ello sabemos que se trata de un AFND.

    Para poder eliminar esa ambigedad (convertir un AFND a AFD ) , iniciamos en el estado inicial q0 y elaboramos la nueva tabla de transicin :

    Observando el autmata dado inicialmente, estamos en el estado q0 e ingresa a nos lleva al estado q0 , pero si ingresa b nos lleva a q0 y q1 a la vez

    a b {q0} {q0} {q0,q1}

    Con esta porcin de tabla de transicin elaborada nos damos cuenta que ha aparecido un nuevo estado {q0,q1} , por ello colocamos en el lugar de los estado a este estado encontrado.

    a b q0 {q0} {q0,q1} {q0,q1} {q0} {q0,q1}

    Comenzando en el estado inicial {q0,q1} habiendo ingresado a llegamos al estado {q0} , habiendo ingresado b llegamos al estado {q0,q1} .

    No habiendo ms estados nuevos, aqu termina la elaboracin de tabla de transicin solo nos queda el remplazo de los estados encontrado por otros estados equivalentes ms fciles de representar.

    a b 1 1 2 2 1 2

    1 2

    a

    ba b

    Tenemos el siguiente AFND 47

  • Cuya solucin es la siguiente

    Que tenemos hasta ahora

    Expresiones regulares proporcionan un lenguaje formal para definir los tokens. Podemos convertir fcilmente las expresiones regulares a NDFA's. Pero los NDFA's no son nada sencillos de implementar. Tienen que adivinar!

    48

  • Ejercicios 1. Sea M = (Q, , , q0, F) un AFD con Q = {q0 ,q1 ,q2 }, = {a, b}, F = {q2} y la

    funcin de transicin :

    a) Dibuja el autmata M b) Traza los cmputos de M que procesan las palabras abaa, bbbabb, babababbbaa c) Qu palabras de las procesadas en (b) son aceptadas por M?

    2. Busca tres palabras aceptadas y tres palabras rechazadas por cada uno de los siguientes autmatas mostrando el cmputo que las procesa. Determina cules de ellos estn totalmente especificados. Sabras cul es el lenguaje aceptado por cada uno de ellos?

    49

  • 3. Construye AFDs que acepten cada uno de los siguientes lenguajes definidos sobre el alfabeto = {a,b}:

    a ) L = { x * : la longitud de x es divisible por 3}

    b ) L = { x *: aba no es subpalabra de x }

    c ) L = { x * : x comienza por a y termina por ab }

    d ) L = { x * : x tiene un nmero par de a's y un nmero par de b's }

    e ) L = { x * : x tiene tres a's consecutivas }

    f ) L = { x * : toda aparicin de la subpalabra aba en x, o bien va seguida de bb, o est al final de la palabra }

    g ) L = { x * : si x empieza por a no contiene la subpalabra aa y si x empieza por b contiene la subpalabra aa }

    h ) L = { x * : x tiene un nmero par de apariciones de la cadena ab }

    50

  • i ) L = { x * : ab es subpalabra de x si y slo si ba es subpalabra de x }

    j ) L = { x * : x est formada por la concatenacin de un nmero arbitrario de cadenas de la forma yyR , con |y|=2 }

    k ) L = { x * : x no contiene ningn prefijo en el que la diferencia entre el nmero de a's y b's sea mayor que tres (a favor de cualquiera de ellos) }

    4. Construye AFD's equivalentes a los siguientes AFND's:

    5. Construye AFD's equivalentes a los siguientes -AFND's:

    51

  • 3. Analizador Sintctico Antes de continuar veamos algunas tems importantes del analizador lxico (expresiones regulares, gramticas y lenguajes)

    Una expresin regular puede ser escrita usando:

    Caracteres en el alfabeto

    Operadores de expresiones regulares: * | + ? ( )

    Ejemplo: (-| ) (0|1|2|3|4|5|6|7|8|9)+ (. (0|1|2|3|4|5|6|7|8|9)*)?

    Un lenguaje regular es un lenguaje definido por una expresin regular

    Qu hay acerca de las variables simblicas?

    Ejemplo: num = 0|1|2|3|4|5|6|7|8|9 posint = num num* int = ( | -) posint real = int ( | (. posint))

    Slo son una abreviacin, llamada syntactic sugar

    Ejemplo: (-| ) (0|1|2|3|4|5|6|7|8|9)+ (. (0|1|2|3|4|5|6|7|8|9)*)?

    Resumen del analizador lexico

    El analizador lxico crea tokens a partir de un character stream

    Los tokens se definen usando expresiones regulares

    Las expresiones regulares pueden mapearse a un Autmata Finito No Determinstico (NFA)

    Por construccin simple

    NFA se transforma a un DFA

    Algoritmo de transformacin

    Ejecutar un DFA es fcil

    52

  • 3.1 Sintaxis y Semntica de un Lenguaje de Programacin? Sintaxis

    Como se ve un programa

    Representacin textual o estructura

    Es posible una definicin matemtica precisa

    Semntica

    Cul es el significado de un programa

    Es ms difcil dar una definicin matemtica

    3.2 Por qu hacer anlisis sintctico? Podemos proveer una definicin precisa y fcil de entender

    Una gramtica apropiada imparte estructura a un lenguaje de programacin

    Podemos construir automticamente un parser que determine si el programa es sintcticamente correcto

    Ayuda en el proceso de traduccin

    Fcil modificar/aadir al lenguaje

    3.3 Anatoma de un Compilador Analizador Sintctico

    Optimizador de Cdigo

    Generador de CdigoRepresentacin Intermedia Optimizada

    Cdigo en Assembler

    Generador de Cdigo IntermedioRepresentacin Intermedia

    Analizador Lxico (Scanner)

    Analizador Sintctico (Parser)Token Stream

    Arbol de Parseo

    Programa (character stream)

    53

  • 3.4 Funciones del analizador sintctico: Comprobar si la cadena de componentes lxicos proporcionada por el analizador

    lxico puede ser generada por la gramtica que define el lenguaje fuente (Gramtica Independiente del Contexto, GIC).

    Construir el rbol de anlisis sintctico que define la estructura jerrquica de un programa y obtener la serie de derivaciones para generar la cadena de componentes lxicos. El rbol sintctico se utilizara como representacin intermedia en la generacin de cdigo.

    Informar de los errores sintcticos de forma precisa y significativa y debera estar dotado de un mecanismo de recuperacin de errores para continuar con el anlisis.

    Ilustracin 6 , Analizador Sintctico

    El anlisis sintctico se puede considerar como una funcin que toma como entrada la secuencia de componentes lxicos producida por el anlisis lxico y produce como salida el rbol sintctico.

    En la realidad, el anlisis sintctico hace una peticin al anlisis lxico del componente lxico siguiente en la entrada (los smbolos terminales) conforme lo va necesitando en el proceso de anlisis, conforme se mueve a lo largo de la gramtica.

    3.5 Reconocedor versus analizador sintctico

    Un reconocedor trata de determinar simplemente si la cadena puede o no ser generada por la gramtica (salida boolena). Podramos preguntar algo ms. Si queremos reconocer las estructuras propias de los lenguajes de programacin en el fichero de entrada para

    54

  • guiar la traduccin, es necesario conocer su estructura jerrquica, el rbol de anlisis sintctico.

    3.6 Especificacin sintctica de los lenguajes de programacin La mayora de las construcciones de los lenguajes de programacin se pueden representar con una gramtica independiente del contexto (GIC). La mayora de las construcciones de los lenguajes de programacin implica recursividad y anidamientos.

    G = {S, VT , VNT , P}

    S: el axioma o smbolo de inicio VT : conjunto de terminales, los componentes lxicos VNT : conjunto de no-terminales P: conjunto de reglas de produccin de la forma VNT X1; : : : ;Xn; con Xi pertenece (VT U VNT )

    Expresiones regulares o gramticas independientes del contexto? Las expresiones regulares no permiten construcciones anidadas tan comunes en los lenguajes de programacin: parntesis equilibrados, concordancia de pares de palabras clave como begin-end, do-while, ... Por ejemplo: consideremos el problema de los parntesis equilibrados en una expresin aritmtica. El hecho de que haya un parntesis abierto obliga a que haya un parntesis cerrado. Este problema es similar a considerar el lenguaje

    L = {aba; aabaa; aaabaaa; : : : ; } = {anban

  • 3.7 Como convertir Expresiones Regulares a CFGs Considere la siguiente expresin regular:

    01+10(11)* Queremos convertir una gramtica regular con las reglas de la forma V w, donde V es un no terminal y w es una cadena de terminales /no terminales. Para comenzar, usted puede simplemente mezclar CFG y la sintaxis de expresiones regulares. Entonces comenzamos usando un no terminal

    -> 01+10(11)* Donde S es el smbolo inicial. Ahora vamos a romper un poco(y aadir espacios en blanco para mayor claridad):

    -> 0 1 0 -> 1+ -> (11)*

    La clave est en convertir *s y +s en recursivas. En primer lugar, vamos a convertir a el asterisco a un + insertando una regla intermediaria que acepta cadenas vacas:

    -> 0 1 0 -> 1+ -> () -> -> (11)+

    Finalmente, convertiremos el + en una recursin:

    -> 0 1 0 -> 1 -> 1 -> (empty) -> -> 11 -> 11

    Al final optemos lo siguiente:

    01+10(11)*

    -> 0 1 0 -> 1 -> 1 -> (empty) -> -> 11 -> 11

    56

  • Ejercicios Convertir las siguientes ER en CFGs

    a) (a|b)* b) xy*a+ c) (ab)+c?

    57

  • 3.8 Definiendo Context-Free Grammars (CFGs) Terminales (VT): Smbolos para strings o tokens

    No terminales (VNT ): Variables sintcticas

    Smbolo de Inicio(S ) : Un no-terminal especial es designado

    Producciones ( P )

    La forma en que los terminales y no-terminales son combinados para formar strings Un no-terminal en el lado izquierdo (LHS) y un string de terminales y no-terminales en el

    lado derecho (RHS)

    Teniendo en cuenta todos los elementos que componen una CFGs (Gramticas libres de contexto) hace posible la creacin de arboles de derivacin que proporcionan una herramienta para hacer posible la creacin de arboles de analizador sintctico (Parser).

    La interseccin entre el vocabulario terminal y no terminal es el conjunto vaco:

    {VN} {VT} = {vaco}

    La unin entre el vocabulario terminal y no terminal es el vocabulario:

    {VN} U {VT} = {V}

    En ocasiones es importante distinguir si un determinado vocabulario incluye o no la cadena vaca, indicndose respectivamente con superndice + o superndice *, tal como se muestra a continuacin:

    V+ = V {}

    V* = V + {}

    Por ejemplo para la gramtica:

    E --> id | num | E + E | ( E ) | - E

    Donde podemos reconocer los siguientes elementos que componen la gramtica:

    Smbolo de inicio: E

    No Terminales: E

    Terminales: id , num , + , ( , ) , -

    Producciones:

    58

  • E id E num E E + E E ( E ) E - E

    Otro ejemplo

    1. ( ) |

    2. ( )

    En este punto podemos definir algunos elementos terminales como lo son : (,), ; porque estos smbolos no pueden llevarnos a crear produccin alguna.

    Y tambin nos pueden dar los elementos no terminales como es .

    Definiendo todo junto

    ( )

    ( )

    Elemento de inicio

    ( )

    Los lenguajes regulares son un subconjunto de los lenguajes libres de contexto Expresin Regular Gramtica libre de contexto

    a a

    Elementos terminales VT

    Elementos no terminales VNT

    Producciones encontradas, 2

    59

  • Si p y q son expresiones regulares, usando CFGs y

    p q

    p | q

    p *

    Si p es una expresin regular, usando una CFG ,

    Qu es?

    ???

    P? ???

    Ejemplo 1

    Aqu hay una gramtica libre de contexto para expresiones enteras algebraicas sintcticamente correctas sobre las variables x, y y z:

    S x | y | z | S + S | S - S | S *S | S/S | (S)

    Generara, por ejemplo, la cadena (x + y) *x - z *y / (x + x)

    Ejemplo 2

    1) Sea la gramtica: G = ( VT, VN, S, P) donde VT = {a, b}, VN = {S}, y el conjunto de producciones es:

    S ab S aSb

    2) Sea la gramtica G = (VN, VT, S, P) donde :

    VN = { , } VT = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } S =

    Las reglas de produccin P son :

    ->

    60

  • -> -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

    Entonces por qu usar expresiones regulares?

    Separar el anlisis sintctico en partes lxica y no-lxica es una buena modularizacin

    Las reglas lxicas son simples y pueden ser expresadas usando expresiones regulares

    Las expresiones regulares son ms concisas Las implementaciones de analizadores lxicos para expresiones regulares son

    ms eficientes

    Creando una CFG

    Tenemos que crear una CFG a partir de las definiciones del lenguaje, identificando cada uno de los elementos que componen la gramtica a partir del lenguaje proporcionado.

    Ejemplo: Una CFG para expresiones

    Expresiones aritmticas simples con + y *

    8.2 + 35.6 8.32 + 86 * 45.3 (6.001 + 6.004) * (6.035 * -(6.042 + 6.046))

    Terminales (o tokens)

    num para todos los nmeros plus_op (+), minus_op (-), times_op(*), left_paren_op((),

    right_paren_op()) Cul es la gramtica para todas las expresiones posibles?

    Identificando Terminales

    ( ) - num + *

    ( ) - num + *

    61

  • Identificando No Terminales , smbolo de inicio

    Producciones

    Al final podemos rescribir, de esta manera

    Pregunta: Cul es el lenguaje definido por esta CFG?

    aa | aa

    ( ) - num + *

    ( )

    -

    num

    +

    *

    Producciones

    | ( ) | - | num

    + | *

    62

  • 3.9 Definicin del lenguaje Sea la gramtica G6 = ({S,A,B}, {a,b}, S, P) donde las producciones P son :

    S aB A bAA S bA B b A a BbS A aS B aBB

    Determinar el lenguaje que genera.

    Solucin : Se generan algunas instrucciones.

    S aB ab S bA ba S aB abS abbA abba S bA bbAA bbaa S aB abS abaB ababS ababaB ababab

    L(G6) = {cadenas que tienen igual n de a que de b}

    3.10 Derivaciones. Arboles de analizador sintctico Cmo mostramos que una secuencia de tokens es aceptada por una CFG?

    Una produccin es usada para derivar una secuencia de tokens a partir del smbolo de inicio

    Dados los strings , y y una produccin A b

    Un solo paso de la derivacin es A

    Por ejemplo para la gramtica:

    E id | num | E + E | ( E ) | - E

    Si queremos derivar la frase -(id + id)

    E -E -(E + E) -(id + E) - (id + id)

    Ejemplo de Derivacin

    Gramtica

    | () | - | num + | * Entrada 36 * ( 8 + 23.4)

    63

  • Token Stream num * ( num + num )

    3.11 Arboles de anlisis sintctico (rbol de parseo) Un rbol de anlisis sintctico indica como a partir del axioma de la gramtica se deriva una frase (cadena) del lenguaje. Dada una gramtica independiente del contexto, un rbol de anlisis sintctico es un rbol tal que:

    1. La raz est etiquetada con el smbolo inicial.

    2. Cada hoja est etiquetada con un componente lxico. Las hojas de izquierda a derecha forman la frase (el programa fuente).

    3. Cada nodo interior est etiquetado con un no-terminal.

    4. Si A es un no-terminal y X1;X2; : : : ;Xn son sus hijos de izquierda a derecha, entonces existe la produccin A X1;X2; : : : ;Xn, con Xi pertenece (VT U VNT ).

    El rbol de anlisis sintctico contiene en general mucha ms informacin que la estrictamente necesaria para generar el cdigo.

    Se puede construir una estructura ms sencilla, los arboles abstractos de anlisis sintctico. Ejemplo: expresiones aritmticas (igual semntica, menor complejidad)

    num num * num * ( ) num * ( ) num * ( num ) num * ( num + ) num * ( num + num ) num * ( num + num )

    64

  • Otro ejemplo

    Derivaciones left-most (mas a la izquierda) vs. right-most (mas a la derecha) Por ejemplo para la gramtica:

    E id | num | E + E | ( E ) | - E

    Si queremos derivar la frase -(id + id)

    E -E -(E + E) -(id + E) - (id + id)

    Derivacin ms a la izquierda.

    num * ( num + num )

    num num

    ( )*num

    65

  • E -E -(E + E) -(E + id) -(id + id)

    Derivacin ms a la derecha.

    Otro ejemplo de right-most

    String: num * ( num + num )

    ( ) ( ) ( num ) ( + num ) ( num + num ) * ( num + num ) num * ( num + num )

    Top-down vs. Bottom-up Parsing Normalmente escaneamos de izquierda a derecha Left-most derivation refleja top-down parsing

    Comenzamos con el smbolo inicial Terminamos con el string de tokens

    Top-down Parsing

    Left-most derivation

    num num * num * ( ) num * ( ) num * ( num ) num * ( num + ) num * ( num + num )

    Top-down vs. Bottom-up Parsing

    Normalmente escaneamos de izquierda a derecha Left-most derivation refleja top-down parsing

    Comenzamos con el smbolo inicial Terminamos con el string de tokens

    Right-most derivation refleja bottom-up parsing Comenzamos con el string de tokens

    66

  • Terminamos con el smbolo inicial

    Right-most derivation

    num * ( num + num ) * ( num + num ) ( num + num ) ( + num ) ( num ) ( ) ( )

    3.12 Gramticas ambiguas Una gramtica es ambigua cuando para una determinada sentencia produce ms de un rbol de derivacin.

    La gramtica siguiente es ambigua:

    E id | num | E + E | E * E | ( E ) | - E

    Supongamos la sentencia id + id * id

    Podriamos obtener : 124 + (23.5 * 86) = 2145 (124 + 23.5) * 86 = 12685 , pero cual seria la respuesta correcta para la operacin planteada?

    El significado semntico es DIFERENTE. No existe una nica traduccin posible. Se genera cdigo diferente. No existe un algoritmo que determine con certeza en un plazo finito de tiempo si una gramtica es ambigua o no. A lo sumo que se ha llegado en el estudio de la ambigedad es que hay algunas condiciones que de cumplirse determinan la ambigedad, pero en el caso de no cumplirse no se puede decir que la gramtica es no ambigua. Necesidad de evitar las gramticas ambiguas. Cmo? transformando la gramtica o estableciendo precedencias entre operadores y de asociatividad.

    67

  • Se puede eliminar la ambigedad transformando la gramtica agrupando todos los operadores de igual precedencia en grupos y asociando a cada uno una regla, de forma que los que tengan menor precedencia aparezcan ms cercanos al simbolo de inicio, precedencia en cascada. Esto conlleva el aumento de la complejidad de la gramtica y con ello en la del rbol sintctico. La gramtica deja de ser intuitiva. Ejemplo 1: gramtica ambigua E num | E + E | E - E | E * E | E / E Si la transformamos, esta gramatica ya no es ambigua. Exp exp + term | exp - term | term term term * factor | term / factor | factor factor ( exp ) | num

    Eliminacin de gramticas ambiguas Eliminar la ambigedad en una gramtica requiere de un proceso de anlisis propio de cada gramtica que verifique que para ninguna palabra que esta genera se puedan generar ms de un rbol de derivacin.

    En algunos casos, la ambigedad de una gramtica se puede eliminar utilizando nuevas variables que eliminen los rboles de derivacin no deseados.

    Tambin existen los lenguajes inherentemente ambiguos para los que no existe una gramtica no ambigua equivalente.

    E E + E E E * E E id E num E -E E (E)

    Comprobamos que esta gramatica es ambigua .

    Es ambigua porque la cadena id + num * id tiene dos rboles de derivacin:

    rbol izquierdo representa (id + num) * id

    rbol de la derecha representa id + (num * id).

    68

  • En el ejemplo de los operadores aritmticos, adems de la variable E, que representa expresiones, tambin se utilizan las variables F para factores y T para trminos y se tienen las siguientes reglas:

    E E + T T T * F F (E) F id E T T F T -F F num

    Ejercicios 1. Para la gramtica Gcuyas producciones son

    describa al lenguaje generado por G. 2. Dada la siguiente gramtica, escribe la derivacin ms a la izquierda, el rbol de

    anlisis sintctico y el rbol sintctico abstracto para las siguientes expresiones: (a) 3+4*5-6; (b) 3*(4-5+6)

    exp exp addop term j term addop + | - term term mulop factor j factor mulop * | / factor ( exp ) j num

    3. Escribe una gramtica para expresiones booleanas que incluya las constantes true y false, los operadores and,or y not y los parntesis. Se ha de tener en cuenta que el operador or tiene menor precedencia que el operador and y este menor que el operador not. Construye la gramatica de forma que los operadores and y or sean asociativos por la izquierda y el operador not por la derecha.

    69

  • 4. Anlisis Semntico y Chequeo de Tipos 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 jerrquica 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 operandos 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, la especificacin del lenguaje puede imponer restricciones a los operandos, por ejemplo, cuando un operador aritmtico binario se aplica a un nmero entero y a un nmero real. Revisa que los arreglos tengan definido el tamao correcto.

    Dnde estamos?

    Qu es la semntica de un programa?

    Sintxis

    Analizador Lxico (Scanner)

    Analizador Sintctico (Parser)Token Stream

    Arbol de Parseo

    Programa (character stream)

    Analizador SemnticoGenerador de Cdigo Intermedio

    Representacin Intermedia + Tabla de Smbolos

    70

  • Cmo se ve un programa

    Representacin textual o estructura

    Es posible dar una definicin matemtica precisa

    Semntica

    Cul es el significado del programa

    Es ms difcil dar una definicin matemtica precisa

    El analisis semantico incluye:

    La construccion de la Tabla de Simbolos para llevar un seguimiento del signicado de los identicadores en el programa (variables, funciones, tipos, parametros y metodo de paso de parametros en funciones, etc)

    Realizar la comprobacion e inferencia de tipos en expresiones y sentencias (por ejemplo, que ambos lados de una asignacion tengan tipos adecuados, que no se declaren variables con el mismo nombre, que los parametros de llamada a una funcin tengan tipos adecuados, numero de parametros correcto, )

    Nos centraremos en el analisis semantico estatico: se realiza en tiempo de compilacion, no de ejecucion.

    Como vamos a implementar la estructura semntica de un lenguaje?

    A partir de la construccion del arbol de anlisis sintctico, lo recorreremos en un determinado orden y calcularemos en cada nodo la informacion semantica necesaria (el valor de una expresin, el tipo de una variable, su ambito de declaracin, el nmero de argumentos de una funcin, etc).

    Conceptualmente, se analiza sintacticamente la cadena de componentes lexicos de entrada, se construye el rbol de anlisis sintctico y despus se recorre el rbol, en un determinado orden para tener en cuenta las dependencias, para evaluar las reglas semanticas en sus nodos.

    71

  • Por qu hacer anlisis semntico

    Asegurarnos que el programa cumple con la definicin del lenguaje de programacin

    Proveer mensajes de error tiles al usuario

    4.1 Atributos y gramaticas de atributos Un atributo es cualquier propiedad de una construccion de un lenguaje de programacion. Varan en funcion del tipo de informacin que contienen, su complejidad de calculo y el momento en el que son calculados (en tiempo de compilacion (atributos est aticos) o de ejecucin (dinmicos)).

    Ejemplos tpicos son:

    el nombre de una variable

    el tipo de una variable

    el ambito de una variable

    el valor de una expresion

    el numero de argumentos de una funcin

    la posicion en memoria de una variable

    un fragmento de codigo

    Ejemplos de atributos que se calculan en tiempo de compilacion: el tipo de dato, el nombre de una variable, el codigo de un procedimiento.

    Ejemplos de atributos que se calculan en tiempo de ejecucion: la posicin de una variable, el valor de una expresion. Aunque algunas expresiones son constante y se pueden calcular en tiempo de compilacion (clculo previo de constantes), por ejemplo print(%d, 3+4*2);.

    Nos centraremos en el analisis semntico esttico (construccin de la Tabla de Smbolos y comprobaciones e inferencia de tipos), ya que el dinamico depende de la arquitectura de la maquina, del sistema operativo (control de ejecucion, gestin de la memoria, llamadas a funciones, etc)

    Se llama enlace (binding) al proceso de calcular el valor del atributo y asociarlo a su correspondiente construccion lingstica. Puede ser enlace dinamico o esttico segn el momento en que se calcule.

    72

  • Una gramatica de atributos es una generalizacion de una gramtica independiente del contexto en la que cada smbolo gramatical (terminal o no-terminal) tiene asociado un conjunto de atributos.

    Las gramaticas de atributos se suelen escribir en forma tabular, con una parte donde aparecen las producciones y otra donde aparecen las reglas semanticas (o ecuaciones de atributos) que permiten calcular los atributos.

    Ejemplo 1. Consideremos la gramatica para la generacin de expresiones ritmeticas simples: Qu atributos nos interesan en esta gramtica?

    El valor numerico de la expresin. Lo denotaremos por val

    Las reglas semanticas para el clculo de este atributo seran:

    Nota: Si un smbolo aparece mas de una vez en una produccin, entonces cada aparicion debe ser distinguida de las otras apariciones, para que los diferentes valores de las ocurrencias sean distinguidos.

    73

  • Los atributos se colocan al lado de los nodos del arbol de anlisis sintctico y se dibujan las dependencias entre ellos. Una echa que va desde los atributos que aparecen en la parte derecha de la ecuacion hacia el del lado izquierdo. Por ejemplo, para la entrada (4-3)*2, el arbol sera:

    Ejemplo 2. La gramatica para la declaracin de variables en C. Qu atributos nos interesan en esta gramatica?

    Las reglas semanticas para el clculo de este atributo seran: Para la entrada float x,y, el arbol de anlisis sintctico con los atributos es:

    74

  • 4.2 La Tabla de Smbolos La Tabla de Smbolos es despues del rbol de anlisis sintctico la principal estructura de datos de un compilador. La Tabla de Smbolos interacciona con el analizador lexico y con el analizador sintctico, a pesar que hemos retrasado su introduccion hasta ahora. Ambos introducen informacin o necesitan consultarla durante todo el proceso de la compilacion. Tambininteracciona con el analisis semntico, como en la comprobacin de tipo y con el modulo de generacin de cdigo (direccin de memoria, tipo de variable y tipo de operacion a realizar...).

    Un lugar para guardar toda la informacin adicional acerca del programa

    Representaciones intermedias: expresiones, statements, control de flujo, etc.

    Tabla de Smbolos: Tipos, variables, scope, etc.

    75

  • Scope (mbito - alcance)

    Un nombre puede tener significados distintos en lugares distintos

    Tipos, variables, etc tiene scope (mbito)

    Tenemos que mantener una tabla de smbolos para cada scope

    El compilador utiliza la Tabla de Smbolos para llevar un seguimiento de los identicadores (variables, funciones, tipos) que aparecen en el programa fuente. Se examina la Tabla de Smbolos cada vez que se encuentra un identicador. Operaciones de consulta, insercion y borrado con bastante frecuencia.

    insercion: introduccion de la informacin de declaraciones de constantes, variables, funciones y tipos.

    busqueda: para obtener informacion de un identicador (su nombre, tipo, ambito, ..) cuando aparece a lo largo del programa.

    borrado: eliminacion de declaraciones (de constantes, variables, funciones o tipos) cuando nos salimos del ambito en que se aplican.

    Operaciones en la tabla de simbolos

    make_table(parent_table) symbol_table // crear la tabla

    scope(id) symbol_table // alcance de ID

    lookup_variable(id, symbol_table) variable // buscar variable ID en la tabla

    lookup_type(id, symbol_table) type // buscar tipo de la variable ID en la tabla

    get_type(variable) type // obtener el tipo de la variable

    add_type(id, symbol_table, type) type // adicionar tipo de ID en la tabla

    add_variable(id, symbol_table, type) variable // adicionar variable ID en la tabla incluyendo tipo

    Tabla de smbolos en lenguaje C Como ya se dijo en el esbozo la tabla de smbolos es una estructura de datos que se crea en tiempo de traduccin del programa fuente. Es como un diccionario variable, debe darle apoyo a la insercin, bsqueda y cancelacin de nombres (identificadores) con sus atributos asociados, representando las vinculaciones con las declaraciones. Debe

    76

  • aclararse que no necesariamente deber estar representada en una tabla como su nombre indica ya que tambin se emplean rboles, pilas , etc.

    Los smbolos se guardan en la tabla con su nombre y una serie de atributos opcionales que dependern del lenguaje y de los objetivos del procesador, este conjunto de atributos almacenados se denominan registro de la tabla de smbolos.

    La siguiente representa una serie de atributos que no es necesaria para todos los compiladores, sin embargo cada uno de ellos se puede utilizar en la implementacin de un compilador particular.

    nombre del identificador.

    direccin en tiempo de ejecucin a partir del cual se almacenara el identificador si es una variable.

    tipo del identificador. Si es una funcin el tipo que devuelve la funcin.

    nmero de dimensiones del array (arreglo), o nmero de miembros de una estructura o clase, o nmeros de parmetros si se trata de una funcin.

    tamao mximo o rango de cada una de las dimensiones de los array, si tiene dimension estatica.

    etc..

    Ilustracin 7 , Ejemplo de tabla de smbolos

    4.3 Chequeos de Control de Flujo El control de flujo del programa es sensitivo al contexto

    Ejemplos:

    Declaracin de una variable debe ser visible al usarla (en scope)

    Declaracin de una variable debe estar antes de usarla

    Cada camino de salida (exit path) retorna un valor del tipo correcto (ejem return)

    77

  • 4.4 Chequeos de Unicidad Uso (y mal uso) de identificadores

    No se puede representar en una CFG (mismo token)

    Ejemplos:

    Ningn identificador puede ser usado para dos definiciones diferentes en el mismo scope

    4.5 Chequeos de Tipo Un comprobador de tipos tiene como funcin asegurar que el tipo de una construccin coincida con el previsto en el contexto. Por eje.: llamada a una funcin con argumentos adecuados, indexacin de solo variables denidas como matrices.

    La comprobacin de tipos se puede realizar junto con el proceso de anlisis sintctico en la mayora de lenguajes.

    El diseo de un comprobador de tipos se basa en informacin acerca de las construcciones sintcticas del lenguaje, la nocin de tipos y las reglas para asignar tipos a las construcciones del lenguaje.

    Que el nmero de argumentos haga match con el nmero de parmetros formales y que los tipos correspondientes sean equivalentes

    Si se llama como expresin, debe retornar un tipo Cada acceso a una variable debe hacer match con la declaracin (arreglo,

    estructura, etc.) Los identificadores en una expresin deben ser evaluables LHS de una asignacin debe ser asignable En una expresin los tipos de las variables, tipos de retorno de mtodos y de

    operadores deben ser compatibles

    78

  • 4.6 Arboles AST Supongamos, por ejemplo, que nuestro lenguaje permite asignaciones segn la regla

    (Asignacin) -> id:=Expresin ;

    Es habitual que se impongan ciertas restricciones. En nuestro caso, estas podran ser:

    El identificador de la parte izquierda debe estar declarado previamente.

    El tipo de la expresin debe ser compatible con el del identificador.

    El analizador semntico deber comprobar que estas dos restricciones se cumplen antes de declarar que la sentencia de asignacin est bien formada. Pero sucede que la informacin necesaria para comprobarlas es til tambin para generar cdigo. Esto quiere decir que si tuviramos una separacin estricta entre las fases del compilador, para generar cdigo deberamos volver a mirar el identificador para saber a qu objeto (variable, funcin, constante, etc.) corresponde y que tipo tiene y tambin deberamos volver a comprobar los tipos de la expresin para generar el cdigo adecuado.

    Por otro lado, aunque en teora el rbol de anlisis sera suficiente para fases posteriores de la compilacin o interpretacin, es una representacin que contiene mucha informacin redundante.

    As el rbol para a:=b+c; podra ser el siguiente

    Ilustracin 8 , rbol AST

    79

  • El segundo rbol se conoce como rbol de sintaxis abstracta (o AST, de las iniciales en ingles).

    Como hemos comentado, durante el anlisis semntico se recoge una serie de informaciones que resultan de utilidad para fases posteriores. Estas informaciones se pueden almacenar en el rbol, decorndolo:

    Ilustracin 9 , rbol AST

    As el objetivo de la fase de anlisis semntico ser doble: por un lado detectaremos errores que no se han detectado en fases previas y por otro lado obtendremos el AST decorado de la entrada.

    Evaluacin de atributos sobre el AST Todo el proceso de evaluacin de los atributos se puede ver como el etiquetado de un rbol (el rbol de anlisis), pero no hay nada que impida que el rbol sobre el que se realiza la evaluacin sea el AST.

    Un ejemplo seria el clculo de tipos. Si tenemos la expresin (2+3.5)*4, podemos calcular los tipos sobre el rbol de anlisis:

    80

  • Tambin podemos realizar el clculo sobre el AST:

    Comprobaciones semnticas Los atributos nos permitirn llevar a cabo las comprobaciones semnticas que necesite el lenguaje.

    81

  • En algunos casos, utilizaremos los atributos directamente (posiblemente evaluados sobre el AST), por ejemplo en la comprobacin que hacamos de que el identificador al final de la funcin era el mismo que al principio.

    En otros casos, los atributos se utilizan indirectamente mediante estructuras globales, por ejemplo la tabla de smbolos. Un ejemplo sera la comprobacin de que un identificador no se ha declarado dos veces. Si hemos utilizado un nodo similar a:

    La tabla de smbolos

    Durante la construccin del AST, las comprobaciones semnticas y, probablemente, durante la interpretacin y la generacin de cdigo necesitaremos obtener informacin asociada a los distintos identificadores presentes en el programa. La estructura de datos que permite almacenar y recuperar esta informacin es la tabla de smbolos.

    En principio, la tabla debe ofrecer operaciones para:

    Insertar informacin relativa a un identificador.

    Recuperar la informacin a partir del identificador.

    La implementacin habitual es una tabla que asocia cada identificador a informacin tal como su naturaleza (constante, variable, nombre de funcin, etc.), su tipo (entero, real, booleano, etc.), su valor (en el caso de constantes), su direccin (en el caso de variables y funciones), etc.

    Es importante tener nicamente una tabla; si tenemos varias, por ejemplo, una para constantes y otra para variables, el acceso se hace ms difcil ya que para comprobar las propiedades de un identificador hay que hacer varias consultas en lugar de una.

    Una cuestin importante es como se relacionan la tabla y el AST. Tenemos distintas posibilidades, que explicaremos sobre el siguiente rbol, correspondiente a la sentencia a= a+c:

    82

  • La primera posibilidad es dejar el rbol tal cual y cada vez que necesitemos alguna informacin, por ejemplo el valor de a, consultar la tabla. Esta opcin seria la ms adecuada para situaciones en las que se vaya a recorrer el rbol pocas veces, por ejemplo en una calculadora donde se evalu cada expresin una sola vez.

    Otra posibilidad es ir decorando cada una de las hojas con toda la informacin que se vaya recopilando. Por ejemplo, si durante el anlisis averiguamos el tipo y direccin de las variables, pasaramos a almacenar la nueva informacin:

    Equivalencia de tipos Comprobar si dos expresiones de tipo, T1 y T2, son equivalentes es muy sencillo. Si ambas corresponden a tipos elementales, son equivalentes si son iguales. En caso de que correspondan a tipos estructurados, hay que comprobar si son el mismo tipo y si los componentes son equivalentes.

    En muchos lenguajes se permite dar nombre a los tipos. Esto introduce una sutileza a la hora de comprobar la equivalencia. La cuestin es, dada una declaracin como

    typedef int a; 83

  • typedef int b;

    son equivalentes a y b? La respuesta depende del lenguaje. Existen dos criterios para la equivalencia:

    Equivalencia de nombre: dos expresiones de tipo con nombre son equivalentes si y solo si tienen el mismo nombre.

    Equivalencia estructural: dos expresiones de tipo son equivalentes si y solo si tienen la misma estructura.

    Hay argumentos a favor de uno y otro criterio. En cualquier caso, hay que tener en cuenta que para comprobar la equivalencia estructural ya no sirve el mtodo trivial presentado antes. En este caso, puede haber ciclos, lo que obliga a utilizar algoritmos ms complicados.

    Comprobacin de tipos en expresiones Para comprobar los tipos en las expresiones podemos utilizar un atributo que indique el tipo de la expresin. Este tipo se infiere a partir de los distintos componentes de la expresin y de las reglas de tipos del lenguaje.

    Por ejemplo, si vamos a crear un nodo suma a partir de los arboles:

    podemos aadir un nodo intermedio para indicar la promocin:

    84

  • 4.7 Otras comprobaciones semnticas y recuperacin de errores semnticos

    Dentro de las comprobaciones estticas (en el momento de la compilacin), tenemos la deteccin e informacin de errores como:

    Comprobaciones de tipos: operadores aplicados a operandos incompatibles, asignacin de tipos incompatibles, llamadas a funciones con tipos no adecuados, etc.

    Comprobaciones de ujo de con