visión histórica del desarrollo de los...

44
1 BENEMÉRITA UNIVERSIDAD AUTONÓMA DE PUEBLA FACULTAD DE CIENCIAS DE LA COMPUTACIÓN NOTAS DE COMPILADORES ANÁLISIS LÉXICO Y SINTÁCTICO Otoño 2013 Capítulo I

Upload: vudien

Post on 18-Sep-2018

215 views

Category:

Documents


0 download

TRANSCRIPT

  • 1

    BENEMRITA UNIVERSIDAD AUTONMA DE PUEBLA

    FACULTAD DE CIENCIAS DE LA COMPUTACIN

    NOTAS DE

    COMPILADORES

    ANLISIS LXICO Y SINTCTICO

    Otoo 2013

    Captulo I

  • 2

    Visin Histrica del Desarrollo de los Compiladores

    En 1946, se desarrolla el primer ordenador digital ejecutaban instrucciones en cdigos

    numricos (lenguaje de mquina) interpretado por un secuenciador cableado.

    Posteriormente, surgen los ensambladores (claves ms fciles de recordar) en donde la propia

    mquina realizaba el proceso mecnico de traduccin.

    A pesar de todo el lenguaje ensamblador segua siendo de una mquina.

    Las lneas de investigacin para crear leguajes ms fciles e independientes de la mquina

    desde 1950 con John Backus hasta 1957 el FORTRAN (Formule Translator) primer lenguaje de alto

    nivel. Por primera vez surge el concepto traductor.

    Traductor. Programa que traduce de un lenguaje a otro.

    Compilador. Traduce un lenguaje de alto nivel a uno de bajo nivel.

    El primer compilador de FORTRAN tard 18 aos en realizarse y era muy sencillo.

    El FORTRAN an estaba muy influenciado por la mquina en la que iba ser implementado.

    Las lneas de investigacin continan hasta 1958 un grupo de investigadores junto con J. Backus

    crean ALGOL 58 (Algorithmic Language). Despus ALGOL 60, LAGOL 68 lenguaje modular

    estructurado en bloques.

    En ALGOL aparecen por primera vez conceptos de los nuevos lenguajes algortmicos.

    a) Definicin de la sintaxis en notacin BNF (Backus Naur Form): Gramtica independiente del contexto. Ejemplo:

    prop if(expr) prop else prop

    b) Formato libre: c) Declaracin explcita de tipo para todos los identificadores d) Estructuras iterativas e) Recursividad f) Paso de parmetros por valor y por referencia g) Estructura de bloques

    Paralelamente, se avanzaba en la tcnica de compilacin. En 1958 Strong y otros proponen

    una solucin al problema de que un compilador fuera utilizable por varia mquinas objeto. Para ello

    dividen el compilador en dos fases:

    1) front end 2) back end

    front end: se encarga de analizar el programa fuente.

    back end: se encarga de generar el cdigo para la mquina objeto

  • 3

    El puente de unin entre las 2 fases era un lenguaje intermedio que se design como UNCOL

    (Universal Computer Oriented Language).

    Para que el compilador fuera utilizable por varia mquinas bastaba modificar su back_end.

    Aunque no tuvo xito la definicin de UNCOL la divisin del compilador fue un adelanto

    importante. En eso aos se van proponiendo las bases par la divisin de tarea en un compilador. As

    en 1959 Rabin y Scott proponen el empleo de autmatas deterministas y no deterministas para el

    reconocimiento lexicogrfico de los lenguajes.

    En 1975, con la aparicin de LEX, surge el concepto de analizadores lxicos a partir de expresiones

    regulares.

    Avance Sintctico

    A partir de los trabajos de Chomsky se produce una sistematizacin de la sintaxis de los

    lenguajes de programacin, y con ello un desarrollo de diversos mtodos de anlisis sintctico.

    Con la notacin BNF desarrollada en 1960 por Backus, modificada en 1963 por Naur y formalizada

    por Knuth en 1964 se tiene una gua para el desarrollo del anlisis sintctico. Los diversos mtodos

    sintcticos ascendentes y descendentes se desarrollaron durante los 60s.

    En 1959, Sheridan describe un mtodo de parsing de FORTRAN que introduca parntesis

    adicionales alrededor de los operandos para ser capaz de analizar las expresiones. Ms adelante,

    Floyd introduce la tcnica de precedencia de operador. A mitad de los 60s, Knuth define las

    gramticas LR (ascendente).

    En 1968, se estudia y definen las gramticas LL (ascendentes).

    Debido a la sencillez y capacidad de anlisis para una gran variedad de lenguajes, la tcnica

    de parsing LR es la elegida par los generadores automticos de parsers. A mediados de los 70s

    Johnson crea el generador de analizadores sintcticos YACC.

    Avance Semntico

    Junto al anlisis sintctico, tambin se fue desarrollando el anlisis semntico. En los

    primeros lenguajes (FORTRAN y ALGOL 60) los tipos posibles de datos eran muy simples y la

    comprobacin de tipos era muy sencilla.

    Avance de Optimizacin

    La inclusin en ALGOL de procedimientos recursivos potenci el uso de la pila como una

    forma de manejo de memoria. As mismo, se estudi el paso de parmetros por valor y referencia,

    con la aparicin de lenguajes que permiten la localizacin dinmica de datos, se desarrolla otra

    forma de manejo de memoria.

    La tcnica de optimizacin apareci desde el desarrollo del primer compilador FORTRAN.

    Backus comenta que se tena el temor de optimizaciones dependientes de la mquina e

    independientes de sta. Entre las dependientes se pueden encontrar:

  • 4

    Localizacin de registros Uso de instrucciones propias de la mquina Reordenamiento de cdigo

    Entre las independientes se pueden encontrar:

    Propagacin de valores Arreglo de expresiones Eliminacin de redundancia

    En la actualidad un compilador es una herramienta bien conocida, dividida en diversas fases.

    Algunas se pueden generar automticamente (analizador lxico y sintctico) y otras requieren mayor

    atencin (traduccin y generacin de cdigo)

    De todas formas, todava se llevan a cabo varias vas de investigacin. El hecho de que surjan

    nuevos lenguajes, como los de 5 generacin implica la revisin de cada fase del compilador.

    Qu es un Compilador? Tipos de Traductores

    Traductor. Cualquier programa que toma como entrada un texto escrito en un lenguaje llamado

    fuente y da como salida un programa equivalente en otro lenguaje, denominado objeto.

    Compilador: Lenguaje de alto nivel (fuente) y lo traduce en lenguaje de bajo nivel (objeto).

    Ensamblador. Traduce del lenguaje ensamblador (fuente) a lenguaje de bajo nivel (objeto).

    Intrprete. Toma una sentencia del programa fuente de un lenguaje de alto nivel y la traduce al

    cdigo equivalente y al mismo tiempo lo ejecuta.

    Histricamente con a la escasez de memoria en los primeros ordenadores, se puso de moda el

    uso de intrpretes pero, la mejor informacin sobre los errores por parte del compilador as como una

    mayor velocidad de ejecucin del cdigo resultante hizo que los compiladores se impusieran.

    Hoy en da, con el problema de la memoria prcticamente resuelto se tiene un predominio de

    los compiladores.

    Ventajas de compilar frente a interpretar

    a) Se compila una vez, se ejecuta n veces b) En bucles, la compilacin genera cdigo equivalente al bucle, interpretndolo se

    traduce tantas veces una lnea como veces se repite el bucle

    Traductor Lenguaje

    Objeto

    Lenguaje

    fuente

  • 5

    c) El compilador tiene un visin global del programa, por lo que la informacin de mensajes de error es ms detallada.

    Ventajas del intrprete vs el compilador

    a) Un intrprete necesita menos memoria que un compilador b) Permiten una mayor interactividad con el cdigo en tiempo de desarrollo

    Un compilador no es un programa que funcione de forma asilada, sino que necesita de otros

    programas para conseguir su objetivo, algunos de esos programas son:

    El preprocesador: incluye ficheros, expandir macros, eliminar comentarios, etc. El linker: construir el fichero ejecutable aadiendo las cabeceras necesarias y las

    funciones de librera utilizadas por el programa fuente.

    El depurador: si se gener el programa objeto, permite seguir paso a paso la ejecucin de un programa.

    El ensamblador: convierte del lenguaje a un ejecutable.

    Tipos de Compiladores

    a) Ensamblador: Tiene una estructura sencilla. b) Compilador cruzado: Genera cdigo en lenguaje objeto para una mquina diferente de la

    que se esta utilizando para compilar.

    c) Compiladores con montador: Compila distintos mdulos de forma independiente y despus los enlaza.

    d) Autocompilador: Compilador de compiladores, aunque tiene la dificultad de unir la generacin de cdigo con la parte de anlisis. Lo que s se han desarrollado son:

    LEX generador de analizadores lxicos YACC generador de analizadores sintcticos

    Aunque los analizadores que generan no son muy eficientes.

    e) Descompilador: Traduce cdigo mquina a un lenguaje de alto nivel. Si hay optimizacin es posible descompilar.

    Estructura de un Compilador

    Para la realizacin del proceso de traduccin es necesario dividir el compilador en varias

    fases.

  • 6

    Etapas que constituyen el Proceso de Compilacin

    Al principio el tamao del archivo ejecutable y la memoria utilizada por el compilador era un

    recurso crtico, por lo que cada fase lea un fichero escrito por la fase anterior y produca un nuevo

    fichero con el resultado de las transformaciones realizadas en dicha fase lo que provocaba que el

    compilador realizar muchas pasadas sobre el programa fuente.

    En los ltimos aos ya no se tienen ambos problemas, el segundo fue resuelto gracias a la

    memoria virtual, as que leer y escribir un fichero en cada fase es una prdida considerable de tiempo

    (incluso en los sistemas modernos).

    Las fases se agrupan en 2 partes:

    1) front_end: fases de anlisis 2) back_end: fases de generacin y optimizacin de cdigo

    Estas dos se comunican mediante una representacin intermedia generada por el front_end

    que puede ser:

    una representacin de la sintaxis del programa (un rbol sintctico abstracto) un programa en lenguaje intermedio

    Anlisis sintctico

    Anlisis lxico

    Anlisis semntico

    Generacin de

    cdigo intermedio

    Optimizacin de cdigo

    Generacin de cdigo

    Programa objeto

    Manejo

    de errores

    Manejo de la

    Tabla de

    smbolos

    Programa fuente

  • 7

    El front end depende del lenguaje fuente y casi siempre es independiente de la mquina

    objeto. El back end depende del lenguaje objeto y debe ser independiente del lenguaje fuente

    (excepto quiz para algn tipo de optimizacin).

    Anlisis Lxico

    Tambin conocido como scanner, lee los caracteres uno a uno y va formando grupos de

    caracteres con alguna relacin entre s (tokens), que sern la entrada para la siguiente etapa.

    Tipos de tokens:

    Tiras especficas: palabras reservadas, ; , , =, +, -, and, etc. Tiras no especficas: identificadores, constantes o etiquetas.

    Un token tiene dos partes:

    Tipo de token Valor

    Las tiras especficas solo tienen tipo (lo que representan).

    Las tiras no especficas tienen tipo y valor.

    Ejemplo: si contador es un identificador

    El tipo es identificador

    Su valor es la cadena contador

    El analizador lxico permite saber si es un lenguaje de formato libre o no. Frecuentemente va

    unido al analizador sintctico en la misma pasada, funcionando como una subrutina de este.

    El analizador lxico ignora elementos innecesarios para la siguiente fase, como tabuladores,

    comentarios, espacios en blanco, etc.

    Ejemplo: entrada CONT * + CONT

    Anlisis lxico id por mas id

    Anlisis sintctico

    Tambin llamado Parser comprueba si los tokens van llegando en el orden correcto (orden

    permitido). Su salida sera un rbol sintctico.

    Sus funciones son:

    Aceptar lo que es vlido sintcticamente y rechazar lo que no lo es Hacer explcito el orden jerrquico que tienen los operadores en el lenguaje de que se trate,

    por ejemplo A/B * C es interpretado como (A/B) * C en FORTRAN

    Guiar el proceso de traduccin (traduccin dirigida por sintaxis)

  • 8

    Anlisis semntico

    Es ms difcil de formalizar que el sintctico. Se encarga de comprobar que lo que va leyendo

    es vlido.

    Sus funciones son:

    a) determinar el tipo de los resultados intermedios b) comprobar que los argumentos que tiene un operador pertenecen al conjunto de operadores

    posibles

    c) compatibilidad entre operandos

    La salida es un rbol semntico. Esto es un rbol sintctico en donde cada rama ha adquirido

    el significado que debe tener.

    Para el caso de lo operadores polimorficos (un smbolo con varios significados), el anlisis

    semntico determina cul es el aplicable.

    Por ejemplo:

    A:= B + C

    En Pascal + sirve para sumar enteros, reales, concatenar cadenas de caracteres y unir

    conjuntos.

    Por ejemplo:

    :=

    posicin +

    inicial *

    velocidad entero real

    60

  • 9

    Generacin de Cdigo Intermedio

    Cuando una empresa desarrolla un compilador para un lenguaje fuente y un lenguaje objeto

    determinados, normalmente no es el nico compilador que la empresa piensa desarrollar. El uso de

    un lenguaje intermedio permite construir en mucho menos tiempo un compilador.

    Por ejemplo, si un compilador de C, uno de FORTRAN y uno de PASCAL usan el mismo

    lenguaje intermedio pueden ser portados a todos los sistemas y mquinas en las que ya exista un

    compilador de C relativamente poco esfuerzo.

    La generacin de cdigo intermedio transforma un rbol de anlisis sintctico (semntico) en

    una representacin en lenguaje intermedio.

    Una forma es usando el cdigo de tres direcciones.

    Ejemplo:

    temp1:= enteroreal (60)

    temp2:= id3 * temp1

    temp3:= id2 + temp2

    id:= temp3 :=

    id 1 +

    id2 *

    id3 enteroreal

    60

    Optimizacin de Cdigo

    Esta fase se aade para conseguir que el programa objeto sea ms rpido en la ejecucin y

    que necesite menos memoria ala hora de ejecutarse.

    Ejemplo de optimizaciones locales:

    eliminar algunos saltos eliminar expresiones comunes optimizaciones de bucles

    Ejemplo:

    1) temp1:= enteroreal (60) temp1:= id3 * 60.0 temp2:= id3 * temp1 optimizacin de cdigo

  • 10

    2) repeat B:= 1 B:= 1 repeat

    A:= A B A:= A B

    until A:= 0 until A:= 0

    Generacin de Cdigo

    Consiste en generar cdigo objeto que consiste en cdigo mquina o ensamblador.

    Ejemplo:

    MOVF id3, R2

    MULF #60.0, R2

    MOVF id2, R1

    ADDF R2, R1

    MOVF R1, id1

    Tabla de Smbolos

    Utilizada para que el compilador guarde y use la informacin de los objetos que encuentra en

    el texto fuente, como variables, etiquetas, declaraciones de tipos, etc.

    El compilador usa la estructura de datos para insertar, consultar, borrar, etc. Los accesos

    deben ser rpidos para que el compilador sea eficiente.

    Ejemplo:

    1 Posicin

    2 Inicial

    3 Velocidad

    4

    Manejo de Errores

    Es una de las funciones ms importantes de un compilador, aunque es lo que ms dificulta su

    realizacin.

    Se utiliza ms en el anlisis sintctico y semntico. Es una tarea difcil por dos razones:

    A veces unos errores ocultan otros A veces un error provoca una avalancha de muchos errores que se solucionan con el primero

    Es conveniente que el compilador detecte todos los errores que tiene el programa y no se pare

    con el primero que encuentre.

    Hay dos criterios para manejar los errores:

  • 11

    1) Pararse al detectar el primer error 2) Detectar todos los errores de una pasada

    Cmo se especfica un Compilador?

    Cuando se va a disear un compilador, es necesario especificar:

    a) el lenguaje fuente b) el lenguaje objeto c) el sistema operativo sobre el que funcionar d) el lenguaje usado para construirlo

    La especificacin del lenguaje fuente se divide en tres partes:

    1) Especificacin lxica: se especifican los componentes lxicos (tokens) o palabras del lenguaje, para ello se usan expresiones regulares.

    2) Especificacin sintctica: se detalla la forma o estructura (la sintaxis) que tendrn los programas en este lenguaje fuente. Para lo cual se utiliza una gramtica independiente del

    contexto en notacin BNF.

    3) Especificacin semntica: se describe el significado de cada construccin sintctica y las reglas semnticas que deben cumplirse.

    Tarea 1: Aplicaciones de las Tcnicas Aprendidas en Compiladores

    a) Desarrolla de interfaces textuales: cualquier programa cuya interaccin con el usuario sea algo ms que pulsar teclas.

    b) Tratamiento de ficheros de texto con informacin estructurada: lenguajes como PERL y TCL.

    c) Procesadores de texto: procesadores como VI o EMACS usan expresiones regulares. d) Diseo e interpretacin de lenguajes para el formateo de texto y descripcin de grficos:

    HTML, PostScript.

    e) Gestin de base de datos: exploracin y proceso de ficheros. f) Procesamiento de lenguaje natural. g) Traduccin de formatos de fichero: estructura de datos de ficheros con registros de

    programas obsoletos se pueden actualizar a formatos actualizados.

    h) Reconocimiento de formas: deteccin de patrones en texto, reconocimiento automtico del habla o la visin por computador.

    El Papel del Analizador Lxico

    El analizador lxico es el nico que gestiona con el fichero de entrada para construir

    elementos lxicos llamados tokens.

    El analizador lxico ignora tabuladores, espacios en blanco, cambios de lnea, comentarios,

    etc.

    Por qu separar el anlisis lxico y sintctico?

  • 12

    1) El diseo de las partes posteriores al anlisis queda simplificado. 2) Con fases separadas se pueden aplicar tcnicas especficas para cada fase, que son ms

    eficientes en sus respectivos dominios.

    3) Se facilita la portabilidad. Si se quiere cambiar alguna caracterstica del alfabeto del lenguaje, slo tiene que cambiar el analizador lxico.

    Ejemplo: si tomamos las expresiones

    6 2 * 30 / 7 Tienen la misma estructura (analizador sintctico) pero los caracteres no son

    6 - 2* 30/7 pero los caracteres no son los mismos

    8-2*3/5

    Es por eso que el procesamiento de caracteres se deja en manos del analizador lxico.

    Ejemplo: las tres expresiones anteriores son representadas por el analizador lxico de la misma

    manera.

    Cada par est representado por el tipo de token (lexema).

    Gran parte del tiempo se consume en leer el archivo fuente

    El analizador lxico debe rechazar cualquier texto en el que aparezcan caracteres ilegales (no

    recogidos en el alfabeto) o combinaciones ilegales (no permitidas por las especificaciones lxicas).

    Errores Lxicos

    Pocos son lo errores de esta etapa, pues el compilador tiene todava una visin muy local del

    programa.

    Por ejemplo:

    Si encuentra y asla la cadena while creer que es un identificador, cuando posiblemente se

    trata de un while mal escrito y no es el quien informa de esto sino etapas sucesivas del anlisis.

    Los errores que tpicamente detecta el analizador lxico son:

    a) Utilizar caracteres que no pertenecen al alfabeto del lenguaje, por ejemplo: o b) Se encuentra una cadena que no coincide con ninguno de los patrones de los tokens posibles,

    por ejemplo:

    En un lenguaje := puede ser la asignacin pero que no permita : solo.

    Cuando el analizador lxico encuentra un error, lo habitual es parar su ejecucin e informa,

    pero hay una serie de posibles acciones para anotar los errores, recuperarse de ellos y seguir

    trabajando.

  • 13

    Tarea 2: Investigar acerca del manejo de buffers de entrada pareja de buffers y centinelas.

    Ignorar los caracteres no vlidos hasta formar un token segn los patrones dados. Borrar los caracteres extraos. Insertar un caracter que pudiera faltar. Reemplazar un caracter presuntamente incorrecto por uno correcto. Conmutar las posiciones de dos caracteres adyacentes.

    Todas son complicadas de llevar a cabo y peligrosas por las equivocadas que pueden resultar

    para el resto del anlisis.

    Funcionamiento de Analizador Lxico

    1) La primera funcin del analizador lxico es procesar la cadena de caracteres y devolver pares (token, lexema). Debe ser una subrutina del analizador sintctico.

    2) Maneja el fichero del programa fuente; es decir: abrirlo, leer sus caracteres y cerrarlo. Tambin deber ser capaz de gestionar posibles errores de lectura.

    3) Ignora comentarios, tabuladores, espacios en blanco, retornos de carro, etc. 4) Cuando se produce una situacin de error este es el que site el error en el programa fuente

    (tal lnea, tal posicin). Lleva la cuenta de las lneas procesadas.

    5) Preproceso de macros, definiciones, constantes y rdenes de inclusin de otros ficheros.

    Cada vez que se llame al analizador este debe continuar en el caracter donde se qued hasta

    completar un token y en ese momento debe devolver el par (token, lexema).

    Cuando se reconocen algunos tipos de tokens como los identificadores o los nmeros el

    analizador lxico debe leer caracteres hasta que lea uno que no pertenece a la categora del token que

    se est leyendo: este ltimo caracter debe devolverse al buffer de entrada para ser ledo en primer

    lugar en la prxima llamada.

    Ejemplo: En la cadena Grande / 307>=

    El nombre del identificador

    Grande ha concluido basta colocarse en l y ver si no es prefijo de ningn otro

    Analizador

    lxico

    Analizador

    sintctico

    Tabla de smbolos

    Componente lxico

    Obtn el siguiente

    componente lxico

    Programa

    fuente

  • 14

    1 2 3

    0 1

    [0-9]

    *Entero otro

    x

    *

    Transicin

    Estados

    Transicin

    No obligatorio (repeticin)

    Retroceso de un estado

    El analizador lxico debe intentar siempre leer el token ms largo posible, pero si no es

    correcto debe devolver el token correcto y debe retroceder en el buffer hasta el final de ese token

    correcto.

    Ejemplo: !> no es vlido pero

    !es vlido

    Para especificar correctamente el funcionamiento de un analizador lxico se debe utilizar una

    mquina de estados, llamada Diagrama de Transiciones (DT), muy parecido a un autmata finito

    determinista con las siguientes diferencias:

    Un ADF slo dice si la cadena de caracteres pertenece al lenguaje o no; un DT debe leer caracteres hasta completar un token, y entonces retornar (en los estados de aceptacin) el

    token ledo y dejar el buffer de entrada preparado para la siguiente llamada. Un DT no puede

    tener estados de absorcin (cadenas incorrectas en AFDs)

    En un DT se considerar que las entradas para las que no hay transicin desde cada estado son error.

    De los estados de aceptacin de un DT no deben salir transiciones. En el caso de tiras no especificas, se necesita otro estado al que ir cuando se lea un caracter

    que no pueda formar parte del patrn. En este ltimo estado (al que se llega con la transicin

    especial a otro) se debe devolver al buffer de entrada el caracter ledo que puede ser parte del

    siguiente token, lo cual se indica marcando el estado con un *, y se debe retornar el token

    correspondiente a ese estado de aceptacin.

    Ejemplo: Reconocedor de nmeros enteros sin signo mediante la expresin regular [0-9]+ = digito+

    DT

    Otro: significa cualquier otro caracter del alfabeto del lenguaje que no est en el rango [0-9]

    Si durante el recorrido del autmata se produce una transicin no autorizada o la tira de

    entrada finaliza en un estado de no aceptacin, el analizador informara del error.

    [0-9] [0-9]

    x

  • 15

    El analizador suele tener unos subprogramas auxiliares encargados de gestionar el buffer

    (tcnicas de doble buffer, doble salto de lnea, , etc.) y de ir volviendo caracteres al buffer de

    entrada cada vez que el procedimiento de reconocimiento y aislamiento lo requiera.

    Identificacin de Palabras Reservadas

    El problema es como reconocer palabras reservadas si responden al mismo patrn que los

    identificadores, pero son tokens diferentes al token identificador.

    Existen dos enfoques para resolver este problema:

    1) Resolucin Implcita: Considerar que todos son identificadores y buscarlos en una tabla.

    2) Resolucin Explcita: Se indican todas las expresiones regulares de todas las palabras reservadas y se integran los DT resultantes de sus especificaciones lxicas en

    la mquina reconocedora.

    Para 1) en definitiva, las palabras reservadas se toman como lexemas particulares del patrn

    del identificador. Para esto en el AL.

    Primero inicializar la tabla de smbolos con todas las palabras reservadas (por orden alfabtico).

    Cuando encuentre identificador se revisar la tabla de smbolos. o Si lo encuentra en la zona reservada para ellos entonces es una palabra reservada. o Si no, ser un identificador, que como tal, ser aadido a la tabla de smbolos.

    Ejemplo: cont

    Tabla de smbolos

    do Pal. reservada

    end Pal. reservada

    for Pal. reservada

    while Pal. reservada

    cont Identificador

    Cuando la deteccin es explicita. Las especificaciones lxicas de las palabras reservadas,

    (tiras especficas) constan de concatenaciones de caracteres y pueden ser siempre prefijos de

    identificadores (por ejemplo do y dos (identificador).

    Cuando un elemento lxico es prefijo de otro y ambos son tiras especificas, aparecen estados

    de aceptacin que partirn de estados intermedios.

    Zona

    de

    Palabras Reservadas

    Zona de identificadores

  • 16

    Ejemplo 1: Construir un diagrama de transiciones para el reconocimiento de identificadores,

    nmeros enteros sin signo y palabras reservadas do y done.

    Notacin

    d = dgito, l = letra, t = otro, f = otro alfanumrico (dgito o letra), an = ir al estado n

    Ejemplo 2: Construir un diagrama de transiciones para el reconocimiento de nmeros enteros con

    signo negativo o si n signo.

    (ER: (- | E) d+ y los operadores suma (+) e incremento (++)

    Notacin

    d = dgito, t = otro

    Ejercicio 1: Construir un diagrama de transiciones para el reconocimiento de operadores

    relacionales: =, >

    Ejercicio 2: Construir un diagrama de transiciones para el reconocer nmeros en notacin cientfica

    ejemplo 3 5 cientfico signo d+ E signo d+

    Ejercicio 3: Construir un diagrama de transiciones para el reconocer nmeros reales dgitos+

    (.dgitos+)

    Ejercicio 4: Construir un diagrama de transiciones para el reconocer los siguientes componentes

    lxicos while, when, ident, opersum (+), opermul (*), operinc (++)

    Ejercicio 5: Construir un diagrama de transiciones para el reconocer opersum (+), opermul (*),

    operdiv (/), operrest (-), parizq ( ( ), parder( ) ), entero, real, ident.

    Ejercicio 6: Construir un diagrama de transiciones para el reconocer los siguientes componentes

    lxicos read, print, palabras reservadas pradir, redir, ident, raya (_), punto ( . )

    Ejercicio 7: Construir un diagrama de transiciones para el reconocer los siguientes operadores

    lgicos and, or, not.

  • 17

    1 2 3

    [0-9]

    *Entero otro

    Implementacin del Analizador Lxico

    La forma de implementar el Diagrama de Transiciones es mediante la construccin de su

    tabla de transiciones. Para ello se etiquetan las filas como los estados del DT y las columnas como

    las distintas posibles entradas a las que hay que aadir el token que se reconoce.

    Ejemplo:

    Estado

    Entradas

    [0-9] _ otro

    # de retroceso

    token retroceso

    1 2 0 0

    2 2 0 - -

    3 0 Entero 1

    Tabla de Transiciones del ejemplo 1

    Entradas

    Estado l d d o n e t 1 2 4 6 2 2 2 0

    2 2 2 2 2 2 2 2

    3 0 0 0 0 0 0 0

    4 $ 4 $ $ $ $ $

    5 0 0 0 0 0 0 0

    6 2 2 2 7 2 2 3

    7 2 2 2 2 9 2 8

    8 0 0 0 0 0 0 0

    9 2 2 2 2 2 10 3

    10 2 2 2 2 2 2 11

    11 0 0 0 0 0 0 0

    Una vez que se tiene esta, el analizador lxico la recorrer cada vez mediante un bucle con la

    sentencia.

    Estado:= Tabla de Transiciones [Estado, Entrada].

    [0-9]

  • 18

    El Analizador intentar llegar a un estado de aceptacin, en el que restaura la entrada segn el

    retroceso.

    Prioridad de tokens

    Dar prioridad al token para el que encontramos el lexema ms largo. Ejemplo Do / DOT se toma (DOT)

    Si el lexema es el mismo que se puede asociar a dos tokens, estos estarn definidos en un orden (el primero).

    Ejemplo:

    while Palabra reservada l (l | d) identificador

    As que el Analizador Lxico devuelve el token palabra reservada.

    TT Ejemplo 2

    Entradas

    Estado + d _ t 1 2 5 7 0

    2 4 3 0 3

    3 0 0 0 0

    4 0 0 0 0

    5 0 5 0 6

    6 0 0 0 0

    7 0 5 0 0

    PROYECTO 1: Hacer un Analizador Lxico para:

    ALGOL ADA MODULA II

    Que por lo menos contenga:

    Tipos de datos Constantes Variables (Identificadores)

    * Suma

    incremento

    * Entero

  • 19

    Operadores Sentencias de control (Decisin y Repeticin) Funciones Paso de parmetros

    Ejercicio 7: Hacer el DT, TT para reconocer nmeros decimales, octales y binarios

    d = 0 | 1 || 9

    oct = 2 | 3 || 7

    dd = 8 | 9

    bin = 0 | 1

    Tabla de Smbolos

    El Analizador Lxico guarda una entrada de la tabla de smbolos el lexema correspondiente a

    los identificadores (las variables).

    Las fases posteriores del compilador pueden aadir a esta entrada informacin, como el tipo

    de identificador, su uso (por ejemplo, procedimiento, variable o etiqueta) y su posicin en la

    memoria.

    Gran parte de la deteccin y recuperacin de errores en un compilador se centra en la fase de

    anlisis sintctico.

    El analizador sintctico debe hacer lo siguiente:

    Informar de los errores con claridad y exactitud Recuperarse de cada error rpido para detectar los errores posteriores No retrasar de manera significativa el proceso de programas correctos

    Existen varia tcnicas para que el Analizador Sintctico se recupere de fallos, pero:

    Una recuperacin inadecuada puede introducir una avalancha de errores introducidos por los cambios hechos al estado del analizador sintctico

    La recuperacin del error sintctico puede introducir errores semnticos

    Tarea 1: Estrategias de recuperacin de Errores.

  • 20

    Captulo II

    Anlisis Sintctico (PARSER)

    Su funcin principal es construir una representacin interna del programa.

    Agrupa los lexemas suministrados por el A.L. con el fin de reconocer frases.

    Determina si el programa es sintcticamente correcto. Esto es si la sucesin de smbolos que representan los tokens es generada por la gramtica correspondiente al lenguaje.

    Los tokens los agrupa de acuerdo a producciones especificadas por la GLC.

    La sintaxis se especifica con GLC.

    La forma ms habitual de representar la sintaxis de un programa es el rbol de anlisis sintctico y el A.S.

    construye una derivacin por la izquierda o por la derecha del programa fuente.

    El A. S. constituye el esqueleto principal del compilador

    Hay dos opciones para implementar un parser

    1. A mano usando tcnicas (eficiente y complejo) 2. Utilizando un generador de A.S., por ejemplo YACC (ineficiente y fcil)

    2.1 Notacin EBNF (Extended Backus-Naur Form).

    Esta se usa con el objetivo de reducir el nmero de producciones en las gramticas.

    1.- Alternativas de una regla: | para separar las distintas posibilidades que definen al no terminal de

    la izquierda.

    Ejemplo: a) si A a

    A b

    A c

    = A a | b | c

    b) entero digito | entero dgito

    2.- { }, lo que aparece entre llaves se repite de cero a n veces.

  • 21

    Ejemplos: a) Lista_parmetros parmetro {, parmetro>

    b) tren locomotora {vagn }

    3.- Llaves con repeticin especificada: { }yx: lo que aparece entre llaves se repite de x a y veces.

    Ejemplo: tren con 3, 4 5 vagones: tren locomotora { vagn }53

    4.- [ ]: lo que est entre los corchetes puede o no aparecer. Es un caso particular de3.-, pues es

    equivalente a { }10

    Ejemplo: Sentencia IF de Pascal:

    IF expresin THEN sentencia

    [ ELSE sentencia ]

    2.2 Gramtica GLC o BNF

    Sea G = (N, T, S, P) es una 4- tupla donde:

    N = conjunto de no terminales: Genera ms de un nica cadena

    T = conjunto de terminales: Genera una nica cadena

    P = conjunto de producciones: Regla que establece una transformacin

    S = Smbolo inicial o axioma: Genera todas las cadenas del lenguaje

    Sea G = (N, T, S, P), donde

    N = {frase, sujeto, predicado, articulo, nombre, verbo, adverbio}

    T = {el, la, est, lejos, cerca, perro, gato}

    S = {frase}

    P = {P1, P2, P3, P4, , P10}

    P1 = frase sujeto predicado P2 = sujeto articulo nombre P3 = predicado verbo adverbio P4 = articulo el P5 = articulo la P6 = nombre perro P7 = nombre gata P8 = verbo est P9 = adverbio cerca P10 = adverbio lejos

    Forma de frase: Cualquier string que se pueda derivar del smbolo inicial (string de smbolos

    gramaticales).

    Frase: Cualquier forma de frase con solo elementos terminales

  • 22

    Lenguaje: Definido por una G (conjunto de todas las frases de la G).

    Para el ejemplo anterior, los siguientes elementos pertenecen al lenguaje generado por la G:

    El perro est cerca Cadena Frase La perro est lejos Cadena - Frase El gata est cerca Cadena Frase

    Los siguientes elementos no pertenecen al lenguaje generado por la G:

    El perro La lejos perro est

    Convenios para la GLC

    Terminales: o Primeras minsculas del abecedario o Smbolos de operacin y puntuacin o Dgitos o Palabras en negrita: perro, begin

    Son no Terminales: o Primeras maysculas del abecedario o Palabras en cursiva: sujeto, expresin

    La S, suele representar el smbolo inicial Letras griegas minsculas representan formas de frase

    o As en un GLC una produccin de escribe A B Parte izq. Parte der.

    Varias producciones con igual parte izquierdo se agrupan en una produccin con alternativas.

    Diseo de Gramticas para Lenguajes de Programacin

    Como se plasma en el aspecto de las reglas sintcticas algunas propiedades de los operadores

    y operandos en los lenguajes de programacin.

    RECURSIVIDAD

    Una dificultad a la hora de disear un compilador es que debe procesar correctamente un

    nmero infinito de programas distintos.

    Por otro lado, la especificacin sintctica de un lenguaje debe ser finita. El concepto que hace

    compatible ambas afirmaciones

    Recursividad. Permite definir sentencias complicadas con un nmero pequeo de sencillas reglas de

    produccin.

  • 23

    EJEMPLO:

    Formar un tren con locomotora y un nmero cualquiera de vagones detrs.

    tren locomotora tren locomotora vagn tren locomotora vagn vagn . . .

    Usando recursividad manera:

    1) Regla base (no recursiva) tren locomotora

    2) Una o ms reglas recursivas tren tren vagn

    Con esto no necesitamos infinitas reglas de produccin.

    Estructura de la recursividad

    1. Regla no recursiva que se define como caso base. 2. Una o ms reglas recursivas que permiten el crecimiento a partir del caso base.

    EJEMPLO 1:

    La gramtica para describir un identificador escrita como GLC, podra ser:

    N = { Letra, Dgito, Identificador}

    T = { a, b, c,..., z, 0, 1,..., 9 }

    S = Identificador

    P = { Letra a ...

    Letra z Dgito 0 ...

    Dgito 9 Identificador Letra Identificador Identificador Letra Identificador Identificador Dgito }

    As, el rbol sintctico de id02a sera:

    Infinitas reglas

    de produccin

  • 24

    Definicin: Una gramtica se dice que es recursiva, si podemos hacer una derivacin (sucesin de

    una o ms producciones) de un smbolo no terminal tras la cual se vuelve a tener dicho smbolo entre

    los smbolos de la parte derecha de la derivacin.

    A A

    Si se tiene:

    A A se denomina recursividad izquierda A A se denomina recursividad derecha

    Un no terminal recursivo: si a partir de A se puede derivar una forma sentencial en que aparece l

    mismo en la parte derecha.

    AMBIGEDAD

    Una gramtica es ambigua si el lenguaje que define contiene alguna sentencia que tenga ms

    de un nico rbol de anlisis sintctico.

    Se debe evitar disear gramticas ambiguas caractersticas, es sencillo encontrar una cadena con dos

    o ms rboles.

    o Gramticas con ciclos simples o menos simples: S A S a A S

    o Alguna regla con una forma

    No es posible construir analizadores sintcticos eficientes para gramticas ambiguas.

  • 25

    E E E

    Con cualquier cadena de terminales y no terminales entre las dos E. Es posible que con algn

    terminal antes de la primera E o algn terminal despus de la ltima E pueda producirse

    ambigedad; por ejemplo, el if-then-else de Pascal.

    o S A S B

    A B

    o Producciones recursivas en las que las variables no recursivas de la produccin puedan derivar a la cadena vaca:

    S H R S

    S s

    H h | e

    R r | e

    o Variables que puedan derivar a la cadena vaca y a la misma cadena de terminales, y que aparezcan juntas en la parte derecha de una regla o en alguna forma esencial.

    S H R

    H h | e

    R r | h | e

    EJEMPLO:

    Sea una gramtica cuyas reglas de produccin son:

    E E + E | E * E | () | nmero

    Se puede generar la tira 2+3*5 que tiene dos posibles rboles sintcticos.

    Para solucionar esta ambigedad se deben modificar las reglas de produccin de la gramtica.

    Se debe lo que es un factor y lo que es un trmino (producto de dos factores - monomio). As se

    establece la jerarqua de precedencias de los operadores:

    + |

    * |

    ( ) | nmero

  • 26

    Una gramtica es ambigua si se produce ms de una derivacin por la izquierda o por la

    derecha de la misma frase.

    De esta forma slo hay un rbol sintctico para 2+3*5:

    ASOCIATIVIDAD Y PRECEDENCIA DE LOS OPERADORES

    Asociatividad: La forma de reflejar la asociatividad de un operador en la G es de la forma siguiente:

    cuando la asociatividad del operador es por la izquierda, la regla sintctica en la que interviene

    dicho operador debe ser recursiva por la izquierda, y cuando es por la derecha debe tener recursin

    por la derecha. Ejemplo: 9 5 2 y a = b = c

    Precedencia: Orden de cada operador con respecto a los dems operadores.

    La forma de reflejar la precedencia de los operadores aritmticos es bastante sencilla. Es necesario

    utilizar una variable en la gramtica por cada operador de distinta precedencia. Cuanto ms cerca

    est la produccin de la del smbolo inicial, menor ser la precedencia del operador involucrado.

    Cercana tiene que ver con el nmero de producciones que hay que llevar a cabo para llegar hasta esa

    regla desde el smbolo inicial.

    Parentizacin: Los parntesis siempre tienen la mxima precedencia. Se usan para agrupar los operadores segn la conveniencia del programador.

    Para incluirlos en la gramtica, se aade una variable que produzca expresiones entre parntesis y los

    operandos (nmeros, variables, etc.) a la mayor distancia posible del smbolo inicial. En esta

    produccin se pondran los operadores unarios a no ser que tengan una precedencia menor.

    EJEMPLO:

    Supnganse los operadores +, -, con asociatividad por la izquierda (en 6-3-3), y * y / por la derecha,

    * / precedencia 1 y los parntesis tienen la suma y la resta precedencia 2 mxima precedencia.

    La gramtica que genera las expresiones con estos operadores y adems recoge la asociatividad y la

    precedencia es la siguiente:

    12-4-6/2/2

    n2 n3

  • 27

    E E + T

    E E T

    E T

    T F T

    T F / T

    T F

    F ( E )

    F nmero

    TIPOS DE ANLISIS SINTCTICO

    Los algoritmos de anlisis sintctico general para gramticas independientes del contexto tienen un

    coste temporal del orden de O(n3); lo que es demasiado elevado para un compilador, por lo que es

    necesario buscar subclases de gramticas que permitan un anlisis sintctico en tiempo lineal.

    Desde el punto de vista de la teora de Anlisis Sintctico, hay dos estrategias para construir el rbol

    sintctico:

    o Anlisis descendente: partimos de la raz del rbol (axioma o smbolo inicial) y se van aplicando reglas por la izquierda de forma que se obtiene una derivacin por la izquierda

    de la cadena de entrada. Para decidir qu regla aplicar, se lee un token de la entrada.

    Recorriendo el rbol de anlisis sintctico resultante, en profundidad de izquierda a

    derecha, encontraremos en las hojas del rbol los tokens que nos devuelve el A.L. en ese

    mismo orden.

    o Anlisis ascendente: partiendo de la cadena de entrada, se construye el rbol de anlisis sintctico empezando por las hojas (donde estn los tokens) y se van creando nodos

    intermedios hasta llegar a la raz (hasta el axioma), construyendo as el rbol de abajo a

    arriba. El recorrido del rbol se har desde las hojas hasta la raz. El orden en el que se

    van encontrando las producciones corresponde a la inversa de una derivacin por la

    derecha.

    Anlisis Sintctico Descendente

    Este intenta encontrar entre las producciones de la gramtica una derivacin por la izquierda del

    smbolo inicial para una cadena de entrada.

    Backtracking: Cuando el anlisis sintctico descendente (ASD) puede incluir retrocesos en el

    anlisis.

    Anlizadores Sintcticos Predictivos (ASP)

    Para que el algoritmo tenga una complejidad lineal, el analizador debe realizar una prediccin

    de la regla a aplicar.

    Para ello, se debe conocer, dado el token de la entrada, a, que est siendo analizado, y el no

    terminal a expandir A, cul de las alternativas de produccin A 1 | 2 || n es la nica posible que da lugar a que el resto de la cadena que se est analizando empiece por a. Dicho de otra forma, la

  • 28

    alternativa apropiada debe poderse predecir slo con ver el primer smbolo que produce. Que forma

    deben tener las gramticas a las que se puede aplicar.

    EJEMPLO:

    Sent if Expres then Sent while Expres do Sent begin Sent end

    En esta gramtica slo existe siempre una posibilidad de derivacin, segn sea el valor del

    token.

    Derivaciones

    Ejemplo 1) de gramticas

    Define expresiones aritmticas

    expr expr op exp.

    expr expr)

    expr expr

    exp id

    op +

    op -

    op *

    op /

    op

    Derivaciones

    La visin derivativa de una descripcin precisa de la construccin descendente de un rbol de

    anlisis sintctico.

    La idea central es que se considera una produccin como una regla de reescritura, donde el no

    Terminal de la izquierda es sustituido por la cadena del lado derecho de la produccin.

    Ejemplo: Gramtica para expresiones aritmticas

    E E + E | E * E | (E) | - E | id E significa que una expresin precedida por un signo menos es tambin una expresin.

    Ejemplo:

    E - E -(E) -(id)

    A esta secuencia de sustituciones se le llama derivacin de (id) a partir de E.

    Las cadenas de L (G) pueden contener slo smbolos terminales de G.

    Los smbolos terminales son: id +, -, *, /,

    ( ),

    Los smbolos no terminales son: exp y op

    Smbolo inicial expr

  • 29

    Se dice que una cadena de terminales W est en L (G) si, y slo si, S W. A la cadena W sed le llama frase de G.

    Si el lenguaje puede ser generado por una gramtica se dice que es lenguaje independiente del

    contexto.

    Ejemplo: La cadena (id + id) es una frase de la G (1), por que existe la derivacin:

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

    Derivacin por la derecha: Donde el no Terminal ms a la derecha se sustituye en cada paso.

    Ejemplo:

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

    Este tipo de gramticas que son susceptibles de ser analizados sintcticamente de forma

    descendente y mediante un anlisis predictivo, pertenecen al conjunto de gramticas denominado LL

    (1).

    A partir de este tipo de G se puede construir automticamente ASDP (Anlisis Sintctico

    Descendente Predictivos), que no son otra cosa que ASD sin retroceso.

    LL (1) donde: L = Anlisis de izquierda a derecha de la cadena de entrada, L = Derivacin por la

    izquierda y 1 = Basta con solo ver un token.

    Conjuntos de prediccin

    Son conjuntos de tokens que ayudan a predecir qu regla se debe aplicar para la variable que

    hay que derivar. Se construyen, como veremos a continuacin, a partir de los smbolos de las partes

    derechas de las producciones de la gramtica.

    El analizador consulta el siguiente token en la entrada y si pertenece al conjunto de prediccin de una

    regla (de la variable que hay que derivar), aplica esa regla. Si no puede aplicar ninguna regla, se

    produce un de error.

    CLCULO DE LOS CONJUNTOS DE PREDICCIN

    Los conjuntos de prediccin de una regla se calculan en funcin de los primeros smbolos que puede

    generar la parte derecha de esa regla, y a veces (cuando esa parte genera la cadena vaca) en funcin

    de los smbolos que pueden aparecer a continuacin de la parte izquierda de la regla en una forma

    sentencial.

    Clculo del conjunto de PRIMEROS

  • 30

    La funcin PRIMEROS se aplica a cadenas de smbolos de la gramtica ( (T N)* y devuelve un conjunto que puede contener cualesquiera terminales de la gramtica y puede contener a la cadena

    vaca, .

    Definicin:

    Si es una forma sentencial compuesta por una concatenacin de smbolos, PRIMEROS () es el conjunto de terminales que pueden aparecer iniciando las cadenas que pueden derivar (en cero o ms pasos) de . Definicin formal:

    a PRIMEROS() si a ( T {} ) / * apara alguna tira

    Algoritmo

    1. Si T, PRIMEROS () = {}

    2. Si N:

    Inicialmente, PRIMEROS () =

    Si aparece la produccin , PRIMEROS () = PRIMEROS () {}

    Si a1 a2 ... an entonces PRIMEROS() = PRIMEROS() PRIMEROS(a1 a2 ...an) y para el clculo de PRIMEROS(a1 a2 ... an) pueden darse dos casos:

    1. Si PRIMEROS(a1) entonces

    PRIMEROS() = PRIMEROS() PRIMEROS(a1)

    2. Si PRIMEROS(a1) entonces

    PRIMEROS() = PRIMEROS() ( PRIMEROS(a1){}) PRIMEROS(a2...an)

    y de nuevo pueden darse estos dos casos para PRIMEROS(a2 ... an) y siguientes, hasta an.

    Si i, PRIMEROS(ai) entonces

    PRIMEROS() = PRIMEROS() {}

    3. Para recoger todos los casos posibles habra que considerar que

    Si 1 | 2 | ... | n entonces

    PRIMEROS () = PRIMEROS(i)

    EJEMPLO 1:

    Sea la siguiente gramtica para expresiones aritmticas con sumas y multiplicaciones:

    E T E

    E + T E

    T F T

    T F T

    F ( E ) ident

    Clculo de los PRIMEROS de todos los no terminales de esta gramtica:

    PRIMEROS(E) = { + , }

    PRIMEROS(T) = { , }

    PRIMEROS(F) = { ( , ident }

    PRIMEROS(E) =(ETE, TN) PRIMEROS(T) =(TFT, FN) PRIMEROS(F) = { ( , ident }

    n

    i 1

  • 31

    EJEMPLO 2:

    Sea la gramtica siguiente:

    A A a

    A B C D

    B b

    B

    C c

    C

    D d

    D C e

    Calculamos los conjuntos de PRIMEROS de todas las variables de esta gramtica:

    PRIMEROS(C) = { c , }

    PRIMEROS(B) = { b , }

    PRIMEROS(D) = PRIMEROS(d) PRIMEROS(Ce) =

    = { d } ( ( PRIMEROS(C) {} ) PRIMEROS(e) ) = { d , c , e }

    PRIMEROS(A) = PRIMEROS(Aa) PRIMEROS(BCD) =(*) PRIMEROS(BCD)

    (*) Puesto que el miembro se calcula como PRIMEROS(A) que an es .

    = { b } PRIMEROS(CD) = { b , c } PRIMEROS(D) = { b , c , d , e }

    Clculo del conjunto de SIGUIENTES

    La funcin SIGUIENTES se aplica a variables de la gramtica (A N) y devuelve un conjunto

    que puede contener cualesquiera terminales de la gramtica y adems puede contener un smbolo

    especial, $, que representa el final de la cadena de entrada. Esto es equivalente a aadir una

    produccin adicional a la gramtica en la que el axioma, S, es definido como X S$.

    Definicin:

    Si A es un smbolo no terminal de la gramtica, SIGUIENTES(A) es el conjunto de

    terminales que pueden aparecer a continuacin de A en alguna forma sentencial derivada del smbolo

    inicial.

    Definicin formal:

    a SIGUIENTES(A) si a ( T {$} ) / S * Aapara algn par de tiras ,.

    Reglas para el clculo del conjunto de los SIGUIENTES

    1. Inicialmente, SIGUIENTES(A)=

    2. Si A es el smbolo inicial, entonces SIGUIENTES(A)=SIGUIENTES(A) {$} 3. (s1) Para cada regla de la forma:

    B A entonces SIGUIENTES(A)=SIGUIENTES(A) PRIMEROS()-{}

    4. (s2) Para cada regla de la forma:

    B A o bien B A en la que PRIMEROS() entonces

  • 32

    SIGUIENTES(A)=SIGUIENTES(A) SIGUIENTES(B)

    5. Repetir los pasos 3 y 4 hasta que no se puedan aadir ms smbolos a SIGUIENTES(A)

    NOTA:

    Las reglas (S1) y (S2) no son excluyentes. Primero habr que intentar aplicar (S1) y luego (S2)

    Slo en el caso de producciones del tipo B A, no tendr sentido intentar aplicar (S1).

    X E$

    SIGUIENTES(E) = F(E) y XE$ { ) , $ } S1

    SIGUIENTES(E) = E+TE y ETE SIGUIENTES(E) SIGUIENTES(E)== { ) , $ } S2

    SIGUIENTES(T) = E+TE PRIMEROS(E){}SIGUIENTES(E)SIGUIENTES(E) = S1

    = {+} SIGUIENTES(E) SIGUIENTES(E) = { + , ) , $ }

    SIGUIENTES(T) = TFT y TFT SIGUIENTES(T) SIGUIENTES(T) == { + , ) , $ } S2

    SIGUIENTES(F)= TFTyTFTPRIMEROS(T){}SIGUIENTES(T)SIGUIENTES(T)= S1 = { } { + , ) , $ } = { , + , ) , $ }

    Clculo del conjunto PREDICT:

    La funcin PREDICT se aplica a producciones de la gramtica (A a) y devuelve un

    conjunto, llamado conjunto de prediccin, que puede contener cualesquiera terminales de la

    gramtica y el smbolo $, pero nunca puede contener .

    Reglas para el clculo del conjunto PREDICT

    PREDICT(A ) =

    Si PRIMEROS() entonces = (PRIMEROS()-{}) {SIGUIENTES(A)}

    sino = PRIMEROS()

    EJEMPLO:

    Supngase la siguiente gramtica:

    S AB s

    A aSc eBf

    B bAd

    Calculamos los conjuntos de prediccin utilizando la regla adecuada en cada caso:

    PREDICT(S AB) = (PRIMEROS(AB){}) SIGUIENTES(S) = { a , e , b , c , $ }

    PREDICT(S s) = PRIMEROS(s) = { s }

    PREDICT(A aSc) = PRIMEROS(aSc) = { a }

    PREDICT(A eBf) = PRIMEROS(eEf) = { e }

    PREDICT(A ) = (PRIMEROS(){}) SIGUIENTES(A) = { b , d , c , $ }

    PREDICT(B bAd) = PRIMEROS(bAd) = { b }

    PREDICT(B ) = (PRIMEROS(){}) SIGUIENTES(B) = { f , c , $ }

    LA CONDICIN LL(1)

  • 33

    Para que una gramtica pertenezca al conjunto de gramticas LL(1) ha de cumplir la

    condicin LL(1).

    Para que la regla a aplicar sea siempre nica, se debe exigir que los conjuntos de prediccin

    de las reglas de cada no terminal sean disjuntos entres s.

    Si la gramtica es LL(1) y se puede realizar su anlisis sintctico en tiempo lineal.

    La condicin LL(1) es necesaria y suficiente para poder construir un ASDP para una gramtica.

    Condicin LL(1):

    Dadas todas las producciones de la gramtica para un mismo terminal:

    A 1 | 2 | ... | n A N

    se debe cumplir la siguiente condicin:

    i, j ( i j ) PREDICT(Ai) PREDICT(Aj) =

    Ejemplo 1:

    A a b B { a }

    A B b { b , c }

    B b { b }

    B c { c }

    EJEMPLO 2:

    Sea la siguiente gramtica:

    E E + T T

    T T F F

    F num ( E )

    PREDICT(E E+T) = PRIMEROS(E+T) = PRIMEROS(E) = { num , ( }

    PREDICT(E T) = PRIMEROS(T) = PRIMEROS(F) = { num , ( }

    PREDICT(T TF) = PRIMEROS(TF) = PRIMEROS(T) = { num , ( }

    PREDICT(T F) = PRIMEROS(F) = { num , ( }

    PREDICT(F num) = PRIMEROS(num) = { num }

    PREDICT(F (E) ) = PRIMEROS( (E) ) = { ( }

    MODIFICACIN DE GRAMTICAS NO LL(1)

    Existen caractersticas que, en el caso de ser observadas en una gramtica, garantizan que no

    es LL(1) (sin calcular los conjuntos de prediccin).

    Si la gramtica no es LL(1) no necesariamente debe tener alguna de estas caractersticas.

  • 34

    Existen mtodos para modificar gramticas que no son LL(1) y convertirlas en LL(1).

    ELIMINACIN DE LA AMBIGEDAD

    Cualquier gramtica ambigua no cumple LL(1).

    Si la gramtica no es ambigua no necesariamente es LL(1), pues puede presentar otros problemas.

    El problema de la ambigedad es el ms difcil de resolver pues no existe una metodologa para

    eliminarla y tampoco hay otra frmula para saber que una gramtica es ambigua (slo queda

    encontrar alguna sentencia que tenga dos rboles de anlisis sintctico distintos).

    La mejor opcin cuando se presenta una gramtica ambigua es replantear la gramtica por una

    equivalente (que genere el mismo lenguaje).

    FACTORIZACIN IZQUIERDA

    Si dos producciones alternativas de un smbolo A empiezan igual, no se sabr por cul de

    ellas seguir, se trata de reescribir las producciones de A para retrasar la decisin hasta haber visto lo

    suficiente de la entrada, se soluciona uno de los problemas que tenia la gramtica para no cumplir la

    condicin LL (1) como para elegir la opcin correcta.

    EJEMPLO: Sean las producciones:

    1) Sent if Expr then Sent else Sent

    2) Sent if Expr then Sent

    3) Sent Otras

    Para expandir Sent no se sabe si 1) o 2) con slo ver if.

    De hecho, un analizador sintctico descendente no sabra hasta ver el cuarto smbolo de esta

    produccin, si entonces llega else ya sabe que se trataba de la primera y si entra cualquier otro pero

    es tarde para el ASDP.

    Regla general para factorizar por la izquierda una gramtica

    Para todos los no terminales, A, de la gramtica, encontrar el prefijo ms largo comn a dos o ms

    alternativas suyas. Si entonces sustituir todas las producciones.

    A 1 | 2 | | n | i

    donde i representa a todas las alternativas que no empiezan por , por:

    A A | i

    A 1 | 2 | | n

  • 35

    Repetir el paso anterior hasta que no haya 2 alternativas de un no terminal con un prefijo comn.

    EJEMPLO:

    Sent if Expr then Sent else Sent

    Sent if Expr then Sent

    Sent Otras

    if Expr then Sent

    i Otras

    Con la gramtica factorizada queda:

    Sent if Expr then Sent Sent

    Sent Otras

    Sent else Sent

    Sent

    ELIMINACIN DE LA RECURSIVIDAD IZQUIERDA

    Los analizadores sintcticos descendentes no pueden manejar gramticas recursivas por la izquierda

    pues estaran en ciclos de recursividad infinita al ejecutarse.

    Cualquier gramtica recursiva por la izquierda no cumple la condicin LL (1).

    A A| A| | Am| | | | n

    Sustituir por: A 1A| 2A|| nA

    A 1A|2A|| mA

    EJEMPLO:

    Eliminar la recursividad izquierda de la gramtica de las expresiones aritmticas.

    1 E E + T E T T

    2 T T F | T / F | F

    F ( E ) | nm

    1 E E + T | T

    A A |

    2 T T F

    A A |

    Por tanto nos queda la siguiente gramtica:

    E T E

    E + T E T E

    T F T

    E T E

    E+ T E |

    T F T

    TF T |

  • 36

    T F T / F T

    F ( E ) | num

    IMPLEMENTACIN DE UN ANALIZADOR SINTCTICO DESCENDENTE

    RECURSIVO

    Es un mtodo de anlisis sintctico descendente que slo se puede aplicar en gramticas LL

    (1) y por tanto es un analizador sintctico descendente predictivo (ASDP).

    Consiste en un conjunto de funciones recursivas (una por cada variable de la gramtica) que

    son diseadas a partir de los elementos que definen cada una de las producciones de la gramtica.

    La secuencia de llamadas al procesar la cadena de entrada define implcitamente su rbol de

    anlisis sintctico.

    Smbolo de preanlisis

    Si esta metodologa es aplicable a las gramticas LL (1) es porque basta ver un nico token

    para saber qu hacer. Ese token se llama smbolo de preanlisis o LookAhead y ser pedido al

    analizador lxico cada vez que se necesite. Este token el que se busque en los conjuntos de

    prediccin.

    Funcin de emparejamiento (Match)

    Comprueba si el smbolo de preanlisis coincide con el terminal de la gramtica que, de

    acuerdo con los elementos de la produccin escogida debera aparecer en esa posicin.

    Tambin se encarga de la peticin del siguiente token al analizador lxico si se da la

    coincidencia o invoca a la funcin de error en caso contrario.

    Estructura

    FUNCIN Emparejar ( Parmetro de entrada: token; Usa variable global preanlisis ) SI preanlisis coincide con token ENTONCES

    Pedir el siguiente preanlisis al analizador lxico SINO

    Error Sintctico(Encontrado preanlisis, esperaba token)

    Si t es el token que el ASDR espera encontrar en la entrada y, la funcin Emparejar en C queda:

    void Emparejar ( int t )

    {

    if ( t == preanalisis )

    preanalisis = analex(); /* analex es el nombre que hemos dado al Analizador Lxico */

    else

    ErrorSintctico(preanalisis,t);

    }

  • 37

    Algoritmo para construir un ASDR

    1) Escribir una funcin por cada smbolo no terminal de la gramtica. Cada una llevar a cabo el anlisis de las producciones de dicho no terminal.

    2) Cuando este no terminal tenga distintas alternativas, para decidir durante su ejecucin cul de las producciones utilizar, se optar por aquella alternativa a cuyo conjunto de prediccin

    pertenezca el token de preanlisis.

    EN CASO DE QUE Preanlisis PERTENEZCA A

    PREDICT(a1): ... proceder segn alternativa a1 ...

    PREDICT(a2): ... proceder segn alternativa a2 ...

    ...

    FIN

    Si el token de preanlisis no pertenece a ninguno de los PREDICT, entonces se considerar error

    sintctico.

    3) Si una de las alternativas para el no terminal que se est analizando es la cadena vaca (A ), en ese caso no se har nada.

    4) Para analizar cada alternativa, se aplican distintas metodologas a los smbolos de la parte derecha de la produccin, en el mismo orden en el que aparecen, segn si son terminales o

    no:

    - Para cada A N hacemos una llamada a su funcin correspondiente. - Para cada a T hacemos una llamada a la funcin Emparejar con a como parmetro.

    5) La invocacin o puesta en marcha del ASDR se realiza mediante una llamada al smbolo inicial de la gramtica. Para hacer esa llamada se supone que el token de preanlisis habr

    sido inicializado por una llamada previa al analizador lxico.

    EJEMPLO: Sea la siguiente gramtica LL(1) con sus conjuntos de prediccin:

    S A { a , $ }

    S s { s }

    A a S c { a }

    A { c , $ }

    Supondremos que:

    - Estn definidos los tokens a, c y s - Se tiene definida una variable lexema como un array de caracteres - Ya se tiene implementada la funcin emparejar

    void S(void)

    {

    if ( preanalisis == a || preanalisis = FINFICHERO )

  • 38

    A();

    else if ( preanalisis == s )

    emparejar(s);

    else ErrorSintactico(lexema,a,s,FINFICHERO);

    /* encontrado 'lexema', esperaba 'a', 's' o fin de fichero */

    }

    void A(void)

    {

    if ( preanalisis == a )

    { emparejar(a); S(); emparejar(c); }

    else if ( preanalisis == c || preanalisis = FINFICHERO )

    ; /* produccin epsilon */

    else ErrorSintactico(lexema,a,c,FINFICHERO);

    }

    NOTA: A la funcin de error sintctico se le suele pasar como argumentos el lexema que ha

    producido el error (el del token de preanlisis) y los que esperaba en su lugar (los terminales que

    aparezcan en la unin de todos los conjuntos de prediccin de las reglas del no terminal al que

    pertenece la funcin).

    EJEMPLO 2: Sea G

    E T E

    E + T E T E

    T F T

    T F T / F T

    F ( E ) | num

    void E()

    {

    T(); E2();

    }

    void E2()

    {

    switch ( preanalisis ) {

    case MAS : Emparejar(MAS); T(); E2(); break;

    case MENOS : Emparejar(MENOS); T(); E2(); berak;

    case RPAR : case FDF : /* E e */ break;

    default : ErrorSintactico(lexema,MAS,MENOS,RPAR,FDF);

    }

    }

    void T()

    {

  • 39

    F(); T2();

    }

    void T2()

    {

    switch ( preanalisis ) {

    case POR : Emparejar(POR); F(); T2(); break;

    case DIV : Emparejar(DIV); F(); T2(); break;

    case MAS : case MENOS :

    case RPAR : case FDF : /* T e */ break;

    default : ErrorSintactico(lexema,POR,DIV,MAS,MENOS,RPAR,FDF);

    }

    }

    void F()

    {

    switch ( preanalisis ) {

    case NUM : Emparejar(NUM); break;

    case LPAR : Emparejar(LPAR); E(); Emparejar(RPAR); break;

    default : ErrorSintactico(lexema,NUM,LPAR);

    }

    }

    NOTA: Al final se debe comprobar que la cadena de entrada se ha analizado en su totalidad para dar

    como exitoso el anlisis. Como se indica:

    token = analex();

    S();

    if (token != FINFICHERO) error(token,lexema,{FINFICHERO});

    /* encontrado 'lexema', esperaba fin de fichero */

    ANALIZADORES SINTCTICOS DESCENDENTES DIRIGIDOS POR TABLA

    Se puede construir un analizador sintctico descendente predictivo utilizando una pila de

    smbolos (terminales y no terminales) en vez de haciendo llamadas recursivas.

    Para determinar qu produccin debe aplicarse a la vista de un terminal (token de preanlisis), se

    buscar en una tabla llamada tabla de anlisis.

  • 40

    Se debe construir la tabla (depende de la gramtica) y posteriormente aplicar el algoritmo.

    Procedimiento para construir tablas de anlisis LL (1)

    1. Las filas de la tabla se etiquetan con las variables de la gramtica.

    2. Las columnas se etiquetan con los terminales y el smbolo de fin de entrada, $. a. [En cada celda de la tabla se va a colocar la regla que se debe aplicar para analizar

    la variable de esa fila cuando el terminal de esa columna (o $) aparezca en la

    entrada (ese terminal o $ debe pertenecer al conjunto de prediccin de esa regla) ].

    3. Se calculan los conjuntos de prediccin para cada regla. 4. Para cada regla A de la gramtica, hacer:

    Para cada terminal a PREDICT(A ), adase A a Tabla[A,a.

    5. Cada entrada no definida de Tabla ser error sintctico.

    NOTA: Al implementar el algoritmo no es necesario almacenar la regla completa en la tabla sino

    slo los smbolos de su parte derecha (que es conveniente guardar al revs) o incluso es ms eficiente

    almacenar un nmero de regla que haga referencia a otra tabla con los smbolos de las partes

    derechas de las reglas.

    EJEMPLO: Sea G

    X E $

    E T E

    E + T E | T E |

    T F T

    T F T | / F T |

    F ( E ) | id

    1: PREDICT(E T E) = { ( , id } en las celdas [E,(] y [E,id] aadir ETE

    2: PREDICT(E+ T E) = {+} en la celda [E,+] aadir E+TE

    3: PREDICT(ET E) = {} en la celda [E,] aadir ETE

    4: PREDICT(E) = { ) , $ } en la celda [E,$] aadir E

    5: PREDICT(T F T) = { ( , id } en las celdas [F,(] y [F,id] aadir TFT

    6: PREDICT(T F T) = {} en la celda [T,] aadir FFT

    7: PREDICT(T / F T) = {/} en la celda [T,/] aadir F/FT

    8: PREDICT(T) = {+,,),$} en las celdas [T,+] [T, ] [T,)] [T,$] aadir T

    9: PREDICT(F( E ) ) = { ( } en la celda [F,)] aadir F (E)

    10: PREDICT(Fid) = {id} en la celda [F,id] aadir F id

    Todas las celdas vacas se marcan como error sintctico.

  • 41

    Tener en cuenta es que este tipo de analizador es predictivo, esto es que slo puede construir

    si la gramtica a analizar es LL (1). Esto en la tabla se refleja en el hecho de que no aparezcan dos

    producciones en la misma casilla.

    EJEMPLO: Sea una gramtica para las sentencias IF en Pascal:

    Sent if Expr then Sent Sent otras

    Sent else Sent

    Expr lgico

    Su tabla es:

    Podemos observar que la gramtica es ambigua pues existen dos producciones en la casilla sealada.

    Una vez que se tiene la tabla de anlisis ya se puede construir el ASDP.

    Algoritmo de ejecucin del Analizador Descendente Dirigido por Tabla:

    Entrada: cadena de elementos lxicos devueltos por el A.L.

    Salida: producciones que construyen su rbol de anlisis sintctico

    Pasos:

    push($)

    push(S)

    REPETIR

    A := Pila[tope] /* el smbolo que haya en el tope de la pila */

    a := analex( ) /* a es el smbolo de preanlisis */

    SI A es un terminal o $ ENTONCES

    SI A = a ENTONCES

    pop A

    a := analex( )

    SINO

    Error Sintctico ( encontrado lexema de a, esperaba A )

  • 42

    FINSI

    SINO /* A es un no terminal */

    SI Tabla[A,a= A c1 c2 ... ck ENTONCES

    pop(A)

    DESDE i := k HASTA 1 HACER push(ci) FINDESDE

    /* A efectos de traza se puede indicar que se usa A c1 c2 ... ck */

    SINO

    Error Sintctico(encontrado lexema de a, esperaba PREDICT( A

    i ) )

    FINSI

    FINSI

    HASTA A = $ /* La pila est vaca */

    EJEMPLO:

    La traza se realizar sobre la gramtica LL(1) de las expresiones aritmticas, tomando la tabla

    descrita antes. La entrada para la traza es: id + id id $.

    n

    i 1

  • 43

    La columna de PILA muestra el contenido de la pila en cada momento, quedando el fondo a

    su izquierda y la cima a su derecha, donde se van colocando los smbolos de las partes derechas de

    las producciones en orden inverso a como aparecen en dichas producciones.

    La columna ENTRADA representa lo que en cada paso resta por analizar de la cadena de

    entrada. El primer smbolo de la izquierda representa el smbolo de preanlisis. Cuando este smbolo

    coincide el terminal de la pila se eliminan ambos (el tope y el preanlisis) avanzando el anlisis al

    siguiente smbolo de la entrada.

    La columna SALIDA muestran los emparejamientos de tokens que se realizan y las

    producciones que se van aplicando de la tabla de anlisis para ir actualizando el contenido de la pila

    y construyendo el rbol de anlisis sintctico que se muestra a la derecha de la tabla.

    EJEMPLO:

    Sea G:

    S C A B { c }

    S a C b { a }

    A a S d { a }

    A { b , d , $ }

    B b { b }

    B { d , $ }

    C c { c } La tabla de anlisis:

  • 44

    La traza del anlisis para la cadena cacdb sera: