Ejemplos

65
Análisis Sintáctico Descendente Tema 4 Juan A. Bot´ ıa Blaya [email protected] http://ants.dif.um.es/staff/juanbot/traductores/traductores.html Departamento de Ingenier´ ıa de la Informaci ´ on y las Comunicaciones Universidad de Murcia An ´ alisis Sint ´ actico Descendente – p.1/65

description

Autor: Juan A. Botía Blaya

Transcript of Ejemplos

Page 1: Ejemplos

Análisis Sintáctico DescendenteTema 4

Juan A. Botıa [email protected]

http://ants.dif.um.es/staff/juanbot/traductores/traductores.html

Departamento de Ingenierıa de la Informacion y las Comunicaciones

Universidad de Murcia

Analisis Sintactico Descendente – p.1/65

Page 2: Ejemplos

Índice

Tema 4. Análisis Sintáctico Descendente

1. Análisis descendente general con retroceso

2. Análisis descendente predictivo(a) Gramáticas LL(1). Construcción de PRIMERO y

SIGUIENTE.Construcción de la tabla de análisis

(b) Análisis descendente predictivo no recursivo(c) Análisis descendente predictivo recursivo

Analisis Sintactico Descendente – p.2/65

Page 3: Ejemplos

Análisis descendente general con retroceso

Sea una gramática cualquiera, G del tipo CFG y su correspondiente AP nodeterminista.

Vamos a simular los movimientos de ese AP ante una cadena de entrada w.

Para cada transición del autómata vamos a tener un conjunto de posibles movimientosque podríamos realizar para simular la lectura de un determinado símbolo de w.

Podríamos ir comprobando todos los posibles movimientos que se pueden generar apartir de cada transición (cjto. transiciones destino finito).

Inconveniente: puede dar lugar a un aumento exponencial en el número decaminos a explorar.

Ventaja: método muy sencillo de codificar.

Si w /∈ L(G) entonces habrá que hacer una búsqueda exhaustiva de todos losposibles movimientos del automata.

Si w ∈ L(G),

Podría interesarnos el primer árbol de derivación que obtengamos

Si quisieramos obtener todos los posibles árboles de derivación que puedandarse la búsqueda debería ser también exhaustiva.

Analisis Sintactico Descendente – p.3/65

Page 4: Ejemplos

Ejemplo Informal

Sea la gramática G = (VN , VT , P, S), con las producciones deP = {S → aSbS|aS|c}.

Asumimos como orden predeterminado el mismo en el queaparecen.

Sea la cadena de entrada w = aacbc.

Usaremos un apuntador, que nos indica en todo momento el símboloai ∈ w que estamos intentando reducir.

El árbol de derivación va a contener inicialmente el símbolo S.

En todo momento, en el árbol va a haber un nodo activo.Inicialmente el nodo activo es S.

Analisis Sintactico Descendente – p.4/65

Page 5: Ejemplos

Ejemplo (Cont.)

A partir de ahí se van a ejecutar los siguientes pasos:

1. Si el nodo activo está etiquetado con A ∈ VN ,se escoge la primera alternativa correspondiente a las partes derechas de A.Sea esta X1X2 · · ·Xk . Creamos k descendientes directos: X1, X2, . . . , Xk.Ahora X1 es el nodo activo (si k = 0 el nodo activo es el que se encuentrainmediatamente a la derecha de A).

2. Si el nodo activo está etiquetado con a ∈ VT , se compara a con el símbolo de w

apuntado por el apuntador anteriormente mencionado.Si coinciden, el nodo activo pasa a ser el inmediatamente derecho de eletiquetado con a, y se avanza el puntero un lugar a la derecha.Si no, se vuelve al nodo en donde se aplicó la producción última, se ajusta elpuntero y se aplica la siguiente producción de entre las alternativas.Si no hubiera más alternativas entonces, volver a subir un nivel, y repetir elproceso.

Analisis Sintactico Descendente – p.5/65

Page 6: Ejemplos

Ejemplo (Cont.)

Si aplicamos el proceso anterior al ejemplo previamente introducido,etiquetamos al primer nodo con S y lo activamos. Al elegir y aplicarla primera S−producción, tenemos el árbol siguiente:

S

a S Sb

Analisis Sintactico Descendente – p.6/65

Page 7: Ejemplos

Ejemplo (Cont.)

Ahora hacemos que el nodo activo sea el etiquetado como ’a’. Dadoque a1 = a, avanzamos el apuntador que pasa ahora a señalar a a2.Hacemos nodo activo a S (i.e. el que se encuentra inmediantamentea la derecha de a) y aplicamos la primera S−producción, obteniendoel árbol parcial siguiente:

a S Sb

a S Sb

S

Analisis Sintactico Descendente – p.7/65

Page 8: Ejemplos

Ejemplo (Cont.)

Volvemos a hacer activo el nuevo nodo etiquetado con’a’ del nivel más profundo del árbol, y comprobamosque el caracter a2 coincide con ese terminal. Por lotanto, actualizamos el puntero a a3, y hacemos activo elnodo de la derecha (S), y aplicamos la primeraS−producción a partir de él. Obtenemos:

a S Sb

a S Sb

a S Sb

S

Analisis Sintactico Descendente – p.8/65

Page 9: Ejemplos

Ejemplo (Cont.)

En el que, despues de hacer nodo activo el más a laizquierda de los recientemente generados, podemoscomprobar que a3 6= a, y por lo tanto rechazamos estaalternativa. Volviendo a la siguiente S−producción,expandimos nuevamente el árbol y generamos

a S Sb

a S Sb

S

a S

que tampoco va a coincidir.

Analisis Sintactico Descendente – p.9/65

Page 10: Ejemplos

Ejemplo (Cont.)

Si probamos la última opción,

a S Sb

a S Sb

S

c

vemos que, haciendo previamente nodo activo al quese acaba de generar, a3 = c.

Analisis Sintactico Descendente – p.10/65

Page 11: Ejemplos

Ejemplo (Cont.)

Como al nivel de profundidad actual no hay más nodos a la derecha del etiquetadocon c, subimos un nivel en el árbol, haciendo activo al nodo b, a la derecha de el queacabamos de expandir (S).

Se comprueba que su etiqueta coincide con a4 y por lo tanto, actualizamos elapuntador, y hacemos activo el nodo a la derecha del etiquetado con b, que lleva laetiqueta S.

Si lo expandimos con la primera opción fallará, al igual que con la segunda. Sinembargo la tercera generará el árbol

a S Sb

a S Sb

S

c c

Analisis Sintactico Descendente – p.11/65

Page 12: Ejemplos

Ejemplo (Cont.)

Ahora la etiqueta del nuevo nodo activo coincide con el último símbolo, a5 de w.Hemos hecho un reconocimiento de la cadena completa, sin embargo aun quedan bS:este camino no es el correcto.

Se vuelve a recuperar como nodo activo al padre pero no existen más alternativas.Como es el que está más a la derecha, tenemos que recuperar como activo a supadre.

Al llegar a b, en profundidad inmediatamente por debajo de la raíz el apuntadorreferencia a a2, y el nodo etiquetado con la primera S de derecha a izquierda esnuevamente el activo.

Elegimos la siguiente opción para S y obtenemos el árbol

a S Sb

S

a SAnalisis Sintactico Descendente – p.12/65

Page 13: Ejemplos

Ejemplo (Cont.)

El nuevo nodo activo, etiquetado con una a coincide con a2. Avanzamos el puntero yhacemos activo a S, a su derecha. Aplicamos la primera S−producción y obtenemosel árbol

a S Sb

a S Sb

S

a S

que no resulta válido. Aplicando la segunda tampoco obtenemos un árbol adecuado.Si aplicamos la tercera, obtenemos

a S Sb

S

a S

c

Si seguimos aplicando el algoritmo de esta forma obtendremos como primer árbol dederivación válido, el siguiente:

a S Sb

S

a S

c

c

Analisis Sintactico Descendente – p.13/65

Page 14: Ejemplos

Retroceso y Recursividad

Si la gramática de entrada es recursiva, elprocedimiento puede caer en ciclos infinitos.

En el ejemplo de la producción A → ab|Ab, si llegamosa un nodo con A como etiqueta, la primera opción nodaría problemas, pero para una cadena de entrada enla que fuera necesario probar con la segunda opción,se generaría un árbol de profundidad infinita.

Si la recursividad no fuera inmediata, el problema aunpersistiría. Si P = {S → AB,A → SC, . . .}, podríamostener la secuencia de derivación S ⇒ SC ⇒ ABC quese repetiría indefinidamente.

Analisis Sintactico Descendente – p.14/65

Page 15: Ejemplos

Retroceso y Recursividad

Para evitar esto podríamos limitar el número de nodos del árbol de derivacióndependiendo de la longitud e la cadena de entrada.

Una gramática G = (VN , VT , P, S) con |VN | = k y para una cadena de entradaw tal que |w| = n − 1, si w ∈ L(G), existe al menos un árbol de derivación paraw que no tiene una profundidad mayor que kn.

El espacio de búsqueda de árboles de derivación de profundidad ≤ d es unafunción con un crecimiento muy fuerte, dependiente de d.

Por ejemplo, para P = {S → SS|λ}, el número de árboles posibles, conprofundidad d viene dado por la expresión recursiva:

D(1) = 1

D(d) = (D(d − 1))2 + 1

Cuyo crecimiento puede verse en la siguiente tabla:

Profundidad Árboles Posibles

1 1

2 2

3 5

4 26

5 677

6 458330

Analisis Sintactico Descendente – p.15/65

Page 16: Ejemplos

Algoritmo de análisis sintáctico general descendente con retroceso

Algoritmo 1 Análisis descendente general con retroceso.Entrada: Una gramática CFG, G = (VN , VT , P, S), sin recursividad por la izquierda, y una cadena de entradaw = a1a2 . . . an, n ≥ 0. Las producciones en P han de estar numeradas, con índices 1, 2, . . . , p.Salida: Una derivación izquierda, si existe. Si no un error.Preparativos

Para cada A ∈ VN , ordénense las alternativas de tal forma que si A → α1| · · · αk entonces, Ai es el índiceescogido para αi . Todos los Ai , 1 ≤ i ≤ k van a formar el conjunto IA que determina un orden fijo.

El algoritmo va a funcionar a la manera de un autómata de pila. Una configuración va a estar formada por unacuádrupla (s, i, α, β), en donde:

s denota un estado en {q, b, t}. El primero, q, denota que se está en situación normal. El estado b denotaque se está en situación de retroceso. El tercero, t, que se ha reconocido la cadena.

i representa el símbolo actual ai de w en el que nos encontramos en el análisis. El símbolo de entrada(n + 1)-ésimo es $.

α representa una primera pila de símbolos, L1 , en la que se van a almacenar un histórico de todas laselecciones Ai para cada A ∈ VN que ha participado en una producción en el árbol parcial estamosconstruyendo junto con los correspondientes símbolos terminales de la cadena w que hasta ahora se hanreducido. La vamos a representar con la cabeza de la pila a la derecha.

β es una segunda pila de símbolos, L2, que contiene la forma sentencial que se ha obtenido hasta elmomento, y en su cabeza aparece el nodo activo actualmente, si usamos la terminología vista en el ejemploinformal anterior. La vamos a representar con la cabeza de la pila a la izquierda.

Analisis Sintactico Descendente – p.16/65

Page 17: Ejemplos

Algoritmo de análisis sintáctico general descendente con retroceso

La configuración inicial del algoritmo es (q, 1, λ, S$).

La notación (s, i, α, β) ` (s′, i′, α′, β′) indica que el movimiento, desde la configuración(s, i, α, β) es hacia la configuración (s′, i′, α′, β′). El índice i, va a ser tal que 1 ≤ i ≤ n + 1,α ∈ (VT ∪ I)∗, en donde I es el correspondiente cjto. de índices de alternativas, yβ ∈ (VN ∪ VT )∗.

Los tres primeros tipos de movimientos son:

1. Expansión del árbol

(q, i, α, Aβ) ` (q, i, αA1, γ1β)

en donde A → γ1 ∈ P , y γ1 es la primera alternativa, según el órden establecido, para A

que es el no terminal no expandido aun más a la izquierda en la frontera del árbol parcial.

2. Coincidencia del símbolo de entrada y un símbolo derivado

(q, i, α, aβ) ` (q, i + 1, αa, β)

siendo αi = a, e i ≤ n.

3. Reconocimiento de la cadena

(q, n + 1, α, $) ` (t, n + 1, α, λ)

Se observa que se alcanza el final de la entrada, con i = n + 1 y además se ha obtenidouna derivación izquierda que es igual a w. El árbol de derivación izquierdo está en α.

Analisis Sintactico Descendente – p.17/65

Page 18: Ejemplos

Algoritmo de análisis sintáctico general descendente con retroceso

Los tres siguientes

4. No coincidencia del símbolo de entrada y el símbolo derivado

(q, i, α, aβ) ` (b, i, α, aβ) if ai 6= a

5. Retroceso en la entrada(b, i, αa, β) ` (b, i − 1, α, aβ)

siendo a ∈ VT .6. Nueva alternativa

(b, i, αAj , γjβ) `

(a) (q, i, αAj+1, γj + 1β), si γj+1 es la alternativa j + 1-ésima para A.(b) No hay más configuraciones. Si i = 1, A = S y solamente hay j alternativas para A.

Esto quiere decir que hemos recorrido todo el árbol, y ya no quedan más alternativas queexpandir. La cadena w /∈ L(G).

(c) (b, i, α, Aβ) en otro caso. Las alternativas de A se han acabado, y hacemos retrocesoeliminando A de L1 y reemplazando γj por A en L2.

Analisis Sintactico Descendente – p.18/65

Page 19: Ejemplos

Algoritmo de análisis sintáctico general descendente con retroceso

Ejecucion:

Paso 1: Comenzando en la configuración inicial,computar las configuraciones sucesivas

C0 ` C1 ` · · · ` Ci ` · · ·

hasta que no se pueda calcular ninguna más.

Paso 2: Si la última Cu computada es (t, n + 1, γ, λ)entonces calcular, a partir de γ la derivación obtenida yfinalizar. Si no, emitir una señal de error y finalizar.

Fin Algoritmo

Analisis Sintactico Descendente – p.19/65

Page 20: Ejemplos

Análisis Descendente Predictivo

ADGR → n3 como complejidad temporal, y n2 como complejidad espacial

Vamos a estudiar un conjunto especial de gramáticas de análisis sintáctico concomplejidad espacial y temporal c1n y c2n

Número de gramática pequeño, aunque suficiente

Algoritmos deterministas

Con las gramáticas de tipo LL(k), concretamente las LL(1), va a ser suficiente elmirar el siguiente token en la cadena de entrada para determinar cual va a ser la reglade producción a aplicar en la construcción del árbol de derivación.

Las gramáticas con análisis de una pasada son:

Tipo LL(k)

Tipo LR(K)

Gramaticas de Precedencia

Dado que este capítulo está dedicado al análisis descendente, nos centraremos enlas gramáticas LL(K), y concretamente en las LL(1).

Analisis Sintactico Descendente – p.20/65

Page 21: Ejemplos

Gramáticas LL(1)

Para introducir formálmente el concepto de gramática LL(1) primero necesitamosdefinir el concepto de FIRSTk(α).

Definición 1 Sea una CFG G = (VN , VT , S, P ). Se define el conjunto

FIRSTk(α) = {x|α∗

⇒lm xβ y |x| = k o bien α∗⇒ x y |x| < k}

en donde k ∈ N y α ∈ (VN ∪ VT )∗.

Ahora podemos definir el concepto de gramática LL(k).

Definición 2 Sea una CFG G = (VN , VT , S, P ). Decimos que G es LL(k) paraalgún entero fijo k, cuando siempre que existens dos derivaciones más a la izquierda

1. S∗

⇒lm wAα ⇒lm wβα∗⇒ wx y

2. S∗

⇒lm wAα ⇒lm wγα∗⇒ wy

tales que FIRSTk(x) = FIRSTk(y), entonces se tiene que β = γ.

Analisis Sintactico Descendente – p.21/65

Page 22: Ejemplos

Gramáticas LL(1)

Ejemplo: Sea G1 la gramática con cjto. P = {S → aAS|b,A → a|bSA}. Vamos a verque esta gramática es LL(1). Entonces, si

S∗

⇒lm wSα ⇒lm wβα∗

⇒lm wx

y

S∗

⇒lm wSα ⇒lm wγα∗

⇒lm wy

Si x e y comienzan con el mismo símbolo, se tiene que dar β = γ. Por casos, six = y = a, entonces se ha usado la producción S → aAS. Como únicamente se hausado una producción, entonces β = γ = aAS. Si x = y = b, se ha usado S → b, yentonces β = γ = b.Si se consideran las derivaciones

S∗

⇒lm wAα ⇒lm wβα∗

⇒lm wx

y

S∗

⇒lm wAα ⇒lm wγα∗

⇒lm wy

se produce el mismo razonamiento.

Analisis Sintactico Descendente – p.22/65

Page 23: Ejemplos

Gramáticas LL(1)

El decidir si un lenguaje es LL(1) es un problema indecidible.

Vamos a definir ahora una gramática LL(1)

Definición 3 Sea una CFG G = (VN , VT , S, P ). Decimos que G es LL(1) cuandosiempre que existens dos derivaciones más a la izquierda

1. S∗

⇒lm wAα ⇒lm wβα∗⇒ wx y

2. S∗

⇒lm wAα ⇒lm wγα∗⇒ wy

tales que FIRST1(x) = FIRST1(y), entonces se tiene que β = γ.

Para poder construir un analizador sintáctico predictivo, con k = 1, se debe conocer,dado el símbolo de entrada actual ai y el no terminal A a expandir, cuál de lasalternativas de la producción A → α1| · · · |αn es la única que va a dar lugar a unasubcadena que comience con ai.

Piénsese, por ejemplo, en el conjunto de producciones siguiente:

prop → if expr then prop else prop

| while expr do prop

| begin lista props end

Analisis Sintactico Descendente – p.23/65

Page 24: Ejemplos

Gramáticas LL(1)

Podríamos conseguir una gramática LL(1)

Si se tiene cuidado al escribir la gramática,eliminando la ambiguedad,la recursión por la izquierda, yfactorizandola por la izquierda.

Analisis Sintactico Descendente – p.24/65

Page 25: Ejemplos

Factorizando una gramática por la izquierda

Algoritmo 2 Factorización por la izquierda de una gramática.Entrada: la gramática G.Salida: Una gramática equivalente y factorizada por la izquierda.Método: Para cada no-terminal A, sea α el prefijo más largo común a doso más de sus alternativas. Si α 6= λ, o lo que es lo mismo, existe unprefijo común no trivial, se han de sustituir todas las producciones de A,

A → αβ1|αβ2| · · · |αβn|γ

en donde γ representa a todas las partes derechas que no comienzancon α, por

A → αA′|γ

A′ → β1|β2| · · · |βn

Aplicar la transformación hasta que no haya dos alternativas para unno-terminal con un prefijo común no trivial.

Analisis Sintactico Descendente – p.25/65

Page 26: Ejemplos

Ejemplo

Ejemplo: Sea la gramática

prop → if expr then prop

| if expr then prop else prop

| otra

Si le aplicamos la transformación anterior, la gramática resultante sería

prop → if expr then prop siguiente prop

| otra

siguiente_prop → else prop | λ

Sigue siendo ambigua

Aunque se puede expandir prop a if expr then prop siguiente prop, con la entradaif, y esperar hasta que if expr then prop haya aparecido, para decidir entonces siexpandir siguiente prop a else prop ó a λ.

Para la entrada else las dos gramáticas siguen siendo ambiguas. Veremos, másadelante, como solucionar este problema.

Analisis Sintactico Descendente – p.26/65

Page 27: Ejemplos

Conjuntos FIRST y FOLLOW

Conjuntos de apoyo para la construcción del analizador sintácticodescendente predictivo.

Vamos a introducir el conjunto FOLLOWk(β) formalmente

Definición 4 Sea G = (VN , VT , S, P ) una gramática CFG. DefinimosFOLLOW G

k (β), en donde k es un entero, β ∈ (VN ∪ VT )∗, como elconjunto

{w|S∗⇒ αβγ junto con w ∈ FIRST G

k (γ)}

Particularizándolo para FOLLOW1 ≡ FOLLOW , sea A un noterminal de una gramática determinada. Definimos FOLLOW (A)

como el conjunto de terminales a tal que haya una derivación de laforma S

∗⇒ αAaβ, para algún α y β, si A es el símbolo más a la

derecha en determinada forma sentencial de la gramática, entoncesel símbolo $ ∈ FOLLOW (A).

Analisis Sintactico Descendente – p.27/65

Page 28: Ejemplos

Algoritmo para el cálculo de FIRST

Algoritmo 3 Cálculo del conjunto FIRST para todos los símbolos no termi-nales y terminales de la gramática de entrada.

Entrada: Una gramática G = (VN , VT , S, P ) de tipo CFG.

Salida: Los conjuntos FIRST (X) para todo X ∈ (VN ∪ VT ).

Método: Ejecutar el siguiente método para todo X ∈ (VN ∪ VT ).

1. Si X ∈ VT , entonces FIRST (X) = {X}.

2. Sino, si X ∈ VN y X → λ ∈ P , entonces añadir λ a FIRST (X).

3. Sino, si X ∈ VN y X → Y1Y2 · · ·Yk ∈ P añadir todo a ∈ VT tal quepara algún i, con 1 ≤ i ≤ k, a ∈ FIRST (Yi) yλ ∈ FIRST (Y1), . . . , F IRST (Yi−1), o lo que es lo mismo,

Y1Y2 . . . Yi−1∗⇒ λ. Además, si λ ∈ FIRST (Yj) para todo

j = 1, 2, . . . , k, añadir λ a FIRST (X).

Analisis Sintactico Descendente – p.28/65

Page 29: Ejemplos

Algoritmo para el cálculo de FOLLOW

Algoritmo 4 Cálculo del conjunto FOLLOW para todos los símbolos no termi-nales de la gramática de entrada.

Entrada: Una gramática G = (VN , VT , S, P ) de tipo CFG.

Salida: Los conjuntos FOLLOW (X) para todo X ∈ VN .

Método: Ejecutar el siguiente método para todo X ∈ VN hasta que no sepueda añadir nada más a ningún conjunto FOLLOW.

1. Añadir $ a FOLLOW (S), en donde $ es el delimitador derecho de laentrada.

2. Si existe una producción A → αBβ ∈ P añadir todoFIRST (β) − {λ} a FOLLOW (B).

3. Si existen una producción A → αB ∈ P , ó A → αBβ ∈ P tal queλ ∈ FIRST (β), entonces añadir FOLLOW (A) a FOLLOW (B).

Analisis Sintactico Descendente – p.29/65

Page 30: Ejemplos

Ejemplo de construcción de FIRST y FOLLOW

Sea la siguiente gramática:

E → TE′

E′ → +TE′|λ

T → FT ′

T ′ → ∗FT ′|λ

F → (E)|id

Los conjuntos FIRST para todos los símbolos terminales de VT = {(, ), +, ∗} son ellosmismos.

Para el no terminal F , aplicando el paso 3 introducimos al conjunto FIRST los símbolos ( y id.

Para el no terminal T ′, aplicando el paso 2 introducimos a FIRST λ, y por el paso 3, el símbolo∗.

Para el no terminal T , por el paso tres, con la regla de producción T → FT ′, añadimosFIRST (F ) a FIRST (T ).

Para E′, con el paso 2 se añade λ y con el tres se añade +.

Para E, FIRST (E) queda con el contenido {(, id} al darse la producción E → TE ′, aplicandoel paso 3.

Los conjuntos FIRST quedan como sigue:

FIRST (F ) = {(, ID} FIRST (T ′) = {∗, λ} FIRST (T ) = {(, ID}

FIRST (E′) = {+, λ} FIRST (E) = {(, ID}Analisis Sintactico Descendente – p.30/65

Page 31: Ejemplos

Ejemplo de construcción de FIRST y FOLLOW (II)

Pasamos ahora a calcular los conjuntos FOLLOW .

Para el símbolo E, el conjunto FOLLOW (E) = {$, )}, añadiendo el $ por el paso 1, y elparéntesis derecho por el paso 3 y la producción F → (E).

Al conjunto FOLLOW (E′) añadimos el contenido de FOLLOW (E) por el paso 3, y laproducción E → TE′.

Al conjunto FOLLOW (T ) se añade + por el paso 2 y la producción E → TE′. Además,como E′ → λ ∈ P , añadimos el contenido de FOLLOW (E′).

Como tenemos que T → FT ′ ∈ P , añadimos FOLLOW (T ) a FOLLOW (T ′).

Por el paso 2, y las producciones T → FT ′ y T ′ → ∗FT ′ añadimos el contenido deFIRST (T ′) − λ a FOLLOW (F ). Además, como T ′ → λ añadimos FOLLOW (T ′).

Y obtenemos los conjuntos FOLLOW siguientes:

FOLLOW (E) = {$, )}

FOLLOW (E′) = {$, )}

FOLLOW (T ) = {+, $, )}

FOLLOW (T ′) = {+, $, )}

FOLLOW (F ) = {∗, +, $, )}

Analisis Sintactico Descendente – p.31/65

Page 32: Ejemplos

Construcción de la tabla de análisis sintáctico

Vamos a construir una tabla de análisis sintáctico quedos diga en todo momento las posibles producciones aaplicar, dado un no-terminal a reducir y un símbolo dela entrada ai.

Esta tabla de análisis va a venir definida,algebraicamente, como:

M : VN × VT ∪ {$} → 2P

Analisis Sintactico Descendente – p.32/65

Page 33: Ejemplos

Construcción de la tabla de análisis sintáctico

El contenido de la tabla se produce con el algoritmo que aparece a continuación.

Algoritmo 5 Construcción de una tabla de análisis sintáctico predictivo.

Entrada: Una gramática G = (VN , VT , S, P ), CFG.

Salida: La tabla de análisis sintáctico M .

Método:1. Créese una tabla M|VN |×(|VT |+1), con una fila para cada no-terminal y

una columna para cada terminal más el $.2. Para cada A → α ∈ P , ejecutar los pasos 3 y 4.3. Para cada a ∈ FIRST (α), añadir A → α a M [A, a].4. Si λ ∈ FIRST (α), añadir A → α a M [A, b], para cada terminal

b ∈ FOLLOW (A). Si además, $ ∈ FOLLOW (A), añadir A → α aM [A, $].

5. Introducir, en cada entrada de M vacía un identificador de error.

Si alguna casilla de M contiene más de una producción de P , la gramática no esLL(1).

Analisis Sintactico Descendente – p.33/65

Page 34: Ejemplos

Construcción de la tabla de análisis sintáctico

Para la gramática anterior la tabla de análisis sintácticopredictivo queda:

id + * ( ) $

E E → TE′ E → TE′ E → TE′

E′ E′ → +TE′ E′ → λ E′ → λ

T T → FT ′ T → FT ′

T ′ T ′ → λ T ′ → ∗FT ′ T ′ → λ T ′ → λ

F F → id F → (E)

Analisis Sintactico Descendente – p.34/65

Page 35: Ejemplos

Gramáticas no LL(1)

Ahora vamos a ver un ejemplo, con una gramática no LL(1)

prop → if expr then prop

| if expr then prop else prop

| a | b

expr → p | q

Si eliminamos la ambigüedad, como ya habíamos visto en otro tema, la gramáticaqueda:

prop → prop1 | prop2

prop1 → if expr then prop1 else prop1

| a | b

prop2 → if expr then prop

| if expr then prop1 else prop2

expr → p | q

Analisis Sintactico Descendente – p.35/65

Page 36: Ejemplos

Gramáticas no LL(1)

Si factorizamos la gramática por la izquierda, tenemos

prop → prop1 | prop2

prop1 → if expr then prop1 else prop1

| a | b

prop2 → if expr then prop2’

prop2’ → prop

| prop1 else prop2

expr → p | q

Analisis Sintactico Descendente – p.36/65

Page 37: Ejemplos

Tabla de gramática no LL(1)

Se obtiene la tabla de análisis siguiente, que como sepuede ver, no es LL(1).

if then else

p p → p1|p2

p1 p1 → if expr then p1 else p1

p2 p2 → if expr then p′2

p′2

p′2

→ p

p′2

→ p1 else p2

expr

a b p q $

p p → p1 p → p1

p1 p1 → a p1 → b

p2

p′2

p′2

→ p

p′2

→ p1 else p2

p′2

→ p

p′2

→ p1 else p2

expr expr → p expr → q

Analisis Sintactico Descendente – p.37/65

Page 38: Ejemplos

Modificando la gramática

Compruébese que modificando ellenguaje, añadiendo delimitadoresde bloque (e.g. endif) la gramáticaproducida es LL(1).

Analisis Sintactico Descendente – p.38/65

Page 39: Ejemplos

Otras soluciones

Una manera ad-hoc de solucionar el problema esadoptando la convención de determinar, de antemano, laproducción a elegir de entre las disponibles en una celdadeterminada de M . Si en el ejemplo de la gramáticaanterior, factorizamos la gramática original, sin eliminar laambiguedad tenemos:

prop → if expr then prop prop’| a| b

prop’ → else prop| λ

expr → p| q

Analisis Sintactico Descendente – p.39/65

Page 40: Ejemplos

Construcción de la tabla de análisis sintáctico (VI)

Si construímos la tabla de análisis para esta gramática, nosqueda:

if else a b p q $

p p → if expr then p p′ p → a p → b

p′ p′ → else p

p′ → λp′ → λ

expr expr → p expr → q

En M [p′, else] hay dos producciones.

Si, por convenio, elegimos siempre p′ → else p,escogemos el árbol de derivación que asociaba el else

con el if más próximo.

En cualquier caso, no existe un criterio general para elegiruna sola regla de producción cuando hay varias en unamisma casilla.

Analisis Sintactico Descendente – p.40/65

Page 41: Ejemplos

Análisis Descendente Predictivo No Recursivo (ADPNR)

Para el diseño de un analizador sintáctico, descendente y no recursivo necesitamos

una estructura de pila.

Vamos a usar la tabla que se ha estudiado anteriormente.

La cadena de entrada para el análisis.

El modelo de parser de este tipo es el de la figura

Analizador

Sintáctico

Predictivo

No Recursivo

a + b $

X

Y

Z

$

Tabla M

Salida

Pila

El final del buffer de entrada está delimitado con el signo $, así como el fondo de lapila.

La pila podrá albergar tanto símbolos terminales como no-terminales. Estará vacíacuando el elemento que aparezca en la cabeza de la misma sea $.

Analisis Sintactico Descendente – p.41/65

Page 42: Ejemplos

Análisis Descendente Predictivo No Recursivo (II)

Siempre se tiene en cuenta la cabeza de la pila y el siguiente carácter a la entrada.

Sea X la cabeza de la pila y a el símbolo de entrada actual.

Dependiendo de si X es no-terminal ó terminal tendremos:

Si X = a = $ el análisis finaliza con éxito.

Si a ∈ VT y X = a, el analizador sintáctico saca X de la pila, y desplaza elapuntador de la entrada un lugar a la derecha. No hay mensaje de salida.

Si X ∈ VN , es hora de usar M . Para ello, el control del análisis consulta laentrada M [X, a].

Si M [X, a] = {X → UV W}, por ejemplo, se realiza una operación pop, conlo que sacamos X de la cima, y una operación push(UV W ), estando U en lacima. La salida, tras esa operación, es precisamente la producción utilizada,X → UV W .Si M [X, a] = ∅, el análisis es incorrecto, y la cadena de entrada no perteneceal lenguaje generado por la gramática. La salida es error. Posiblemente sellame a una rutina de recuperación de errores.

Analisis Sintactico Descendente – p.42/65

Page 43: Ejemplos

ADPNR → Algoritmo

Algoritmo 6 Análisis Sintáctico Predictivo No Recursivo.

Entrada: Una tabla de análisis sintáctico M para una gramática G = (VN , VT , S, P ), CFG yuna cadena de entrada w.

Salida: Si w ∈ L(G), una derivación por la izquierda de w; si no una indicación de error.

Método:Sea la configuración inicial de la pila, $S. Sea w$ el buffer de entrada.

Hacer que ap(apuntador) apunte al primer símbolo de w$.

Repetir

Sea X el símbolo a la cabeza de la pila, y a el símbolo apuntado por ap.

Si X ∈ VT o X = $ Entonces· Si X = a Entonces extraer X de la pila y avanzar ap.· Si no error();

Si No· Si M [X, a] = X → Y1Y2 · · · Yk entonces· Begin

1. Extraer X de la pila2. Meter YkYk−1 · · · Y1 en la pila, con Y1 en la cima

3. Emitir a la salida la producción X → Y1Y2 · · · Yk

· End· Si no error()

Hasta que (X = $).

Analisis Sintactico Descendente – p.43/65

Page 44: Ejemplos

Ejemplos

Para hacer un seguimiento de las sucesivasconfiguraciones que va adquiriendo el algoritmo, se usauna tabla de tres columnas:

En la primera se muestra, para cada movimiento elcontenido de la pila,en la segunda la entrada que aun queda poranalizar, yen la tercera la salida que va emitiendo el algoritmo.

Analisis Sintactico Descendente – p.44/65

Page 45: Ejemplos

Ejemplos

PILA ENTRADA SALIDA$E id + id ∗ id$$E′T id + id ∗ id$ E → T ′E$E′T ′F id + id ∗ id$ T → FT ′

$E′T ′id id + id ∗ id$ F → id$E′T ′ +id ∗ id$$E′ +id ∗ id$ T → λ$E′T+ +id ∗ id$ E′ → +TE′

$E′T id ∗ id$$E′T ′F id ∗ id$ T → FT ′

$E′T ′id id ∗ id$ F → id$E′T ′ ∗id$$E′T ′F∗ ∗id$ T ′ → ∗FT ′

$E′T ′F id$$E′T ′id id$ F → id$E′T ′ $$E′ $ T ′ → λ$ $ E′ → λ

Analisis Sintactico Descendente – p.45/65

Page 46: Ejemplos

Recuperación de Errores en el análisis descendente predictivo

Los errores pueden darse por dos situaciones

bien diferentes:

Cuando el terminal de la cabeza de la pila no

concuerda con el siguiente terminal a la

entrada.

Cuando se tiene un no-terminal A en la cima

de la pila, y un símbolo a a la entrada, y la el

contenido de M [A, a] = ∅.

Analisis Sintactico Descendente – p.46/65

Page 47: Ejemplos

Recuperación de Errores en el análisis descendente predictivo

Recuperación a Nivel de Frase: consiste en introducir apuntadores a rutinas de erroren las casillas en blanco de la tabla M → muy complejo.

Recuperación en Modo Pánico

Los cjtos. de tokens deben ser formados cuidadosamente (eficiencia)

Se deberá prestar más atención a aquellos errores que ocurren con másfrecuencia en la práctica.

HeurísticasTodo lo que viene a continuación equivalía, en teoría, a la parte derecha de unno terminalEstructura de bloque del lenguajewhile(a > 0)

{

if (a=100) printf(‘‘Estamos en la iteracion 100’’);

for(int j = 0;j < a;j++) printf(‘‘Iteracion’’);

}

Los tokens erroneos son añadiduras prescindibles

Analisis Sintactico Descendente – p.47/65

Page 48: Ejemplos

Soluciones a las heurísticas

Todo lo que viene a continuación equivalía, en teoría, a la partederecha de un no terminal → Dado el símbolo A ∈ VN , para él lostokens de sincronización podrían ser aquellos pertenecientes aFOLLOW (A) →

Estructura de bloque del lenguaje

Incluir las palabras claves en el conjunto de sincronización paraA.

Incluir en los conjuntos de sincronización de no-terminalesinferiores, los terminales que inician las construccionessuperiores.

Los tokens erroneos son añadiduras prescindibles → incluir, enel conjunto de sincronización de los correspondientes A, elcontenido de FIRST (A).

Analisis Sintactico Descendente – p.48/65

Page 49: Ejemplos

Recuperación de Errores en el análisis descendente predictivo

Veámoslo con un ejemplo. Obsérvese la tabla siguiente:

id + * ( ) $

E E → TE′ E → TE′ sinc sinc

E′ E′ → +TE′ E′ → λ E′ → λ

T T → FT ′ sinc T → FT ′ sinc sinc

T ′ T ′ → λ T ′ → ∗FT ′ T ′ → λ T ′ → λ

F F → id sinc sinc F → (E) sinc sinc

Analisis Sintactico Descendente – p.49/65

Page 50: Ejemplos

Recuperación de Errores en el análisis descendente predictivo

En ella se han incluido, como tokens de sincronización,aquellos correspondientes a los tokens de FOLLOW

del no-terminal en cuestión.

Para utilizar la tabla, con esos nuevos elementos, se hade hacer:1. Si M [A, a] = ∅, ignoramos el símbolo de entrada y lo

saltamos.2. Si M [A, a] = sinc, se saca el no-terminal de la cima

de la pila y se continua el análisis.3. Si en el caso de comparar la cima de la pila con un

componente léxico de la entrada, estos noconcuerdan, sacamos el componente léxico de lapila, como en el paso 1.

Analisis Sintactico Descendente – p.50/65

Page 51: Ejemplos

Recuperación de Errores en el análisis descendente predictivo

Si lo estudiamos con la entrada )id ∗ +id, vemos la evolución delalgoritmo en la siguiente tabla:

PILA ENTRADA Comentario$E )id ∗ +id$ error, ignorar )$E id ∗ +id$ id ∈ FIRST (E)$E′T id ∗ +id$$E′T ′F id ∗ +id$$E′T ′id id ∗ +id$$E′T ′ ∗ + id$$E′T ′F∗ ∗ + id$$E′T ′F +id$ error, M [F, +] = sinc$E′T ′ +id$ F se ha extraído de la pila$E′ +id$$E′T+ +id$$E′T id$$E′T ′F id$$E′T ′id id$$E′T ′ $$E′ $$ $

Analisis Sintactico Descendente – p.51/65

Page 52: Ejemplos

Recuperación de Errores en el análisis descendente predictivo

En el parsing anterior se observa una primerasecuencia de derivaciones más a la izquierda:

E ⇒ TE′ ⇒ FT ′E′ ⇒ idT ′E′ ⇒ id ∗ FT ′E′

A partir de ahí, no podríamos seguir generando lacadena. Si eliminamos F de la cima de la pila podemoscontinuar con:

id ∗ +idT ′E′ ⇒ id ∗ +idE ′ ⇒ id ∗ +id

Con lo que, al final somos capaces de simular laproducción de la cadena errónea.

Analisis Sintactico Descendente – p.52/65

Page 53: Ejemplos

Recuperación de Errores en el análisis descendente predictivo

Otro ejemplo puede ser el de la entrada (id$, para lamisma gramática. La evolución del algoritmo será:

PILA ENTRADA Comentario$E (id$$E′T (id$ E → TE′

$E′T ′F (id$ T → FT ′

$E′T ′)E(F (id$ F → (E)$E′T ′)E id$$E′T ′)E′T id$ E → TE′

$E′T ′)E′T ′F id$ T → FT ′

$E′T ′)E′T ′id id$ F → id$E′T ′)E′T ′ $$E′T ′)E′ $ T ′ → λ$E′T ′) $ E′ → λ$E′T ′ $ Error. Sacamos ’)’ de la pila.$E′ $ T ′ → λ$ $ E′ → λ$ $

Analisis Sintactico Descendente – p.53/65

Page 54: Ejemplos

Recuperación de Errores en el análisis descendente predictivo

Se interpreta que se había omitido, por equivocación, elparéntesis derecho. Esto produce la derivaciónizquierda siguiente:

E ⇒ TE′ ⇒ FT ′E′ ⇒ (E)T ′E′ ⇒ (TE′)T ′E′ ⇒

(FT ′E′)T ′E′ ⇒ (idT ′E′)T ′E′ ⇒ (idE′)T ′E′ ⇒ (id)T ′E′ ⇒ (id)E′ ⇒ (id)

Analisis Sintactico Descendente – p.54/65

Page 55: Ejemplos

Análisis Descendente Predictivo Recursivo

Se basa en la ejecución, en forma recursiva, de un conjunto de procedimientos que seencargan de procesar la entrada.

Se asocia un procedimiento a cada no-terminal de la gramática, con lo que se tieneque codificar cada uno de ellos según sus características.

Los símbolos de los respectivos conjuntos FIRST van a determinar, de forma noambigua, el siguiente procedimiento que se deberá invocar.

Se introducirá este análisis usando la gramática CFG, G = (VN , VT , S, P ) con elsiguiente conjunto de producciones en P :

tipo → simple

| ↑ id

| array [simple] of tipo

simple → integer

| char

| num puntopunto num

Esta gramática de tipo LL(1), ya que los respectivos conjuntos FIRST (tipo) yFIRST (simple) son disjuntos.

Analisis Sintactico Descendente – p.55/65

Page 56: Ejemplos

ADPR. Tipos de Procedimientos.

procedure empareja(t:simbolo);begin

if preanalisis = t then

preanalisis := sigsimboloelse error

end;procedure tipo;begin

if preanalisis is in {integer, char, num} then

simple

else if preanalisis = ’↑’ then begin

empareja(’↑’); empareja(id)endelse if preanalisis = array then begin

empareja(array); empareja(’]’); simple; empareja(’]’); empareja(of); tipoendelse error

end;

Analisis Sintactico Descendente – p.56/65

Page 57: Ejemplos

ADPR. Tipos de Procedimientos.

procedure simple;begin

if preanalisis = integer then

empareja(integer)

else if preanalisis = char then

empareja(char)

else if preanalisis = num then begin

empareja(num); empareja(puntopunto); empareja(numero);endelse error

end;

Analisis Sintactico Descendente – p.57/65

Page 58: Ejemplos

ADPR. Ejemplo de análisis.

Vamos a tener dos procedimientos similares, uno para cada símbolo ∈ VN . Cada unode los procedimientos, correspondientes a los no terminales tipo y simple.

Un procedimiento empareja para simplificar el código de los dos anteriores.

Nótese que el análisis sintáctico debe comenzar con una llamada al no-terminal quees símbolo inicial de la gramática, tipo.

Ejemplo:

array [num puntonum num] of integer;

El contenido de preanalisis es, inicialmente, array.

Se generan las llamadas

empareja(array); empareja(’[’]); simple; empareja(’[’);

empareja(of); tipo

que precisamente corresponde con la producción

tipo → array [simple] of tipo

Simplemente, se invoca al procedimiento empareja para cada símbolo terminal, y alos correspondientes simple y tipo para el tamaño y el tipo base del array,respectivamente.

Analisis Sintactico Descendente – p.58/65

Page 59: Ejemplos

ADPR. Ejemplo de análisis.

El orden de la invocación es importante, al estar realizando un análisis descendente y,por lo tanto, obteniendo una derivación más a la izquierda.

El valor del símbolo de anticipación inicial (i.e. array) coincide con el argumento deempareja(array) → se actualiza la variable preanalisis al siguiente carácter a laentrada, que es ’[’.

La llamada empareja(’[’) también actualiza la variable preanalisis pasando aser ahora num.

Ahora se invoca a simple, que compara el contenido de esta variable con todos lossímbolos terminales que forman su correspondiente conjunto FIRST . Coincide connum y por lo tanto se hace la siguiente serie de invocaciones:

empareja(num); empareja(puntopunto); empareja(num)

Analisis Sintactico Descendente – p.59/65

Page 60: Ejemplos

ADPR. Ejemplo de análisis (II).

Las llamadas anteriores resultan exitosas. Después de su ejecución, el contenido depreanalisis es of, y estamos en la llamada empareja(of).

Resulta exitosa y nuevamente se actualiza el contenido de preanálisis a integer.

Se llama ahora a tipo que genera su correspondiente llamada simple según dicta elsímbolo de preanálisis y el conjunto FIRST (tipo).

Finalmente se genera la llamada empareja(integer), y como el siguiente símboloes $, finaliza con éxito.

La secuencia de llamadas puede seguirse con

empareja(puntopunto)empareja(num) empareja(num)

tipo

empareja(array) empareja(’[’) empareja(’]’)simple empareja(of) tipo

simple

empareja(integer)

Analisis Sintactico Descendente – p.60/65

Page 61: Ejemplos

ADPR. Más ejemplos.

Otro ejemplo podemos verlo con la gramática siguiente:

E → TE′

E′ → +TE′|λ

T → FT ′

T ′ → ∗FT ′|λ

F → (E)|id

Vamos a escribir los procedimientos necesarios para el análisis recursivodescendente predicitivo, para esta gramática LL(1).

Se debe escribir un procedimiento para cada símbolo no-terminal, que se encarguede analizar sus correspondientes partes derechas.

En el caso especial de las λ−producciones (i.e. E ′ y T ′), si la variable preanalisis nocoincide con + ó ∗, respectivamente, se interpreta que el correspondiente símbolono-terminal se ha reducido a la palabra vacía y se continua el análisis.

Analisis Sintactico Descendente – p.61/65

Page 62: Ejemplos

Procedimientos

procedure empareja(t:simbolo);begin

if (preanalisis = t) then

preanalisis := sigsimbolo

else error

end;

procedure No_terminal_E;begin

No_terminal_T; No_terminal_E’

end;procedure No_terminal_E’;begin

if preanalisis = ’+’ then

empareja(’+’); No_terminal_T; No_terminal_E’

else

begin

end

end; Analisis Sintactico Descendente – p.62/65

Page 63: Ejemplos

Procedimientos

procedure No_terminal_T;begin

No_terminal_F; No_terminal_T’

end;procedure No_terminal_T’;begin

if preanalisis = ’*’ then begin

empareja(’*’); No_terminal_F; No_terminal_T’

end

end procedure No_terminal_F;begin

if preanalisis = ’(’ then begin

empareja(’(’); No_terminal_E; empareja(’)’)

else if preanalisis = id then

empareja(’id’);

end

Analisis Sintactico Descendente – p.63/65

Page 64: Ejemplos

ADPR. Ejemplo de análisis

E

T

F T’

emp(’(’) E emp(’)’)

T E’

F T’

emp(’id’)

E’

emp(’+’) T E’

F

emp(’id’)

T’

( id ) + id

Analisis Sintactico Descendente – p.64/65

Page 65: Ejemplos

ADPR. Ejemplo de análisis (IV).

emp(’+’) T E’

F

emp(’id’)

T’

E

T

F T’

emp(’(’) E emp(’)’)

T E’

F T’

emp(’id’)

E’

( id + id ) * id

emp(’*’) F T’

emp(’id’)

Analisis Sintactico Descendente – p.65/65