cuadernosintactico excelente

Upload: wilmar-augusto

Post on 19-Oct-2015

52 views

Category:

Documents


2 download

TRANSCRIPT

  • AANNLLIISSIISS SSIINNTTCCTTIICCOO

    EENN

    PPRROOCCEESSAADDOORREESS DDEE LLEENNGGUUAAJJEE

    Apuntes de Procesadores de Lenguaje

    M. Cndida Luengo Dez Juan Manuel Cueva Lovelle

    Francisco Ortn Soler Ral Izquierdo Castanedo Aquilino A. Juan Fuente Jose Emilio Labra Gayo

    Oviedo, Enero 2005

  • ii

  • i

    Tabla de Contenidos

    TEMA 4 FUNDAMENTOS DEL ANLISIS SINTCTICO ...............................1

    4.1 INTRODUCCIN .........................................................................................................................1 4.2 ESPECIFICACIN SINTCTICA DE LOS LENGUAJES DE PROGRAMACIN .................2

    4.2.1 Derivaciones y rboles sintcticos .............................................................................3 4.2.1.1 Ejemplo: gramtica de expresiones aritmticas ..................................................3

    4.2.2 Derivaciones ms a la izquierda y ms a la derecha..................................................4 4.2.2.1 Ejemplo ...............................................................................................................4

    4.2.3 Capacidad de descripcin de las gramticas de tipo 2...............................................6 4.2.4 Recursividad ..............................................................................................................7

    4.2.4.1 Ejemplo ...............................................................................................................7 4.2.5 Gramticas ambiguas.................................................................................................8

    4.2.5.1 Ejemplo ...............................................................................................................8 4.2.6 Conversin de gramticas ambiguas en no ambiguas................................................9

    4.2.6.1 Ejemplo: representacin de los arrays y llamada de funciones...........................9 4.2.6.2 Ejemplo: else danzante o ambiguo......................................................................9 4.2.6.3 Ejemplo: definicin de precedencia y asociatividad .........................................11

    4.2.7 Gramticas limpias y gramticas sucias ..................................................................14 4.2.8 Limpieza de gramticas ...........................................................................................14

    4.2.8.1 Teorema de los smbolos vivos .........................................................................15 4.2.8.2 Ejemplo .............................................................................................................15 4.2.8.3 Teorema de los smbolos accesibles..................................................................16 4.2.8.4 Ejemplo .............................................................................................................16 4.2.8.5 Anlisis automtico de la limpieza de gramticas.............................................16

    4.3 FORMAS NORMALES DE CHOMSKY Y GREIBACH..........................................................17 4.3.1 Forma Normal de Chomsky (FNC) .........................................................................17

    4.3.1.1 Teorema de la forma normal de Chomsky ........................................................17 4.3.1.2 Ejemplo .............................................................................................................18

    4.3.2 Forma Normal de Greibach (FNG)..........................................................................19 4.3.2.1 Teorema de la forma normal de Greibach.........................................................19 4.3.2.2 Ejemplo .............................................................................................................19

    4.4 TIPOS GENERALES DE ANALIZADORES SINTCTICOS .................................................20 4.5 SINTAXIS CONCRETA Y SINTAXIS ABSTRACTA .............................................................21

    TEMA 5 ANLISIS SINTCTICO DESCENDENTE ....................................23

    5.1 INTRODUCCIN .......................................................................................................................23 5.2 EL PROBLEMA DEL RETROCESO.....................................................................................................24

    5.2.1 Ejemplo de retroceso ...............................................................................................24 5.3 ANLISIS SINTCTICO DESCENDENTE CON RETROCESO ................................................................27

    5.3.1 Algoritmo de anlisis sintctico descendente con retroceso....................................27 5.3.2 Corolario ..................................................................................................................27

  • ii

    5.4 ANLISIS DESCENDENTE SIN RETROCESO ..................................................................................... 28 5.4.1 Gramticas LL(k).....................................................................................................28

    5.4.1.1 Teorema.............................................................................................................28 5.4.1.2 S-gramticas ......................................................................................................28 5.4.1.3 Corolario de la definicin de S-gramticas .......................................................29 5.4.1.4 Conjunto de smbolos INICIALES o cabecera..................................................30 5.4.1.5 Gramticas LL(1) simples .................................................................................31 5.4.1.6 Corolario de las gramticas LL(1) simples .......................................................31 5.4.1.7 Teorema de equivalencia entre gramticas LL(1) y S-gramticas ....................31 5.4.1.8 Conjunto de smbolos SEGUIDORES o siguientes ..........................................32 5.4.1.9 Conjunto de smbolos DIRECTORES ..............................................................34 5.4.1.10 Definicin de las gramticas LL(1) .............................................................34

    5.4.2 Condiciones de las gramticas LL(1).......................................................................35 5.4.2.1 Primera condicin de Knuth..............................................................................35 5.4.2.2 Segunda condicin de Knuth.............................................................................35 5.4.2.3 Tercera condicin de Knuth ..............................................................................35 5.4.2.4 Cuarta condicin de Knuth................................................................................36

    5.4.3 Transformacin de gramticas .................................................................................36 5.4.3.1 La recursividad a izquierdas..............................................................................36 5.4.3.2 Eliminacin de la recursividad a izquierdas ......................................................38 5.4.3.3 Factorizacin y sustitucin................................................................................41 5.4.3.4 Transformacin de gramticas mediante aspectos semnticos..........................44

    5.5 CONSTRUCCIN DE ANALIZADORES SINTCTICOS DESCENDENTES............................................... 45 5.5.1 Mtodos basados directamente en la sintaxis...........................................................45

    5.5.1.1 Reglas de construccin de diagramas sintcticos ..............................................45 5.5.1.2 Traduccin de reglas sintcticas a programas ...................................................46

    5.5.2 Analizadores sintcticos recursivos descendentes ...................................................50 5.5.3 Analizadores sintacticos descendentes dirigidos por tabla ......................................53 5.5.4 Construccin de analizadores sintcticos decendentes basados en autmatas de pila

    ..................................................................................................................................55 5.5.5 Analizadores sintcticos descendentes deterministas dirigidos por estructuras de

    datos .........................................................................................................................56 5.5.5.1 Traduccin de reglas sintcticas a estructuras de datos. Ejemplo: ....................58 5.5.5.2 Construccin de analizadores sintcticos descendentes genricos dirigidos por

    estructuras de datos ...........................................................................................58 5.6 TRATAMIENTO DE ERRORES SINTCTICOS .................................................................................... 58

    TEMA 6 ANLISIS SINTCTICO ASCENDENTE....................................... 63

    6.1 INTRODUCCIN....................................................................................................................... 63 6.2 ANALIZADORES LR ...................................................................................................................... 63

    6.2.1 Ejemplo de anlisis ascendente con retroceso .........................................................63 6.3 GRAMTICAS Y ANALIZADORES LR(K) ........................................................................................ 65 6.4 ESTRUCTURA Y FUNCIONAMIENTO DE UN ANALIZADOR LR ......................................................... 65

    6.4.1 Ejemplo ....................................................................................................................67 6.5 ALGORITMO DE ANLISIS LR ....................................................................................................... 68 6.6 GRAMTICAS LR(K) - LL(K)........................................................................................................ 69 6.7 TRATAMIENTO DE ERRORES SINTCTICOS ................................................................................... 70 6.8 GENERADORES DE PROCESADORES DE LENGUAJES ...................................................................... 71

  • iii

    6.8.1 Estructura.................................................................................................................71 6.8.2 Caractersticas..........................................................................................................72 6.8.3 Clasificacin ............................................................................................................73 6.8.4 Ventajas ...................................................................................................................74 6.8.5 Generadores de analizadores sintcticos..................................................................75

    6.8.5.1 Lex/Yacc ...........................................................................................................76 6.8.5.2 Antlr ................................................................................................................129 6.8.5.3 JavaCC ............................................................................................................137

    ANEXO I: ALGORITMO DE DECISIN ...........................................................141 PASO 1: Encontrar los smbolos no terminales y producciones anulables ................141 PASO 2: Construccin de la relacin EMPIEZA DIRECTAMENTE CON .............144 PASO 3: Construccin de la relacin EMPIEZA CON .............................................146 PASO 4: Clculo del conjunto de smbolos INICIALES de cada no terminal ..........147 PASO 5: Clculo de los conjuntos INICIALES de cada produccin.........................148 PASO 6: Construccin de la relacin ESTA SEGUIDO DIRECTAMENTE POR...148 PASO 7: Construccin de la relacin ES FIN DIRECTO DE ...................................150 PASO 8: Construccin de la relacin ES FIN DE......................................................152 PASO 9: Construccin de la relacin ESTA SEGUIDO POR...................................152 PASO 10: Calcular el conjunto de seguidores de cada no terminal anulable.............153 PASO 11: Calcular el conjunto de smbolos directores .............................................153

    ANEXO II: ANALIZADOR SINTCTICO GENERADO CON YACC............153

    EJERCICIOS PROPUESTOS.................................................................................166

    BIBLIOGRAFIA.......................................................................................................169

  • Anlisis Sintctico en Procesadores de Lenguaje

    1

    TEMA 4 FUNDAMENTOS DEL ANLISIS SINTCTICO

    4.1 INTRODUCCIN El anlisis sintctico (parser en lengua inglesa) toma los tokens que le enva el

    analizador lxico y comprueba si con ellos se puede formar alguna sentencia vlida del lenguaje. Recurdese que se entiende por sintaxis como el conjunto de reglas formales que especifican como se construyen las sentencias de un determinado lenguaje.

    La sintaxis de los lenguajes de programacin habitualmente se describe mediante gramticas libres de contexto (o gramticas tipo 2), G = { S, VT, VNT, P } donde:

    S: el axioma o smbolo inicial

    VT : conjunto de terminales, los componentes lxicos o tokens

    VNT : conjunto de no-terminales

    P: conjunto de reglas de produccin de la forma:

    VNT X1, ... , Xn con Xi (VT VNT)*

    utilizando para ello algn tipo de notacin como por ejemplo, las notaciones BNF y EBNF. Esta especificacin ofrece numerosas ventajas:

    3 Una gramtica da una especificacin sintctica precisa, y fcil de comprender, de un lenguaje de programacin.

    3 Para ciertas clases de gramticas se puede construir automticamente un analizador sintctico, que determina si un programa est bien construido. Como beneficio adicional, el proceso de construccin del analizador sintctico puede revelar ambigedades sintcticas y otras dificultades para la construccin del parser que de otra forma no sern detectadas en la fase de diseo inicial de un lenguaje y que podran se arrastradas a su compilador.

    3 Una gramtica bien diseada da una estructura al lenguaje de programacin que se utiliza en la traduccin del programa fuente en cdigo objeto correcto y para la deteccin de errores. Existen herramientas que a partir de la descripcin de la gramtica se puede generar el cdigo del analizador sintctico.

    3 Los lenguajes de programacin despus de un periodo de tiempo, adquieren nuevas construcciones y llevan a cabo tareas adicionales. Estas nuevas construcciones se pueden aadir ms fcilmente al lenguaje cuando hay una implementacin basada en una descripcin gramatical del lenguaje.

  • Anlisis Sintctico en Procesadores de Lenguaje

    2

    Funciones del analizador sintctico:

    3 Comprobar si la cadena de tokens proporcionada por el analizador lxico puede ser generada por la gramtica que define el lenguaje fuente (gramtica libre del contexto, GLC).

    3 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 tokens. El rbol sintctico se utilizar como representacin intermedia en la generacin de cdigo.

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

    El papel del analizador sintctico dentro de un procesador de lenguaje puede representarse segn el esquema de la figura 1.

    Tablade

    smbolos

    Gramtica Libre de Contexto

    Analizadorlxico

    Analizadorsintctico

    Analizadorsemntico

    token

    pidesiguientetoken

    representacin

    intermediarbolsintctico

    rogramafuente

    Gestor deerrores

    Figura 1: Interfaces del analizador sintctico

    El anlisis sintctico se puede considerar como una funcin que toma como entrada la secuencia de componentes lxicos (tokens) producida por el anlisis lxico y produce como salida el rbol sintctico. En realidad, el anlisis sintctico hace una peticin al anlisis lxico del token siguiente en la entrada (los smbolos terminales) conforme lo va necesitando en el proceso de anlisis.

    4.2 ESPECIFICACIN SINTCTICA DE LOS LENGUAJES DE PROGRAMACIN

    Habitualmente la estructura sintctica de los lenguajes de programacin se especifica mediante Gramticas Libres de Contexto (GLC).

    Pregunta: Si las expresiones regulares son un caso particular de GLC, por qu no se incluye la especificacin lxica como parte de la sintaxis?

    Respuesta: Los AFD son muy sencillos de implementar y son muy eficientes frente a los autmatas de pila necesarios para reconocer las GLC, la eficiencia del procesador de lenguaje se vera comprometida.

  • Anlisis Sintctico en Procesadores de Lenguaje

    3

    4.2.1 Derivaciones y rboles sintcticos Analizar sintcticamente una cadena de tokens es encontrar para ella un rbol

    sintctico o derivacin, que tenga como raz el smbolo inicial de la gramtica libre de contexto y mediante la aplicacin sucesiva de sus reglas de derivacin se pueda alcanzar dicha cadena como hojas del rbol sintctico. En caso de xito la sentencia pertenece al lenguaje generado por la gramtica, y puede proseguirse el proceso de compilacin. En caso contrario, es decir cuando no se encuentra el rbol que genera dicha cadena, se dice entonces que la sentencia no pertenece al lenguaje, y el compilador emite un mensaje de error, pero el proceso de compilacin trata de continuar. Algunos compiladores paran el proceso de compilacin cada vez que encuentran un error, en ellos es necesario realizar tantas compilaciones como errores tendra el programa fuente.

    4.2.1.1 Ejemplo: gramtica de expresiones aritmticas

    Supongamos que se desea construir una gramtica G = {VN, VT, S, P} que describe un lenguaje basado en la utilizacin de expresiones aritmticas con sumas, diferencias, productos, divisiones, potenciacin, parntesis, y menos unario. Este lenguaje tambin permitir el uso de constantes e identificadores de variables. La gramtica est compuesta por un vocabulario terminal VT formado por los smbolos de los operadores, parntesis y los tokens constante e identificador. El vocabulario no terminal VN slo contendr el smbolo no terminal . El smbolo inicial S tambin ser . La gramtica G queda tal y como se muestra a continuacin:

    VT = {+, *, /, ^, (, ), -, identificador, constante} VN = { } S =

    Las reglas de produccin P que en un principio representaran al lenguaje se muestran a continuacin numeradas del (1) al (9). La numeracin se utilizar para indicar la regla que se aplica en cada derivacin.

    (1) ::= + (2) ::= * (3) ::= - (4) ::= / (5) ::= ^ (6) ::= - (7) ::= ( ) (8) ::= identificador (9) ::= constante

    Sea la expresin - ( a * 9 ) se desea saber si pertenece o no al lenguaje, para lo cual se pretende alcanzar a partir de derivaciones desde el smbolo inicial de la gramtica, construyndose el rbol de anlisis sintctico de la figura 2. El rbol sintctico no indica el orden seguido para alcanzar la cadena incgnita. Para indicar el orden de aplicacin de las derivaciones con las que se construy el rbol se muestran las derivaciones siguientes, sealando encima de la flecha el nmero de la regla aplicada:

  • Anlisis Sintctico en Procesadores de Lenguaje

    4

    (6) - (7) -(

  • Anlisis Sintctico en Procesadores de Lenguaje

    5

    Determinar los rboles sintcticos ms a la izquierda y ms a la derecha que reconocen la cadena a*(a+b).

    Para determinar el rbol ms a la izquierda se parte del smbolo inicial S y en la variable parse se van poniendo las producciones aplicadas, utilizando nmeros para indicar los cdigos de cada regla aplicada. Siempre se expansiona el no terminal ms a la izquierda en el rbol hasta alcanzar un smbolo terminal. En las figuras siguientes se observa como se alcanza el rbol ms a la izquierda aplicando las producciones por el orden indicado por los nmeros 23465124647.

    parse= 2

    parse= 23

    parse= 234

    S

    T

    S

    T

    T * F

    S

    T

    T * F

    F

    parse= 234561

    S

    T

    T * F

    F

    a

    ( S )

    S + T

    parse= 23465

    S

    T

    T * F

    F

    a

    ( S )

    parse= 2346

    S

    T

    T * F

    F

    a

    S

    T

    T * F

    F

    a

    ( S )

    S + T

    T

    parse= 2346512

    S

    T

    T * F

    F

    a

    ( S )

    S + T

    T

    F

    parse= 23465124

    S

    T

    T * F

    F

    a

    ( S )

    S + T

    T

    F

    a

    parse= 234651246

    S

    T

    T * F

    F

    a

    ( S )

    S + T

    T

    F

    a

    F

    parse= 2346512464

    S

    T

    T * F

    F

    a

    ( S )

    S + T

    T

    F

    a

    F

    b

    parse Izdo= 23465124647

    Para obtener el rbol ms a la derecha se parte del smbolo inicial S y se van aplicando las producciones de forma que se eligen en primer lugar las expansiones del smbolo no terminal ms a la derecha en el rbol. As en la variable produccin utilizada (p.u.) se van colocando los nmeros de las producciones utilizadas. En las figuras siguientes puede observarse el orden de sustitucin hasta alcanzar el rbol ms a la derecha representado por los nmeros 23514724646.

  • Anlisis Sintctico en Procesadores de Lenguaje

    6

    p.u.= 235

    S

    T

    T * F

    ( S )p.u.= 23

    S

    T

    T * Fproduccin

    S

    T

    utilizada= 2

    S

    T

    T * F

    ( S )

    S + T

    F

    b

    p.u.= 235147

    S

    T

    T * F

    ( S )

    S + T

    Fp.u.= 23514

    S

    T

    T * F

    ( S )

    S + T

    p.u.= 2351

    S

    T

    T * F

    ( S )

    S + T

    T

    F

    F

    b

    p.u.= 23514724

    S

    T

    * F

    ( S )

    S + T

    T F

    b

    p.u.= 2351472

    S

    T

    T * F

    ( S )

    S + T

    T

    F

    a

    F

    b

    p.u.= 235147246

    S

    T

    T * F

    F

    a

    ( S )

    S + T

    T

    F

    a

    F

    b

    p.u.= 23514724646

    S

    T

    T * F

    F ( S )

    S + T

    T

    F

    a

    F

    b

    p.u.= 2351472464

    Puede observarse que los rboles finales alcanzados son los mismos aunque por distintos caminos. En general puede ocurrir que el rbol ms a la izquierda y el rbol ms a la derecha no sea el mismo, dando lugar a problemas de ambigedad tal y como se estudia en el apartado 4.2.4.

    4.2.3 Capacidad de descripcin de las gramticas de tipo 2 La mayora de las construcciones de los lenguajes de programacin implican

    recursividad y anidamientos y las gramticas libres de contexto pueden representar este tipo de especificaciones, sin embrago, existen ciertos aspectos de los lenguajes de

  • Anlisis Sintctico en Procesadores de Lenguaje

    7

    programacin que no se pueden representar. A estos aspectos se les llama aspectos semnticos, y son aspectos en general dependientes del contexto. Por ejemplo, el problema de declaracin de los identificadores antes de su uso.

    Por este motivo, la definicin sintctica de los lenguajes de programacin viene dada habitualmente en dos partes. La mayor parte de la sintaxis se describe por gramticas libres de contexto, especificadas en notacin BNF o EBNF y el resto de la sintaxis, que no se puede describir por medio de gramticas libres de contexto, se presenta como un aadido en lenguaje natural, y se trata en el compilador en la parte de anlisis semntico. Tambin se amplan las gramticas libres de contexto con atributos, condiciones y reglas semnticas, con el objeto de definir las especificaciones semnticas.

    Ejemplo: llamada a funciones

    En la llamada a subrutinas se ha de comprobar que el nmero de argumentos coincida con el nmero de parmetros ficticios. Esto no lo pueden describir las gramticas libres de contexto. Esta verificacin se suele hacer en la fase de anlisis semntico. Otra solucin es la que utiliza el lenguaje C ANSI obligando a utilizar la definicin de funciones prototipo.

    4.2.4 Recursividad Las reglas de produccin de una gramtica estn definidas de forma que al realizar

    sustituciones dan lugar a recursividades. Entonces se dice que una regla de derivacin es recursiva si es de la forma:

    AA Si es nula, es decir AA se dice que la regla de derivacin es recursiva a

    izquierda. De la misma forma AA es recursiva a derecha (vase figura 3).

    Recursividad a Izquierda

    A

    A

    A

    A

    Recursividad a Derecha

    A

    A

    A

    A

    Figura 3: Recursividad a izquierdas y a derechas

    Los analizadores sintcticos que trabajan con derivaciones ms a la izquierda deben evitar las reglas de derivacin recursivas a izquierda, pues entraran en un bucle infinito.

    4.2.4.1 Ejemplo

    Sea la gramtica siguiente que describe nmeros enteros e identificadores:

  • Anlisis Sintctico en Procesadores de Lenguaje

    8

    | | |

    sus rboles sintcticos son los de la figura 4.

    dgito>

    Figura 4: rboles sintcticos recursivos

    4.2.5 Gramticas ambiguas Una sentencia generada por una gramtica es ambigua si existe ms de un rbol

    sintctico para ella. Una gramtica es ambigua si genera al menos una sentencia ambigua, en caso contrario es no ambigua. Ntese que se llama a la gramtica ambigua y no al lenguaje que describe dicha gramtica. Hay muchas gramticas equivalentes que pueden generar el mismo lenguaje, algunas son ambiguas y otras no. Sin embargo existen ciertos lenguajes para los cuales no pueden encontrarse gramticas no ambiguas. A tales lenguajes se les denomina ambiguos intrnsecos. Por ejemplo el lenguaje {xi, yj, zk / i=j o j=k} es un lenguaje ambiguo intrnseco.

    El grado de ambigedad de una sentencia se caracteriza por el nmero de rboles sintcticos distintos que la generan.

    La ambigedad de una gramtica es una propiedad indecidible, lo que significa que no existe ningn algoritmo que acepte una gramtica y determine con certeza y en un tiempo finito si la gramtica es ambigua o no.

    4.2.5.1 Ejemplo

    Sea la gramtica de manejo de expresiones mostrada en el apartado 4.2.1.1.Se puede comprobar que la sentencia: 5-C*6 tiene dos derivaciones ms a la izquierda diferentes, y cuyos rboles

    EXP> -

    constante-

    5-*

    5-dentificador*

    5-C*constante

    5-C*6

    *

    -*

    constante-*

    5-identificador*

    5-C*constante

    5-C*6

  • Anlisis Sintctico en Procesadores de Lenguaje

    9

    EXP

    EXP EXP-

    EXP EXP*

    identificador constante

    c 6

    constante

    5

    EXP

    EXP EXP*

    EXP EXP-

    identificador constante

    5 c

    constante

    6

    Figura 5: rbol 1 Figura 6: rbol 2

    El rbol de anlisis sintctico de la figura 5 refleja la precedencia habitual de matemticas de la operacin sustraccin sobre la multiplicacin. Mientras que en el rbol de la figura 6 no se respeta esta precedencia.

    4.2.6 Conversin de gramticas ambiguas en no ambiguas Se ha indicado anteriormente que la propiedad de ambigedad es indecidible, es decir,

    no existe ni puede construirse un algoritmo que, tomando una gramtica en BNF, determine con certeza, y en plazo finito de tiempo, si es ambigua o no. Sin embargo, se han desarrollado las condiciones que, de cumplirse, garantizan la no ambigedad, aunque en caso de que no se cumplan no puede afirmarse nada. Son condiciones suficientes pero no necesarias. As, las gramticas del tipo LL(k) y LR(k), que se estudiarn en otros apartados siguientes a ste, no son ambiguas, pero una gramtica que no sea LL(k) ni LR(k) no puede decirse que sea ambigua.

    Una gramtica ambigua produce problemas al analizador sintctico, por lo que interesa construir gramticas no ambiguas.

    Sin embargo, en algunos lenguajes de programacin, la ambigedad sintctica existe y se deber eliminar con consideraciones semnticas.

    4.2.6.1 Ejemplo: representacin de los arrays y llamada de funciones

    La representacin de los elementos de un array puede dar lugar a ambigedades, pues se puede confundir la llamada a una funcin con un elemento de un array. As la expresin M(I,J,K) es ambigua, puede considerarse como el elemento Mi,j,k del array, y tambin la llamada a la subrutina M con los parmetros I,J,K.

    Los lenguajes Pascal, C, C++, y Algol 60 resuelven esta ambigedad empleando corchetes para representar los arrays.

    El lenguaje FORTRAN no tiene declaracin obligatoria de variables ni de subrutinas, pero resuelve la ambigedad obligando a declarar las funciones no estndar. La llamada a subrutinas no constituye ambigedad pues se deben hacer con la sentencia CALL. El lenguaje PL/I resuelve la ambigedad con la declaracin obligatoria de todas las variables.

    4.2.6.2 Ejemplo: else danzante o ambiguo

    Una sentencia alternativa simple es de la forma siguiente:

  • Anlisis Sintctico en Procesadores de Lenguaje

    10

    ::= if then

    | if then else | otra_sentencia

    Puede darse el caso de que la sentencia que va despus del then sea otra sentencia alternativa, es decir se produce una sentencia if-then-else anidada de la forma:

    if E1 then if E2 then S1 else S2

    En este caso se produce una ambigedad pues la parte correspondiente al else puede asociarse a dos if, lo que da lugar a dos rboles sintcticos, que se muestran en las figuras 7 y 8.

    IF E1 THEN

    IF E2 THEN S1 ELSE S2

    Figura 7: rbol 1, el else se asocia con el if anterior ms cercano

    IF E1 THEN IF E2 THEN S1 ELSE S2

    Figura 8: rbol 2, el else se asocia con el primer if

    La mayor parte de los lenguajes de programacin con sentencias condicionales de este tipo utilizan el primer rbol sintctico (Fig. 7), es decir utilizan la regla el else se empareja con el if anterior ms cercano. Si se quisiera asociar la parte else con la sentencia if anterior se deber recurrir al uso de palabras reservadas, llaves, etc.

    Ejemplo: if (x != 0) {if (y == 1/x) ok = TRUE;} else z = 1/x;

    Esta regla elimina la ambigedad y se puede incorporar a la gramtica. Se debe, por tanto, construir una gramtica equivalente que elimine dicha ambigedad. La idea es que una sentencia que aparezca entre un tTHEN y un ELSE debe estar emparejada, es decir no debe terminar con un THEN sin emparejar seguido de cualquier sentencia, porque entonces el ELSE estara obligado a concordar con este THEN no emparejado. As sentencia emparejada tan solo puede ser una sentencia alternativa IF-THEN-ELSE que no contenga sentencias sin emparejar o cualquier otro tipo de sentencia diferente de la alternativa. La nueva gramtica equivalente ser la siguiente:

  • Anlisis Sintctico en Procesadores de Lenguaje

    11

    | if then else

    | otra_sentencia if then

    | if then else 0 | 1

    4.2.6.3 Ejemplo: definicin de precedencia y asociatividad

    Una de las principales formas de evitar la ambigedad es definiendo la precedencia y asociatividad de los operadores.

    As el lenguaje C est basado en el uso intensivo de operadores, con una definicin estricta de las precedencias y asociatividades de cada uno de ellos. Volvamos otra vez a la gramtica de expresiones ya utilizada en el ejemplo 4.2.1.1. Dicha gramtica era ambigua debido a problemas de precedencia y asociatividad de sus operadores. En este ejemplo se mostrar como se refleja la precedencia y asociatividad en la gramtica para evitar la ambigedad.

    3 Se define el orden de precedencia de evaluacin de las expresiones y los operadores. A continuacin se presenta el orden de precedencia de mayor a menor precedencia:

    1) ( ) identificadores constantes

    2) - (menos unario)

    3) ^ (potenciacin)

    4) * /

    5) + -

    3 La asociatividad se define de forma diferente para el operador potenciacin que para el resto de los operadores. As el operador ^ es asociativo de derecha a izquierda:

    a ^ b ^ c = a ^ (b ^ c)

    mientras que el resto de los operadores binarios sern asociativos de izquierda a derecha, si hay casos de igual precedencia.

    a-b-c= (a-b)-c a+b-c= (a+b)-c

    a*b/c= (a*b)/c

    Estas dos propiedades, precedencia y asociatividad, son suficientes para convertir la gramtica ambigua basada en operadores en no ambigua, es decir, que cada sentencia tenga slo un rbol sintctico.

  • Anlisis Sintctico en Procesadores de Lenguaje

    12

    Para introducir las propiedades anteriores de las operaciones en la gramtica se tiene que escribir otra gramtica equivalente en la cual se introduce un smbolo no terminal por cada nivel de precedencia.

    4.2.6.3.1 Nivel de precedencia 1

    Se introduce el no terminal para describir una expresin indivisible, y con mxima precedencia, por lo tanto

    ::= ( ) | identificador | constante

    4.2.6.3.2 Nivel de precedencia 2 Se introduce el no terminal , que describe el menos unario y el no

    terminal de precedencia superior.

    ::= - | 4.2.6.3.3 Nivel de precedencia 3

    El siguiente no terminal que se introduce es que describe los operadores del siguiente nivel de precedencia.

    ::= ^ | Hay que sealar que el orden es fundamental. As ^

    obliga a expresiones del tipo a ^ b ^ c a agruparse como a ^ (b ^ c) siendo su rbol sintctico el representado en la figura 9.

    ^

    identificador

    a

    ^

    identificador

    b

    identificador

    c

    Figura 9: rbol de anlisis sintctico de a^b^c

  • Anlisis Sintctico en Procesadores de Lenguaje

    13

    4.2.6.3.4 Nivel de precedencia 4

    El siguiente no terminal que se introduce es , que es una secuencia de uno o ms factores conectados con operadores de nivel de precedencia 4, es decir: multiplicacin y divisin.

    ::= * | / |

    El orden de esta produccin obliga a que expresiones del tipo:

    a * b / c signifique (a * b) / c

    4.2.6.3.5 Nivel de precedencia 5

    Por ltimo se introduce el no terminal que representar a conectado a otro con operadores de menor precedencia: adicin y sustraccin.

    ::= + | - |

    4.2.6.3.6 Gramtica equivalente no ambigua

    Entonces la nueva gramtica no ambigua ser GNA= (VN, VT, S, P) donde:

    VN= {, , , , } VT= {identificador, constante, (, ), ^, *, /, +, -} S=

    y las producciones P:

    ::= + | - |

    ::= * | / |

    ::= ^ | ::= - | ::= ( ) | identificador | constante

    Entonces el rbol de anlisis sintctico de la sentencia a * c + d ^ 4 se muestra en la figura 10. Sin embargo esta gramtica es recursiva a izquierdas, este inconveniente se resolver en el ejemplo del apartado 5.4.5.2.2.

  • Anlisis Sintctico en Procesadores de Lenguaje

    14

    +

    * ^

    identificador

    a

    identificador

    c

    identificador

    d

    constante

    4

    Figura 10: rbol de anlisis sintctico de a*c+d^4

    4.2.7 Gramticas limpias y gramticas sucias Las gramticas de los lenguajes de programacin estn formadas por un conjunto de

    reglas, cuyo nmero suele ser bastante amplio, lo cual incide en la ocultacin de distintos problemas que pueden producirse, tales como tener reglas que produzcan smbolos que no se usen despus, o que nunca se llegue a cadenas terminales. Todo esto se puede solventar realizando la transformacin de la gramtica inicial "sucia" a una gramtica "limpia". A continuacin se formalizarn estos conceptos por medio de definiciones.

    3 Smbolo muerto: es un smbolo no terminal que no genera ninguna cadena de smbolos terminales.

    3 Smbolo inaccesible: es un smbolo no terminal al que no se puede llegar por medio de producciones desde el smbolo inicial.

    3 Smbolo extrao: se denomina as a todo smbolo muerto o inaccesible. 3 Gramtica sucia: es toda gramtica que contiene smbolos extraos. 3 Gramtica limpia: es toda gramtica que no contiene smbolos extraos. 3 Smbolo vivo: es un smbolo no terminal del cual se puede derivar una cadena

    de smbolos terminales. Todos los smbolos terminales son smbolos vivos. Es decir son smbolos vivos lo que no son muertos.

    3 Smbolo accesible: es un smbolo que aparece en una cadena derivada del smbolo inicial. Es decir, aquel smbolo que no es inaccesible.

    4.2.8 Limpieza de gramticas En el apartado anterior se han definido algunos problemas que pueden presentarse en

    una gramtica. Por lo tanto es norma general que toda gramtica en bruto ha de limpiarse con el objetivo de eliminar todos los smbolos extraos.

    Existen algoritmos para depurar y limpiar las gramticas sucias. El mtodo consiste en detectar en primer lugar todos los smbolos muertos, y a continuacin se detectan todos los smbolos inaccesibles. Es importante seguir este orden, puesto que la eliminacin de smbolos muertos puede generar nuevos smbolos inaccesibles.

  • Anlisis Sintctico en Procesadores de Lenguaje

    15

    Los algoritmos que se utilizan en la limpieza de gramticas se basan en los teoremas que se enunciarn a continuacin sobre los smbolos vivos y los smbolos accesibles.

    4.2.8.1 Teorema de los smbolos vivos

    Si todos los smbolos de la parte derecha de una produccin son vivos, entonces el smbolo de la parte izquierda tambin lo es.

    La demostracin es obvia. Este teorema se utiliza para construir algoritmos de deteccin de smbolos muertos. El procedimiento consiste en iniciar una lista de no terminales que sepamos a ciencia cierta que son smbolos vivos, y aplicando el teorema anterior para detectar otros smbolos no terminales vivos para aadirlos a la lista. Dicho de otra forma, los pasos del algoritmo son:

    1. Hacer una lista de no-terminales que tengan al menos una produccin sin smbolos no terminales en la parte derecha.

    2. Dada una produccin, si todos los no-terminales de la parte derecha pertenecen a la lista, entonces podemos incluir al no terminal de la parte izquierda.

    3. Cuando no se puedan incluir ms smbolos mediante la aplicacin del paso 2, la lista contendr todos los smbolos vivos, el resto sern muertos.

    4.2.8.2 Ejemplo

    Sea la gramtica expresada en BNF:

    ::= a | d ::= b

    ::= e | de ::= g | h ::= f

    ::= t | v Determinar los smbolos muertos.

    Se aplican los pasos:

    1. Confeccin de la lista: slo hay un smbolo no terminal con el cual comenzar la lista.

    2. Aplicando el teorema se incluyen en la lista:

    3. No se puede aplicar el teorema ms veces, por lo tanto la lista de smbolos vivos est completa y los smbolos y son no terminales muertos.

  • Anlisis Sintctico en Procesadores de Lenguaje

    16

    4.2.8.3 Teorema de los smbolos accesibles

    Si el smbolo no terminal de la parte izquierda de una produccin es accesible, entonces todos los smbolos de la parte derecha tambin lo son.

    La demostracin es obvia. El teorema se puede utilizar para construir algoritmos, consistiendo stos en el siguiente procedimiento: se hace una lista inicial de smbolos no terminales que se sabe a ciencia cierta que son accesibles, y aplicando el teorema para detectar nuevos smbolos accesibles para aadir a la lista, hasta que no se pueden encontrar ms.

    Los pasos a seguir son:

    1. Se comienza la lista con un nico no terminal, el smbolo inicial.

    2. Si la parte izquierda de la produccin est en la lista, entonces se incluyen en la misma a todos los no terminales que aparezcan en la parte derecha.

    3. Cuando ya no se puedan incluir ms smbolos mediante la aplicacin del paso 2, la lista contendr todos los smbolos accesibles, y el resto ser inaccesible.

    4.2.8.4 Ejemplo

    Sea la siguiente gramtica en notacin BNF:

    ::= a | ::= c d

    ::= e | f ::= g | h t ::= x | y | z

    Determinar los smbolos inaccesibles

    Aplicando los pasos:

    1. Confeccin de la lista:

    2. Se incluyen en la lista:

    3. No se puede aplicar ms veces el paso, luego la lista de smbolos accesibles est completa, y los no terminales inaccesibles son:

    4.2.8.5 Anlisis automtico de la limpieza de gramticas

    Los algoritmos de limpieza de gramticas son fciles de programar, y comprueban si las gramticas son limpias. El primer paso para el tratamiento de cualquier gramtica es la eliminacin de los smbolos extraos. En la Universidad de Oviedo se ha desarrollado un

  • Anlisis Sintctico en Procesadores de Lenguaje

    17

    analizador de gramticas LL(1)1 que toma como entrada una gramtica descrita en el formato BNF sin la opcin alternativa e indica si la gramtica es LL(1) o no sealando las reglas de la gramtica que se lo impiden. El primer paso de este analizador es verificar si la gramtica es limpia. La gramtica de los ejemplos anteriores debe introducirse en el formato siguiente:

    ::= A

    ::=

    ::= C D

    ::= E

    ::= F

    ::= G

    ::= H T

    ::= X

    ::= Y

    ::= Z

    El analizador indicara que la gramtica no es limpia. En el men correspondiente se puede obtener la relacin de smbolos no accesibles. En este caso, NOTER3 y NOTER4.

    4.3 FORMAS NORMALES DE CHOMSKY Y GREIBACH

    Sucede con frecuencia en lingstica matemtica, que en algunas ocasiones es imprescindible que las gramticas se hallen dispuestas de una forma especial. Es decir, se trata de obtener una gramtica equivalente, que genera el mismo lenguaje, pero que debe cumplir unas especificaciones determinadas. A continuacin se muestran las dos formas normalizadas ms frecuentes, que se emplean en los lenguajes formales y sus aplicaciones.

    4.3.1 Forma Normal de Chomsky (FNC) Una gramtica se dice que est en la Forma Normal de Chomsky si sus reglas son de

    una de estas formas:

    A BC

    A a

    Siendo A, B, C no terminales y a un terminal.

    4.3.1.1 Teorema de la forma normal de Chomsky

    Toda gramtica libre de contexto sin la cadena vaca tiene una gramtica equivalente cuyas producciones estn en la Forma Normal de Chomsky.

    1 Las condiciones de las gramticas LL(1) se definen en el tema 5

  • Anlisis Sintctico en Procesadores de Lenguaje

    18

    4.3.1.2 Ejemplo

    Sea la gramtica G= ( VN={S, A, B}, VT={a, b}, P, S) cuyas producciones son:

    S bA|aB A bAA | aS | a B aBB | bS | b

    encontrar una gramtica equivalente en FNC.

    En primer lugar las reglas pueden rescribirse:

    (1) S bA

    (2) S aB

    (3) A bAA

    (4) A aS

    (5) (*) A a

    (6) B aBB

    (7) B bS

    (8) (*) B b

    Solamente las sealadas con (*) estn en forma FNC. La produccin (1) puede sustituirse por dos:

    S Cb A

    Cb b

    Igualmente la (2) puede sustituirse por

    S Ca B

    Ca a

    Las producciones (3) y (4) se sustituyen por

    A Cb D1 D1 AA

    A Ca S

    y la (6) y la (7) por

    B Ca D2

    D2 BB

    B Cb S

    Entonces la gramtica equivalente en FNC es:

    S CbA

    S CaB

  • Anlisis Sintctico en Procesadores de Lenguaje

    19

    A CaS

    A CbD1

    A a

    B CbS

    B CaD2

    B b

    D1 AA

    D2 BB

    Ca a

    Cb b

    4.3.2 Forma Normal de Greibach (FNG) Se dice que una gramtica est en la Forma Normal de Greibach si sus reglas de

    produccin son de la forma:

    A a

    A a

    donde A es un no terminal, a es un terminal y es una cadena compuesta por terminales y no terminales.

    4.3.2.1 Teorema de la forma normal de Greibach

    Todo lenguaje de contexto libre sin la cadena vaca puede ser generado por una gramtica cuyas reglas de produccin estn en la FNG.

    4.3.2.2 Ejemplo

    La gramtica dada en el ejemplo 4.3.1.2.

    S bA|aB A bAA | aS | a B aBB | bS | b

  • Anlisis Sintctico en Procesadores de Lenguaje

    20

    4.4 TIPOS GENERALES DE ANALIZADORES SINTCTICOS Atendiendo a la forma en que procesan la cadena de entrada se clasifican en:

    3 Mtodos direccionales: procesan la cadena de entrada smbolo a smbolo de izquierda a derecha.

    3 Mtodos no-direccionales: acceden a cualquier lugar de la cadena de entrada para construir el rbol. Necesitan tener toda la cadena de componentes lxicos en memoria para que el anlisis pueda comenzar.

    Atendiendo al nmero de alternativas posibles en una derivacin se clasifican en:

    3 Mtodos deterministas: dado un smbolo de la cadena de entrada se puede decidir en cada paso cual es la alternativa/derivacin adecuada a aplicar, slo hay una posible. No se produce retroceso y el coste es lineal.

    3 Mtodos no-deterministas: en cada paso de la construccin del rbol se deben probar diferentes alternativas/derivaciones para ver cual es la adecuada, con el correspondiente aumento del coste.

    Existen tres tipos generales de analizadores sintcticos:

    Analizadores Universales

    Los algoritmos ms referenciados para reconocer las gramticas libres de contexto son el algoritmo CYK introducido en 1963 por Cocke, Younger y Kasami [You67], y el algoritmo de Early [Ear70]. El primero opera solamente con gramticas libres de contexto en forma normal de Chomsky mientras que el segundo trata las gramticas libres de contexto en general. Ambos algoritmos no se consideran demasiado eficientes para ser utilizados de forma generalizada ya que su coste es exponencial (dependen de la longitud de la cadena de entrada).

    Analizadores Descendentes (top-down)

    Construyen el rbol sintctico de la sentencia a reconocer desde el smbolo inicial (raz), hasta llegar a los smbolos terminales (hojas) que forman la sentencia, usando derivaciones ms a la izquierda.

    Los principales problemas que se plantean son dos: el retroceso (backtraking) y la recursividad a izquierdas. Para solventar este inconveniente, se opera con gramticas LL(k), que pueden realizar un anlisis sin retroceso en forma descendente.

    Analizadores Ascendentes (bottom-up)

    Construyen el rbol sintctico de la sentencia a reconocer desde las hojas hasta llegar a la raz. Son analizadores del tipo reduccin-desplazamiento (shift-reduce), parten de los distintos tokens de la sentencia a analizar y por medio de reducciones llegan al smbolo inicial de la gramtica.

    El principal problema que se plantea en el anlisis ascendente es el retroceso. Para solventar este inconveniente, se definieron distintos tipos de gramticas entre las cuales

  • Anlisis Sintctico en Procesadores de Lenguaje

    21

    las ms utilizadas son las LR(k) ya que realizan eficientemente el anlisis ascendente sin retroceso.

    Cabe destacar por tanto, la importancia de los mtodos direccionales y deterministas en el diseo de los procesadores de lenguaje. El anlisis determinista por la necesidad de eficiencia (coste lineal frente al exponencial que le hara prohibitivo en la implementacin prctica de los procesadores de lenguaje) y porque las herramientas para su construccin asumen esta condicin. Los mtodos direccionales por la propia naturaleza secuencial en que se van procesando los smbolos del fichero fuente de izquierda a derecha.

    4.5 SINTAXIS CONCRETA Y SINTAXIS ABSTRACTA

    Se ha visto anteriormente que la sintaxis de un lenguaje de programacin determina el conjunto de programas legales y la relacin entre los smbolos y frases (o sentencias) que en ellos aparecen.

    La sintaxis concreta, describe todas aquellas caractersticas del lenguaje que estn diseadas para hacerlo ms claro y legible. Entre estas caractersticas se encuentran las palabras clave, los delimitadores, los separadores, etc. Estos elementos son irrelevantes desde el punto de vista estructural e incluso se puede decir que una vez cumplida su funcin, pueden llegar a estorbar en el proceso de anlisis semntico ya que hacen perder la visin global de la estructura del lenguaje.

    Ejemplo: La siguiente produccin describe la forma que debe tener una sentencia condicional en algn lenguaje de programacin.

    Condicion: SI expresin_logica ENTONCES

    COMIENZO sentencia FIN

    SINO sentencia FIN

    Sin embargo, desde un punto de vista semntico lo nico importante que se necesita saber es que una sentencia condicional est compuesta de dos grupos de sentencias y de una expresin lgica que discrimina cual de las dos debe ejecutarse.

    Algunos de estos elementos cumplen adems una segunda funcin en la fase de anlisis sintctico, haciendo que no tengamos que construir reconocedores excesivamente potentes, o proporcionando puntos de seguridad que ayuden a la recuperacin de errores sintcticos (el ms tpico es el carcter ;).

    La sintaxis abstracta, permite definir los aspectos estructurales de un lenguaje. De esta forma, al reflejar solo los aspectos esenciales, es posible representar ms claramente su estructura, y por lo tanto se simplifica el posterior tratamiento semntico ya que un rbol de anlisis sintctico contiene ms informacin de la que es absolutamente necesaria para que un procesador de lenguaje genere cdigo ejecutable.

    Los rboles sintcticos abstractos representan abstracciones de las secuencias de tokens del cdigo fuente real.

    A continuacin se muestran algunos ejemplos.

  • Anlisis Sintctico en Procesadores de Lenguaje

    22

    Ejemplo 1: Sentencia de asignacin

    V := E

    V E

    Set V = E

    Todas son diferentes en trminos de sintaxis concreta pero son las mismas en trminos de estructura.

    Ejemplo 2: Sentencia condicinal

    while (x!=y) { ....

    }

    while (xy) do begin

    ....

    end

    Como se puede observar, los dos bloques poseen diferente sintaxis concreta e igual sintaxis abstracta:

    while condicion

    bloque

  • Anlisis Sintctico en Procesadores de Lenguaje

    23

    TEMA 5 ANLISIS SINTCTICO DESCENDENTE

    5.1 INTRODUCCIN Uno de los mtodos de reconocimiento para las gramticas de contexto libre son los

    analizadores sintcticos descendentes o tambin llamados predictivos y orientados hacia un fin, debido a la forma en que trabajan y construyen el rbol sintctico. Los analizadores sintcticos descendentes son lo que construyen el rbol sintctico de la sentencia a reconocer de una forma descendente, comenzando por el smbolo inicial o raz, hasta llegar a los smbolos terminales que forman la sentencia. El anlisis descendente es un procedimiento que crea objetivos y subobjetivos al intentar relacionar una sentencia con su entorno sintctico. Al comprobar los subobjetivos, se verifican y descartan las salidas falsas y las ramas impropias hasta que se alcanza el subobjetivo propio que son los smbolos terminales que forman la sentencia.

    El procedimiento de anlisis, en cada encuentro con la estructura sintctica, tiene que examinar los subobjetivos. Si se cumplen los subobjetivos requeridos, entonces, por definicin, se logra el objetivo de mayor rango. En caso contrario, se descarta dicho objetivo superior. Esta secuencia de comprobar, descartar y por ltimo efectuar los objetivos, se programa hacia abajo siguiendo el rbol sintctico hasta que todas las componentes bsicas se hayan acumulado en componentes de nivel superior o hasta que se compruebe que la sentencia es errnea.

    Los algoritmos que realizan el anlisis descendente deben de cumplir al menos dos condiciones: a) el algoritmo debe saber en todo momento dnde se encuentra dentro del rbol sintctico; y b) debe poder elegir los subobjetivos (es decir la regla de produccin que aplicar).

    Histricamente, los compiladores dirigidos por sintaxis, en la forma de anlisis recursivo descendente fue propuesta por primera vez en forma explcita por Lucas (1961), para describir un compilador simplificado de ALGOL 60 mediante un conjunto de subrutinas recursivas, que correspondan a la sintaxis BNF. El problema fundamental para el desarrollo de este mtodo fue el retroceso, lo que hizo que su uso prctico fuera restringido. La elegancia y comodidad de la escritura de compiladores dirigidos por sintaxis fue pagada en tiempo de compilacin por el usuario.

    La situacin cambi cuando comenz a realizarse anlisis sintctico descendente sin retroceso, por medio del uso de gramticas LL(1), obtenidas independientemente por Foster (1965) y Knuth (1967). Generalizadas posteriormente por Lewis, Rosenkrantz y Stearns en 1969, dando lugar a las gramticas LL(k), que pueden analizar sintcticamente sin retroceso, en forma descendente, examinando en cada paso todos los smbolos procesados anteriormente y los k smbolos de entrada ms a la derecha.

  • Anlisis Sintctico en Procesadores de Lenguaje

    24

    5.2 El problema del retroceso

    El primer problema que se presenta con el anlisis sintctico descendente, es que a partir del nodo raz, el analizador sintctico no elija las producciones adecuadas para alcanzar la sentencia a reconocer. Cuando el analizador se da cuenta de que se ha equivocado de produccin, se tienen que deshacer las producciones aplicadas hasta encontrar otras producciones alternativas, volviendo a tener que reconstruir parte del rbol sintctico. A este fenmeno se le denomina retroceso, vuelta atrs o en ingls backtracking.

    El proceso de retroceso puede afectar a otros mdulos del compilador tales como tabla de smbolos, cdigo generado, etc. teniendo que deshacerse tambin los procesos desarrollados en estos mdulos.

    5.2.1 Ejemplo de retroceso Para explicar mejor el problema del retroceso, se estudiar el siguiente ejemplo, donde

    se utiliza la gramtica G = (VN, VT, S, P) donde:

    VN={, , } VT={module, d, p, ;, end} S=

    las reglas de produccin P son las siguientes:

    ::= module ; end

    ::= d | d; ::= p | p;

    Se desea analizar la cadena de entrada siguiente: module d ; d ; p ; p end

    A continuacin se construye el rbol sintctico de forma descendente:

    1. Se parte del smbolo inicial

    2. Aplicando la primera regla de produccin de la gramtica se obtiene:

    module ; end

    3. Aplicando las derivaciones ms a la izquierda, se tiene que:

    3.1 module es un smbolo terminal, que coincide con el primero de la cadena a reconocer.

    3.2 se deriva con la primera alternativa.

  • Anlisis Sintctico en Procesadores de Lenguaje

    25

    module ; end

    d

    Se comprueba que el nuevo terminal generado d coincide con el segundo token de la cadena de entrada.

    3.3 ; coincide con el tercer token de la cadena de entrada.

    3.4 Se deriva con la primera alternativa.

    module ; end

    d p

    y se llega a un terminal que no es el que tiene la cadena.

    Se deriva con la segunda alternativa.

    odule ; end

    d ;p

    Se observa que el siguiente terminal generado, tampoco coincide con el token de la cadena de entrada. Entonces el analizador sintctico debe de volver atrs, hasta encontrar la ltima derivacin de un no terminal, y comprobar si tiene alguna alternativa ms. En caso afirmativo se debe de elegir la siguiente y probar. En caso negativo, volver ms atrs para probar con el no terminal anterior. Este fenmeno de vuelta atrs es el que se ha definido anteriormente como retroceso.

    Si en este proceso de marcha atrs se llega al smbolo inicial o raz, se tratara de una cadena errnea sintcticamente.

    Dado que no se ha encontrado el terminal de la cadena de entrada, se ha de volver atrs hasta el no-terminal analizado anteriormente, que en este caso es , es decir, se pasa a 3.2 y en vez de tomar la primera alternativa se toma la segunda alternativa.

  • Anlisis Sintctico en Procesadores de Lenguaje

    26

    module ; end

    ;d

    Llegados a este punto, tambin se debe de retroceder en la cadena de entrada hasta la primera d, ya que en el proceso de vuelta atrs lo nico vlido que nos ha quedado del rbol ha sido el primer token module. Si se deriva nuevamente con la primera alternativa, se tiene

    module ; end

    ;d

    d

    En este momento se tienen reconocidos los primeros 5 tokens de la cadena.

    Se deriva el no terminal , con la primera alternativa, y el rbol resultante se muestra a continuacin. Se ha reconocido el sexto token de la cadena.

    module ; end

    ;d

    d

    p

    El siguiente token de la cadena es ; mientras que en el rbol se tiene end, por lo tanto habr que volver atrs hasta el anterior no terminal, y mirar si tiene alguna otra alternativa.

    El ltimo no terminal derivado es , si se deriva con su otra alternativa se tiene el rbol mostrado a continuacin. Con esta derivacin se ha reconocido la parte de la cadena de entrada module d ; d ; p ;

    module ; end

    ;d

    d

    p ;

    Se deriva con la primera alternativa y se obtiene el siguiente rbol sintctico, reconocindose module d ; d ; p ; p

  • Anlisis Sintctico en Procesadores de Lenguaje

    27

    module ; end

    ;d

    d

    p ;

    p

    El rbol sintctico ya acepta el siguiente token de la cadena end y por tanto la cadena completa.

    Puede concluirse, que los tiempos de reconocimiento de sentencias de un lenguaje pueden dispararse a causa del retroceso, por lo tanto los analizadores sintcticos deben eliminar las causas que producen el retroceso.

    5.3 Anlisis sintctico descendente con retroceso

    La forma en que se hace el anlisis descendente con retroceso ya se ha visto en el ejemplo del apartado 5.2.1, aqu se expone el algoritmo general para construir un analizador sintctico descendente con retroceso.

    5.3.1 Algoritmo de anlisis sintctico descendente con retroceso 1. Se colocan las reglas de la gramtica segn un orden preestablecido para cada uno de

    los no terminales de la que est compuesta.

    2. Se comienza la construccin del rbol sintctico a partir del smbolo inicial, y aplicando las siguientes reglas en forma recursiva. Al nodo en proceso de expansin en un determinado momento se le llamar nodo activo.

    3. Cada nodo activo escoge la primera de sus alternativas posibles, por ejemplo, para el no terminal A con la regla A x1x2...xn crea n descendientes directos, y el nodo activo en ese momento pasa a ser el primer descendiente por la izquierda. Cuando se deriven todos los descendientes, pasar a ser nodo activo el ms inmediato derecho de A susceptible de ser derivado. En el caso de que la regla fuese: A x1 | x2 |...| xn se elegir en un principio la alternativa de ms a la izquierda.

    4. Si el nodo activo es un terminal deber entonces compararse el smbolo actual de la cadena a analizar con dicho nodo. Si son iguales se avanza un token de entrada y el nuevo smbolo actual ser el situado ms a la derecha del terminal analizado. Si no son iguales se retrocede hasta un nodo no terminal y se reintenta eligiendo la siguiente alternativa. Si an as no existe ninguna alternativa posible se retrocede al no terminal anterior, y as sucesivamente. Si se llega al smbolo inicial la cadena no pertenece al lenguaje.

    5.3.2 Corolario Una gramtica de contexto libre, que es una gramtica limpia y no es recursiva a

    izquierdas, para cualquier cadena de smbolos de su alfabeto terminal existe un nmero finito de posibles anlisis a izquierda desde el smbolo inicial para reconocerla o no.

  • Anlisis Sintctico en Procesadores de Lenguaje

    28

    A partir de todo lo expresado anteriormente, se pueden construir analizadores sintcticos descendentes con retroceso. Su principal problema es el tiempo de ejecucin.

    5.4 Anlisis descendente sin retroceso

    Para eliminar el retroceso en el anlisis descendente, se ha de elegir correctamente la produccin correspondiente a cada no terminal que se expande. Es decir que el anlisis descendente ha de ser determinista, y slo se debe de dejar tomar una opcin en la expansin de cada no terminal.

    5.4.1 Gramticas LL(k) Las gramticas LL(k) son un subconjunto de las gramticas libres de contexto.

    Permiten un anlisis descendente determinista (o sin retroceso), por medio del reconocimiento de la cadena de entrada de izquierda a derecha ("Left to right") y que va tomando las derivaciones ms hacia la izquierda ("Leftmost") con slo mirar los k tokens situados a continuacin de donde se halla. Si k=1 se habla de gramticas LL(1).

    Las gramticas LL(1) permiten construir un analizador determinista descendente con tan slo examinar en cada momento el smbolo actual de la cadena de entrada (smbolo de preanlisis) para saber que produccinn aplicar.

    Antes de definir completamente las gramticas LL(1), se definirn otros tipos de gramticas ms sencillas que son LL(1). La introduccin de estas gramticas permitir una aproximacin paso a paso hacia la definicin completa de las gramticas LL(1).

    5.4.1.1 Teorema

    Una gramtica LL(k) es no ambigua.

    Una gramtica LL(k) no es recursiva a izquierdas.

    Demostracin: Por definicin de gramtica LL(k).

    5.4.1.2 S-gramticas

    Las S-gramticas son un subconjunto muy restringido de las gramticas LL(1), debido a dos condiciones muy fuertes.

    Una S-gramtica es una gramtica libre de contexto que debe cumplir las siguientes dos condiciones:

    1) Todas las partes derechas de cada produccin comienzan con un smbolo terminal.

    2) Si dos producciones tienen la misma parte izquierda, entonces su parte derecha comienza con diferentes smbolos terminales. Es decir las distintas producciones de cada no terminal, deben comenzar por distinto smbolo terminal. As si se tienen la producciones del no terminal A: A a11 | a2 2 | ...| amm se debe cumplir que:

  • Anlisis Sintctico en Procesadores de Lenguaje

    29

    ai aj i j ai VT i V* 1 i m

    La primera condicin es similar a decir que la gramtica est en la Forma Normal de Greibach (FNG).

    La segunda condicin ayudar a escribir los analizadores sintcticos descendentes sin retroceso (o deterministas), ya quepermitirn siempre elegir la derivacin correcta, con slo mirar un token hacia adelante.

    5.4.1.3 Corolario de la definicin de S-gramticas

    Toda S-gramtica es LL(1), la inversa no es cierta. Toda S-gramtica es una gramtica LL(1) dado que una vez que analiza un token es posible determinar que regla de produccin se debe aplicar.

    Contraejemplo de S-gramtica

    Sea la gramtica:

    (1) S a T

    (2) S T b S

    (3) T b T

    (4) T b a

    No es una s-gramtica, ya que la parte derecha de la produccin (2) no comienza por un terminal como exige la primera condicin. Adems las producciones (3) y (4) no cumplen la segunda condicin..

    Ejemplo de S-gramtica

    Sea la gramtica:

    S a b R

    S b R b S

    R a

    R b R

    Obviamente es una s-gramtica, y por tanto es una gramtica LL(1).

    Ejemplo de S-gramtica

    Sea la gramtica: S p X

    S q Y

    X a X b

    X x

    Y a Y d

    Y y

    Obviamente es una s-gramtica, y por tanto es una gramtica LL(1).

  • Anlisis Sintctico en Procesadores de Lenguaje

    30

    5.4.1.4 Conjunto de smbolos INICIALES o cabecera

    Se define el conjunto de smbolos iniciales o cabecera (en ingls FIRST) de un smbolo (VT VN)*, como el conjunto de smbolos terminales que pueden aparecer al principio de cadenas derivadas de . La definicin anterior se puede expresar como:

    INICIALES() = {a / a ... siendo a VT } Si a 1 ...n entonces {a} INICIALES() con a VT Si entonces {} INICIALES()

    Algoritmo para calcular el conjunto de INICIALES

    Clculo del conjunto de INICIALES para todos los smbolos gramaticales.

    Repetir hasta que no se puedan aadir ms smbolos terminales o al conjunto.

    1. Si X es un terminal o , entonces INICIALES (X) = {X}

    2. Si X es un no terminal, entonces para cada produccin de la forma XX1X2...Xn, INICIALES (X) contiene a INICIALES (X1) {}. Si tambin para algn i < n todos los conjuntos INICIALES (X1) ... INICIALES (Xi) contienen a , entonces INICIALES (X) contiene a INICIALES (Xi+1) {}. Si todos los conjuntos INICIALES (X1) ... INICIALES (Xn) contiene , entonces INICIALES (X) tambin contiene a .

    3. Se define INICIALES (), para cualquier cadena = X1X2...Xn, de terminales y no terminales, de la manera siguiente. INICIALES () contiene a INICIALES (X1) {}. Para cada i = 2, ...,n si INICIALES (Xk) contiene a para toda k = 1, ...i-1, entonces INICIALES() contiene a INICIALES (Xi) - {}. Finalmente, si para todo i = 1...n, INICIALES (Xi) contiene , entonces INICIALES () contiene a .

    El seudocdigo del algoritmo para todo no terminal A es el siguiente:

    for todo no terminal A do INICIALES(A) := {} while existan cambios en cualquier INICIALES(A) do for cada seleccin de produccin AX1X2...Xn do k :=1; continuar = verdadero; while contiuar = verdadero and k

  • Anlisis Sintctico en Procesadores de Lenguaje

    31

    S A B e

    A d B

    A a S

    A c

    B A S

    B b

    INICIALES(A)={d, a, c}

    INICIALES(S)=INICIALES(A)={d, a, c}

    INICIALES(B)=INICIALES(A) {b} ={d, a, c, b}

    5.4.1.5 Gramticas LL(1) simples

    Las gramticas LL(1) simples son un subconjunto de las gramticas LL(1), con las dos restricciones siguientes:

    3 No se permiten smbolos no terminales que deriven a vaco. Es decir no se permiten producciones vacas o reglas-, cuya parte derecha es la cadena vaca .

    3 Las distintas producciones de cada no terminal A VN A 1 | 2 | ...| n deben cumplir los conjuntos INICIALES(1), INICIALES(2),..., INICIALES(n) son disjuntos entre s, es decir INICIALES(i) INICIALES(j) = i j

    5.4.1.6 Corolario de las gramticas LL(1) simples

    Toda gramtica LL(1) simple es LL(1), la inversa no es cierta.

    5.4.1.7 Teorema de equivalencia entre gramticas LL(1) y S-gramticas

    Dada una gramtica LL(1) simple siempre es posible encontrar una S-gramtica equivalente.

    Ejemplo de gramtica LL(1) simple

    Sea la gramtica cuyas reglas de produccin son:

    S A B e

    A d B

    A a S

    A c

    B A S

    B b

    Se desea verificar si es o no LL(1) simple.

    4. Dadas las producciones A d B | a S | c

  • Anlisis Sintctico en Procesadores de Lenguaje

    32

    INICIALES (dB) INICIALES(aS) INICIALES(c) = {d} {a} {c}= 0

    5. Dadas las producciones B A S | b

    INICIALES (AS) INICIALES(b) = {a,c,d} {b} = 0

    Luego esta gramtica es LL(1) simple.

    Ejemplo de gramtica LL(1) simple

    Sea la siguiente gramtica que incluye una produccin para reconocer el carcter final de la cadena de entrada.

    (0) S S #

    (1) S a S

    (2) S b A

    (3) A d

    (4) A c c A

    Claramente es una gramtica LL(1) simple, que permite reconocer una cadena sin retroceso. As con esta gramtica se desea reconocer la cadena: aabccd#. Realizando derivaciones ms a la izquierda se obtiene:

    # aa # aab # aabcc # aabccd#

    siendo el rbol sintctico el que se muestra en la figura 11.

  • Anlisis Sintctico en Procesadores de Lenguaje

    33

    Los smbolos seguidores o siguientes (en ingls FOLLOW) de un smbolo no terminal tambin se pueden definir como los smbolos iniciales del smbolo que sigue al no terminal A.

    Algoritmo para calcular el conjunto de SEGUIDORES

    Clculo del conjunto de SEGUIDORES para los smbolos A VNT.

    Repetir hasta que no cambie el conjunto de seguidores

    1. Si A es el smbolo inicial, entonces $ est en SEGUIDORES (A).

    2. Si hay una produccin B A, entonces

    INICIALES () {} SEGUIDORES (A)

    3. Si existe una produccin B A B A tal que INICIALES () entonces SEGUIDORES (B) SEGUIDORES (A).

    El seudocdigo del algoritmo para el clculo de conjuntos de Seguidores.

    SEGUIDORES (smbolo-inicial) := {$}; for todos los no terminales A smbolo-inicial do SEGUIDORES(A):={}; while existan cambios en cualquier conjunto SEGUIDORES do for cada produccin AX1X2...Xn do for cada Xi que sea un no terminal do aadir INICIALES (Xi+1Xi+2...Xn) - {} a SEGUIDORES (Xi) (* NOTA: si i=n, entonces Xi+1Xi+2...Xn = *) if est en INICIALES(Xi+1Xi+2...Xn) then aadir SIGUIENTE (A) a SIGUIENTE (Xi)

    Ejemplo de clculo del conjunto de Seguidores

    Sea la gramtica:

    ::= module end

    ::= d

    ::= | ; ::= p

    ::= | ;

    Clculo del conjunto de seguidores del smbolo no terminal A.

    module d end

    INICIALES () = { p }

    Clculo de los smbolos seguidores de

  • Anlisis Sintctico en Procesadores de Lenguaje

    34

    module p end

    SEGUIDORES()= { end }

    5.4.1.9 Conjunto de smbolos DIRECTORES

    Los smbolos directores (en ingls SELECT) de una produccin como su nombre indica son los que dirigen al analizador sintctico para elegir la alternativa adecuada, se pueden definir como el conjunto de smbolos terminales que determinarn que expansin de un no terminal se ha de elegir en un momento dado, con solo mirar un smbolo hacia adelante. La definicin formal se puede enunciar de la siguiente forma, dada una produccin A donde A es un smbolo no terminal, y es una cadena de smbolos terminales y no terminales. Entonces se define conjunto de smbolos directores SD(A, ) de una produccin A como:

    INICIALES () si es no anulable INICIALES () SEGUIDORES (A) si es anulable

    Ejemplo de clculo del conjunto de smbolos Directores

    Sea la gramtica:

    ::= module end

    ::= d

    ::= | ; ::= p

    ::= | ; ::=

    a) Calcular el conjunto de smbolos directores de la produccin A vaco

    En este caso es es anulable, luego:

    SD (,) = INICIALES() SEGUIDORES () = {p} = { p }

    b) Calcular el conjunto de smbolos directores de la produccin: A ; DECLARACIONES

    SD(, ; ) = { ; }

    5.4.1.10 Definicin de las gramticas LL(1)

    La condicin necesaria y suficiente para que una gramtica limpia sea LL(1), es que los smbolos directores correspondientes a las diferentes expansiones de cada smbolo no terminal sean conjuntos disjuntos.

    La justificacin de esta condicin es simple. La condicin es necesaria, puesto que si un smbolo aparece en dos conjuntos de smbolos directores, el analizador sintctico descendente no puede decidir (sin recurrir a informacin posterior) que expansin aplicar. La condicin es suficiente, puesto que el analizador siempre puede escoger una expansin como un smbolo dado, y esta alternativa ser siempre correcta. Si el smbolo

    SD (A, )

  • Anlisis Sintctico en Procesadores de Lenguaje

    35

    no est contenido en ninguno de los conjuntos de los smbolos directores, la cadena de entrada no pertenecer al lenguaje y se tratar de un error.

    Existe un algoritmo diseado por Lewis et al. [LEWI76, pg. 262-276], traducido y adaptado por Snchez Dueas et al. [SANC84, pg 86-95], que permite decidir si una gramtica es o no LL(1). Es decir, si con el diseo de una gramtica para un lenguaje de programacin, se puede construir un analizador sintctico descendente determinista, con solo examinar el siguiente token de entrada. Los distintos pasos del algoritmo se encaminan a construir los conjuntos de smbolos directores para cada expansin de un smbolo no terminal, y aplicar la condicin necesaria y suficiente para que la gramtica sea LL(1). Ver anexo I.

    5.4.2 Condiciones de las gramticas LL(1) La definicin original dada por D.E. Knuth, de gramticas LL(1) consta de cuatro

    condiciones equivalentes a la definicin dada en la seccin anterior.

    5.4.2.1 Primera condicin de Knuth

    No se permitirn producciones de la forma A A donde A a VN y V*. Esta condicin equivale a no admitir la recursividad a izquierdas.

    5.4.2.2 Segunda condicin de Knuth

    Los smbolos terminales que pueden encabezar las distintas alternativas de una regla de produccin deben formar conjuntos disjuntos. Es decir, si

    A B | C A,B,C VN , V*

    No debe ocurrir que

    B dS d VT

    C d S, V* Esto implica que en todo momento, el smbolo terminal que estamos examinando

    seala sin ambigedad, que alternativa se ha de escoger sin posibilidad de error y, en consecuencia, sin retroceso.

    5.4.2.3 Tercera condicin de Knuth

    Si una alternativa de una produccin de un smbolo no terminal origina la cadena vaca, los smbolos terminales que pueden seguir a dicho no-terminal en la produccin donde aparezca, han de formar un conjunto disjunto con los terminales que pueden encabezar las distintas alternativas de dicho terminal (INICIALES (A) SEGUIDORES(A) = ). Expresado de otra forma, sea la cadena A1... A2... A3A4A5 y sea A3 el smbolo que se est analizando, adems se tienen las producciones:

    A3 ax |

    A4 A3ay

    *

    *

    *

  • Anlisis Sintctico en Procesadores de Lenguaje

    36

    Dado que A3 puede derivar a la cadena vaca, puede darse el caso de que:

    INICIALES(A3)= { a }

    INICIALES(A4)= { a }

    y no puede determinarse si se ha de elegir la produccin de A3 o de A4.

    Esta condicin garantiza que para aquellos smbolos que pueden derivar la cadena vaca, el primer smbolo que generan y el siguiente que puede aparecer detrs de ellos sean distintos, sino no se podra saber si se va a empezar a reconocer el no terminal o por el contrario ya se ha reconocido.

    5.4.2.4 Cuarta condicin de Knuth

    Ningn smbolo no terminal puede tener dos o ms alternativas que conduzcan a la cadena vaca. Esta condicin deriva de la anterior. As por ejemplo no se permite:

    X A | B

    A | C B | D

    5.4.3 Transformacin de gramticas En el apartado anterior se ha visto la forma de determinar si una gramtica es LL(1) o

    no. Sin embargo, la cuestin de si un lenguaje posee una gramtica LL(1) es indecidible. Es decir, no se puede saber si un determinado lenguaje puede ser generado o no por una gramtica LL(1), hasta que no se encuentre esta gramtica. No existe ningn algoritmo general que transforme una gramtica a LL(1). Pero en algunos casos se puede obtener una gramtica equivalente por medio de las transformaciones que se estudiarn en los siguientes epgrafes. Ha de tenerse en cuenta que las gramticas LL(1) son un subconjunto muy particular de las gramticas libres de contexto, tal como se muestra en el diagrama de la figura 12.

    LL(1)

    NO AMBIGUAS

    GRAMTICAS LIBRES DE CONTEXTO

    Figura 12: Las gramticas LL(1) como subconjunto de las gramticas libres de contexto

    5.4.3.1 La recursividad a izquierdas

    Se dice que una gramtica tiene recursividad a izquierdas ("left-recursive"), si existe un no terminal A, tal que para algn V* existe una derivacin de la forma:

  • Anlisis Sintctico en Procesadores de Lenguaje

    37

    +

    donde el signo + encima de la flecha indica que al menos existe una produccin.

    Si el analizador sintctico toma el primer no terminal (el ms a la izquierda), el rbol sintctico es el de la figura 13. La recursividad a izquierdas deja al analizador sintctico en un bucle infinito, ya que al expandir A, se encontrara con otro A, y as sucesivamente, sin avanzar en la comparacin del token de entrada.

    A

    A

    A

    A

    A

    Figura 13: Recursividad a izquierda

    Ejemplo de recursividad a izquierdas

    Sea la gramtica G = (VN, VT, S, P) donde VN = {A, S}, VT = {a, b, c}, y las reglas de produccin P son las siguientes:

    S aAc

    A Ab |

    El lenguaje reconocido por esta gramtica es L = {a bn c / n>=0}. Supongamos que el analizador sintctico desea reconocer la cadena: abbc, se obtienen los rboles sintcticos de la figura 14. No saliendo el analizador sintctico de este bucle.

    S

    (1)

    S

    a A c

    (2)

    S

    a A c

    A b

    (3)

    S

    a A c

    A b

    A b

    (4)

    S

    a A c

    A b

    A b

    A b

    (5)

    Figura 14: Bucle infinito tratando de reconocer abbc.

    Una forma de resolver este problema es volviendo a escribir la segunda produccin de la gramtica de esta otra manera:

    A | Ab entonces se construyen los rboles sintcticos que se muestran en la figura 15.

  • Anlisis Sintctico en Procesadores de Lenguaje

    38

    S

    (1)

    S

    a A c

    (2)

    S

    a A c

    (3)

    S

    a A c

    A b

    (4)

    S

    a A c

    A b

    A b

    (5)

    Figura 15: Reconocimiento de la cadena abbc.

    Otra forma de resolver el problema es cambiando en la regla conflictiva el orden Ab por bA, que a su vez cambia la gramtica, pero se obtiene una gramtica equivalente, es decir que genera el mismo lenguaje.

    A | bA Para reconocer abbc se obtienen los rboles sintcticos de la figura 16.

    S

    (1)

    S

    a A c

    (2)

    S

    a A c

    b A

    (3)

    S

    a A c

    b A

    b A

    (4)

    S

    a A c

    b A

    (5)

    b A

    Figura 16: Reconocimiento de la cadena abbc.

    No siempre es tan fcil eliminar la recursividad a izquierdas, por tanto, se deben estudiar otros mtodos para eliminar la recursividad a izquierdas.

    5.4.3.2 Eliminacin de la recursividad a izquierdas

    Una gramtica con producciones recursivas a izquierda no cumple las condiciones necesarias para que sea LL(1). Greibach, en 1964, demostr tericamente que es posible eliminar la recursividad a izquierdas de cualquier gramtica. A continuacin se muestra el caso ms simple, sea una gramtica con el par de producciones, presentando la primera una recursividad a izquierdas inmediata:

    A A donde no comienza por A, se puede eliminar la recursividad a izquierdas con slo

    reemplazar este par por:

    A C C C

    Se puede observar que si se desea reconocer la cadena por medio de producciones ms a la izquierda se obtienen los rboles sintcticos de la figura 17.

  • Anlisis Sintctico en Procesadores de Lenguaje

    39

    A

    C

    C

    C

    A

    A

    A

    A

    Bucle infinito

    Figura 17: rboles sintcticos con y sin recursividad a izquierdas

    En general, para eliminar la recursividad a izquierdas de todas las producciones de A, lo que se hace es agrupar dichas producciones de la siguiente forma:

    A A 1 | A 2 | ... | A n | 1 | 2 | 3 | ... | n donde ningn i comienza por A. Seguidamente, se reemplazan las producciones de A

    por:

    A 1 C | 2 C | ... | n C C 1 C | 2 C | ... | n C |

    Este proceso elimina todas las recursividades a izquierda inmediatas (siempre que ningn i sea la cadena vaca), pero no se eliminan las recursividades a izquierda indirectas. Se dice que existe recursividad indirecta cuando no se observan recursividades directas inmediatas, pero se llegan a recursividades a izquierda inmediatas por medio de dos o ms derivaciones de las reglas. El mtodo para resolver las recursividades indirectas es convertirlas a recursividades inmediatas por medio de sustituciones.

    Ejemplo 1: Recursividad a izquierdas indirecta

    Sea la gramtica, en la que presenta una recursividad a izquierda indirecta:

    (1) ::= (2) ::= identificador | + identificador

    Para eliminarla se realiza la sustitucin de la produccin (2) en (1), quedando la nueva gramtica equivalente con una recursividad a izquierdas inmediata:

    ::= identificador | + identificador

    Ahora se puede aplicar el mtodo estudiado anteriormente para eliminar la recursividad a izquierda inmediata, obtenindose la siguiente gramtica no recursiva a izquierdas:

    (1) ::= identificador

    (2) ::= + identificador | Ejemplo 2: Recursividad a izquierdas indirecta

    Sea la siguiente gramtica que presenta una recursividad a izquierdas indirecta:

  • Anlisis Sintctico en Procesadores de Lenguaje

    40

    ::= . ::= ; ::= return | end ::= exit

    Esta gramtica es recursiva a izquierdas indirectamente tal como se muestra en el rbol sintctico de la figura 18.

    .

    ;

    return

    exit

    (se vuelve a repetir desde )

    Figura 18: Recursividad a izquierdas indirecta

    La produccin que hace que sea recursiva a izquierdas es la siguiente:

    ::= exit

    Se puede sustituir por su parte derecha en la 2 produccin quedando:

    ::= ; exit

    Pero an as sigue siendo recursiva a izquierdas, entonces se sustituye por sus dos partes derechas, con lo que quedan las producciones:

    ::= return ; exit

    ::= end ; exit

    Con lo que se ha llegado a una recursividad a izquierdas inmediata. Aplicando el mtodo visto anteriormente para eliminar la recursividad a izquierdas inmediata, las producciones quedan:

    ::= end ; exit

    ::= return ; exit | La gramtica equivalente a la dada sin recursividad a izquierdas es la siguiente:

    ::= . ::= ; ::= return | end ::= end ; exit

    ::= return ; exit |

  • Anlisis Sintctico en Procesadores de Lenguaje

    41

    5.4.3.3 Factorizacin y sustitucin

    Una gramtica puede no ser LL(1) y no ser recursiva a izquierdas. El motivo puede ser que los conjuntos de smbolos directores no sean conjuntos disjuntos, por empezar varias reglas de produccin por el mismo smbolo no anulable. No existe ningn algoritmo genrico que pueda convertir las gramticas, tan solo hay recomendaciones. El mtodo de factorizacin y sustitucin lleva implcito el concepto matemtico de sacar factor comn. Es decir, se trata de agrupar las producciones que comienzan por el mismo smbolo no anulable, realizar sustituciones de reglas o incluir nuevos smbolos no terminales. Dada una produccin de la forma:

    A 1 | 2 | ... n | evidentemente no es LL(1) si no es anulable.

    El orden en que se realizan las sustituciones es importante tenerlo en cuenta. En general, se debe de sustituir primero el no terminal que necesita el mayor nmero de expansiones, antes de sacar el factor comn. Bauer (1974) da en su libro [BAUE74, Pg. 75] un algoritmo para elegir el orden de sustitucin.

    Algoritmo para la factorizacin:

    3 primer paso: para cada no terminal A buscar el prefijo ms largo comn a dos o ms alternativas de dicho no terminal.

    3 segundo paso: Si , sustituir todas las producciones de A por: A C | C 1 | 2 |...|n

    Ejemplo 1: El problema if-then-else

    La instruccin if-then-else expresada de la forma:

    ::= if then else

    |if then

    Presenta el problema descrito en el apartado 4.2.5.2 impidiendo que la gramtica sea LL(1). Sin embargo, si se aplica factorizacin y sustitucin quedara de la forma:

    ::= if then

    ::= else |

    Pero esta sustitucin no elimina la ambigedad, dado que se puede generar ms de un rbol sintctico. Para eliminar la ambigedad de la sentencia es necesario expresarla de la forma vista en el apartado 4.2.5.2.

    Ejemplo 2: Gramtica de expresiones aritmticas

    Sea la gramtica no ambigua GNA = (VN, VT, S, P), obtenida en el apartado 2.5.3.6, que describe expresiones aritmticas teniendo en cuenta precedencia y asociatividad. Sin embargo no es LL(1). En primer lugar se observa varias recursividades a izquierdas inmediatas.

  • Anlisis Sintctico en Procesadores de Lenguaje

    42

    VN = {, , , , } VT = {identificador, constante, (, ), ^, *, /, +, -} S =

    y las producciones P:

    ::= + | - |

    ::= * | / |

    ::= ^ | ::= - | ::= ( ) | identificador | constante

    Para resaltar la recursividad a izquierdas y manejar reglas ms compactas se aplicar factorizacin y sustitucin, utilizando los no terminales , y :

    ::= + | - ::= * | / ::= ^ |

    Entonces las reglas de produccin anteriores quedan de la forma:

    ::= | ::= | ::=

    ::= - | ::= ( ) | identificador | constante

    Ahora pueden verse claramente dos recursividades a izquierda inmediatas que aplicando los mtodos dados se convierten en:

    ::=

    ::= | ::=

    ::= |

    El resto de las producciones quedan como estn, y si se vuelve a deshacer la sustitucin de , y se obtiene la siguiente gramtica de expresiones aritmticas con precedencia y asociatividad, que es LL(1).

    ::=

    ::= +

    ::= -

    ::=

    ::=

    ::= *

  • Anlisis Sintctico en Procesadores de Lenguaje

    43

    ::= / ::=

    ::=

    ::= ^

    ::=

    ::= -

    ::=

    ::= ( ) ::= identificador

    ::= constante

    ::=

    Esta gramtica se puede utilizar para construir la gramtica de un lenguaje denominado MUSIM/11, que se adjunta a continuacin:

    ::= MAIN { } ::= ::= ;

    ::=

    ::=

    ::=

    ::=

    ::= =

    ::=

    ::= +

    ::= -

    ::=

    ::=

    ::= *

    ::= / ::= %

    ::=

    ::=

    ::= ^

    ::=

    ::= -

    ::=

    ::= ( ) ::=

    ::=

    ::= READ

    ::= WRITE

  • Anlisis Sintctico en Procesadores de Lenguaje

    44

    ::= entera

    ::= letra_minuscula

    ::=

    5.4.3.4 Transformacin de gramticas mediante aspectos semnticos

    En algunas construcciones de los lenguajes de programacin es necesario conocer ms informacin que la estrictamente sintctica, para ayudar a elegir el smbolo director en cada momento, en esos casos se puede tomar informacin semntica, que habitualmente proporcionar la tabla de smbolos o los atributos semnticos de los smbolos de la gramtica. En el caso de los procesadores de lenguaje de una sola pasada, esto es fcil de implementar dado que en cada instante se tiene toda la informacin del smbolo que se est procesando.

    5.4.3.4.1 Ejemplo

    Sea un lenguaje de programacin tipo ALGOL con un fragmento de gramtica de la forma:

    ::= begin end ::= ::= identificador :

    | ::= while DO

    | := | repeat until | for := do | goto constante | case of end ...

    ::= identificador

    ...

    Puede observarse que, en este lenguaje, las sentencias pueden llevar etiquetas, que son identificadores. Supongamos que se tienen las sentencias (1) y (2).

    (1) aa: x:= 5 (2) yy:= 5

    Cuando se analiza una sentencia y se encuentra el identificador yy puede haber duda al elegir la alternativa correcta en la produccin , si se elige identificador se supone que se est en el caso (1). Si se elige vaco se supone que se est en el caso (2), eligindose posteriormente , e identificador. Esto produce que el lenguaje no sea LL(1).

    Para resolver este problema el lenguaje de programacin puede exigir la declaracin obligatoria de los identificadores de tipo etiqueta, y por medio de una consulta a la tabla de smbolos el analizador puede decidir si el identificador es una etiqueta o una variable de otro tipo, con lo que discrimina entre instruccin con etiqueta (1) y sentencia de

  • Anlisis Sintctico en Procesadores de Lenguaje

    45

    asignacin (2). Otra solucin sera dar un smbolo terminal diferente para las etiquetas, dado que la declaracin obligatoria permitir fcilmente al analizador lxico reconocerlas, y se evita que la gramtica no sea LL(1).

    El lenguaje Pascal estndar subsana esto definiendo etiqueta como un entero sin signo con declaracin obligatoria, sin embargo las extensiones del Turbo Pascal de Borland permiten el uso de identificadores como etiquetas. Los lenguajes C y C++ permiten el uso de identificadores como etiquetas que no se declaran.

    5.5 Construccin de analizadores si