30.10.2014 Views

Procesadores de Lenguaje Tema 4: Analizador sintáctico ...

Procesadores de Lenguaje Tema 4: Analizador sintáctico ...

Procesadores de Lenguaje Tema 4: Analizador sintáctico ...

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong><br />

<strong>Tema</strong> 4: <strong>Analizador</strong> <strong>sintáctico</strong><br />

3 er curso<br />

2º cuatrimestre<br />

Alfonso Ortega: alfonso@ii.uam.es<br />

<strong>Analizador</strong> <strong>sintáctico</strong><br />

Conceptos<br />

• Se ocupa específicamente <strong>de</strong>l tratamiento <strong>de</strong> la parte <strong>de</strong>l lenguaje <strong>de</strong> programación<br />

que es in<strong>de</strong>pendiente <strong>de</strong>l contexto<br />

• Recuer<strong>de</strong> el alumno la <strong>de</strong>finición que vio en TALF <strong>de</strong> gramáticas in<strong>de</strong>pendientes <strong>de</strong>l<br />

contexto<br />

• < Σ T<br />

, Σ N<br />

, axioma, reglas ><br />

• Don<strong>de</strong><br />

• axioma ∈ Σ N<br />

• reglas ∈ ℘(Σ N<br />

×Σ * ),, Σ * = Σ T<br />

∪Σ N<br />

• Es <strong>de</strong>cir, las reglas <strong>de</strong> producción tienen la forma<br />

A→v,,A ∈ Σ N<br />

∧ v ∈ (Σ T<br />

∪Σ N<br />

) *<br />

• También recibe el nombre <strong>de</strong> “parser”<br />

• Suele ser el que gobierna todo el proceso <strong>de</strong> análisis.<br />

• El proceso <strong>de</strong> análisis pue<strong>de</strong> enten<strong>de</strong>rse como el mecanismo para obtener el “árbol<br />

<strong>sintáctico</strong> <strong>de</strong> <strong>de</strong>rivación <strong>de</strong>l programa (en caso <strong>de</strong> ser correcto) que es una manera<br />

<strong>de</strong> po<strong>de</strong>r reducir el programa completo al axioma <strong>de</strong> la gramática.<br />

• Recuér<strong>de</strong>se que, tras el paso <strong>de</strong> análisis morfológico, los símbolos terminales para<br />

este paso son las unida<strong>de</strong>s sintácticas reconocidas por el analizador morfológico<br />

Construcciones <strong>de</strong> lenguajes no in<strong>de</strong>pendientes <strong>de</strong>l contexto<br />

Declaración <strong>de</strong> i<strong>de</strong>ntificadores antes <strong>de</strong> su uso [Aho]<br />

• Considérese el siguiente lenguaje<br />

L={wcw|w∈(a|b)*}<br />

• Al analizar alguna <strong>de</strong> sus palabras:<br />

• aabcaab<br />

• aca<br />

• bcb<br />

• Po<strong>de</strong>mos interpretar que abstrae la circunstancia <strong>de</strong> utilizar un i<strong>de</strong>ntificador que ha<br />

sido previamente <strong>de</strong>clarado:<br />

• En aabcaab el i<strong>de</strong>ntificador sería aab<br />

• En aca el i<strong>de</strong>ntificador sería a<br />

• En bcb el i<strong>de</strong>ntificador sería b<br />

• En cualquiera <strong>de</strong> las situaciones, la primera aparición <strong>de</strong>l i<strong>de</strong>ntificador representa su<br />

<strong>de</strong>claración y la segunda su uso.<br />

• Observe que el lenguaje supone una simplificación bastante gran<strong>de</strong> <strong>de</strong> la situación<br />

real <strong>de</strong>scrita (ausencia <strong>de</strong> tipo en la <strong>de</strong>claración necesaria en muchos lenguajes, por<br />

ejemplo<br />

3<br />

4


Construcciones <strong>de</strong> lenguajes no in<strong>de</strong>pendientes <strong>de</strong>l contexto<br />

Declaración <strong>de</strong> i<strong>de</strong>ntificadores antes <strong>de</strong> su uso [Aho]<br />

• Se pue<strong>de</strong> <strong>de</strong>mostrar, no es objeto <strong>de</strong> este curso, que el lenguaje anterior no es<br />

in<strong>de</strong>pendiente <strong>de</strong>l contexto.<br />

• Cualquier lenguaje real que tenga esta característica necesitará reglas todavía más<br />

complicadas (el lenguaje anterior es una simplificación <strong>de</strong>l problema)<br />

• Por lo tanto, ninguno <strong>de</strong> los lenguajes <strong>de</strong> programación en los que haya que <strong>de</strong>clarar<br />

los i<strong>de</strong>ntificadores antes <strong>de</strong> su uso sean in<strong>de</strong>pendientes <strong>de</strong>l contexto.<br />

• Posibles soluciones:<br />

• Utilizar una arquitectura abstracta más potente que los autómatas a pila para<br />

gestionar los lenguajes<br />

• Intentar añadir a la gramática algún mecanismo que permita solucionar el<br />

problema:<br />

• Por ejemplo la tabla <strong>de</strong> símbolos.<br />

• Es la opción utilizada<br />

Construcciones <strong>de</strong> lenguajes no in<strong>de</strong>pendientes <strong>de</strong>l contexto<br />

Declaración <strong>de</strong> i<strong>de</strong>ntificadores antes <strong>de</strong> su uso [Aho]<br />

• Considérese el siguiente lenguaje<br />

L={a n b m c n d m |n≥1, m≥1}<br />

• Al analizar alguna <strong>de</strong> sus palabras:<br />

• aaabcccd<br />

• abbcdd<br />

• aaaaabbcccccdd<br />

• La coinci<strong>de</strong>ncia <strong>de</strong> número <strong>de</strong> repeticiones <strong>de</strong> la ca<strong>de</strong>na <strong>de</strong> aes y <strong>de</strong> ces y <strong>de</strong> la<br />

ca<strong>de</strong>na <strong>de</strong> bes y <strong>de</strong> <strong>de</strong>s se pue<strong>de</strong> interpretar como la comprobación en la llamada <strong>de</strong><br />

una subrutina <strong>de</strong> que se tiene el mismo número <strong>de</strong> parámetros que en la <strong>de</strong>claración<br />

• En aaabcccd el número <strong>de</strong> parámetros <strong>de</strong> la pareja aaa···ccc··· es 3 y el<br />

<strong>de</strong> la pareja ···b···d es 1.<br />

• En abbcdd el número <strong>de</strong> parámetros <strong>de</strong> la pareja a···c··· es 1 y el <strong>de</strong> la<br />

pareja ···bb···dd es 2.<br />

• En aaaabbcccccdd el número <strong>de</strong> parámetros <strong>de</strong> la pareja<br />

aaaaa···ccccc··· es 5<br />

• En cualquiera <strong>de</strong> las situaciones, la primera ca<strong>de</strong>na representa la <strong>de</strong>claración <strong>de</strong> la<br />

subrutina y la segunda una llamada<br />

• Observe que el lenguaje supone una simplificación bastante gran<strong>de</strong> <strong>de</strong> la situación<br />

real <strong>de</strong>scrita (ausencia <strong>de</strong> nombre <strong>de</strong> función y tipo <strong>de</strong> los argumentos)<br />

5<br />

6<br />

Construcciones <strong>de</strong> lenguajes no in<strong>de</strong>pendientes <strong>de</strong>l contexto<br />

Declaración <strong>de</strong> i<strong>de</strong>ntificadores antes <strong>de</strong> su uso [Aho]<br />

• Se pue<strong>de</strong> <strong>de</strong>mostrar, no es objeto <strong>de</strong> este curso, que el lenguaje anterior no es<br />

in<strong>de</strong>pendiente <strong>de</strong>l contexto.<br />

• Cualquier lenguaje real que tenga esta característica necesitará reglas todavía más<br />

complicadas (el lenguaje anterior es una simplificación <strong>de</strong>l problema)<br />

• Por lo tanto, ninguno <strong>de</strong> los lenguajes <strong>de</strong> programación en los que tenga subrutinas<br />

con argumentos (en todos ellos las llamadas tienen que proporcionar el mismo<br />

número <strong>de</strong> argumentos <strong>de</strong>clarados) es in<strong>de</strong>pendientes <strong>de</strong>l contexto.<br />

• Posibles soluciones:<br />

• Utilizar una arquitectura abstracta más potente que los autómatas a pila para<br />

gestionar los lenguajes<br />

• Intentar añadir a la gramática algún mecanismo que permita solucionar el<br />

problema:<br />

• Por ejemplo la tabla <strong>de</strong> símbolos.<br />

• Es la opción utilizada<br />

Construcciones <strong>de</strong> lenguajes in<strong>de</strong>pendientes <strong>de</strong>l contexto<br />

Construcciones <strong>de</strong> la programación estructurada:<br />

• Consi<strong>de</strong>re el siguiente fragmento <strong>de</strong> la gramática <strong>de</strong> ASPLE que tiene para este año<br />

7 : ::= <br />

8 : | ; <br />

22 : ::= if then fi<br />

23 : | if then else fi<br />

24 : ::= while do end<br />

25 : | repeat until <br />

• Estas reglas representan respectivamente las construcciones <strong>de</strong> control <strong>de</strong> flujo <strong>de</strong><br />

programa <strong>de</strong> la programación estructurada:<br />

• Bloque <strong>de</strong> sentencias<br />

• Sentencia <strong>de</strong> control <strong>de</strong> flujo condicional<br />

• Sentencia <strong>de</strong> control <strong>de</strong> flujo iterativa<br />

• La existencia <strong>de</strong> estas reglas muestra que son construcciones in<strong>de</strong>pendientes <strong>de</strong>l<br />

contexto<br />

7<br />

8


Construcciones <strong>de</strong> lenguajes in<strong>de</strong>pendientes <strong>de</strong>l contexto<br />

Conclusiones<br />

• Es suficiente el uso <strong>de</strong><br />

• Gramática in<strong>de</strong>pendiente <strong>de</strong>l contexto<br />

• Tabla <strong>de</strong> símbolos<br />

<strong>Analizador</strong> <strong>sintáctico</strong><br />

Conceptos: clases <strong>de</strong> estrategias <strong>de</strong> análisis <strong>sintáctico</strong><br />

• Segundo enfoque:<br />

• A partir <strong>de</strong> la ca<strong>de</strong>na <strong>de</strong> “tokens” <strong>de</strong>vueltos por el analizador morfológico, se<br />

comienza a leer intentando i<strong>de</strong>ntificar las partes <strong>de</strong>rechas <strong>de</strong> las reglas <strong>de</strong> la<br />

gramática.<br />

• Cuando esto ocurre se sustituye la ca<strong>de</strong>na <strong>de</strong> “tokens” por el no terminal <strong>de</strong> la<br />

parte izquierda <strong>de</strong> la regla y se continúa el mismo análisis teniendo en cuenta<br />

esta sustitución<br />

• Si en algún momento ninguna secuencia <strong>de</strong> la ca<strong>de</strong>na se correspon<strong>de</strong> con la<br />

parte <strong>de</strong>recha <strong>de</strong> ninguna regla tal vez se tenga que <strong>de</strong>shacer alguna elección<br />

para probar si con otra <strong>de</strong>cisión se consigue terminar el análisis<br />

• Cuando se han probado sistemáticamente todas las opciones sin po<strong>de</strong>r terminar<br />

el análisis se concluye que el programa es sintácticamente incorrecto.<br />

• La otra forma <strong>de</strong> terminar el análisis es cuando se consigue obtener por el<br />

mecanismo <strong>de</strong>scrito el axioma <strong>de</strong> la gramática.<br />

• En este último caso se concluye que el programa es sintácticamente correcto.<br />

9<br />

10<br />

<strong>Analizador</strong> <strong>sintáctico</strong><br />

Conceptos: clases <strong>de</strong> estrategias <strong>de</strong> análisis <strong>sintáctico</strong><br />

• Las diferentes técnicas para resolver el problema se pue<strong>de</strong>n agrupar <strong>de</strong> la siguiente<br />

forma:<br />

• Primer enfoque<br />

• A partir <strong>de</strong>l axioma <strong>de</strong> la gramática y el programa (transformado en secuencia<br />

<strong>de</strong> “tokens” por el analizador morfológico):<br />

• Probar con las distintas opciones <strong>de</strong> <strong>de</strong>rivación para cada no terminal que<br />

encontremos<br />

• Ir avanzando simultáneamente en el programa y en las hojas <strong>de</strong>l árbol <strong>de</strong><br />

<strong>de</strong>rivación que estamos construyendo, cuando haya coinci<strong>de</strong>ncia entre el<br />

terminal actual en el programa y el terminal <strong>de</strong> la hoja actual <strong>de</strong>l árbol.<br />

• Hasta que<br />

• O bien se recorra por completo la ca<strong>de</strong>na y coincida con las hojas <strong>de</strong>l árbol<br />

y, por tanto, el programa es sintácticamente correcto<br />

• O bien se intentan todas las opciones posibles para cada no terminal<br />

(incluido el axioma) y no se pue<strong>de</strong> completar el análisis por lo que el<br />

programa es sintácticamente incorrecto.<br />

<strong>Analizador</strong> <strong>sintáctico</strong><br />

Conceptos: clases <strong>de</strong> estrategias <strong>de</strong> análisis <strong>sintáctico</strong><br />

• Al primer enfoque, por la manera y el or<strong>de</strong>n en que proce<strong>de</strong> se le conoce también<br />

como análisis <strong>de</strong>scen<strong>de</strong>nte o “top down”.<br />

• Por la misma razón al segundo enfoque se le conoce también como análisis<br />

ascen<strong>de</strong>nte o “bottom up”.<br />

11<br />

12


Análisis <strong>sintáctico</strong> <strong>de</strong>scen<strong>de</strong>nte<br />

Introducción<br />

• El alumno pue<strong>de</strong> imaginar alguna solución a este problema con las herramientas que<br />

ha adquirido en otras materias <strong>de</strong> la carrera.<br />

• Se está ante una situación en la que se <strong>de</strong>be encontrar una <strong>de</strong>rivación (secuencia <strong>de</strong><br />

aplicación <strong>de</strong> reglas <strong>de</strong> la gramática en lugares concretos) que lleve <strong>de</strong>s<strong>de</strong> el no<br />

terminal inicial (el axioma) hasta la situación final (el programa proporcionado como<br />

entrada)<br />

• A<strong>de</strong>más, el número <strong>de</strong> posibles <strong>de</strong>rivaciones es muy gran<strong>de</strong> (potencialmente infinito)<br />

• Esta situación pue<strong>de</strong> a los problemas <strong>de</strong> búsqueda <strong>de</strong> un camino que llevara <strong>de</strong> una<br />

situación inicial a otra final atravesando un espacio enorme <strong>de</strong> posibles situaciones.<br />

• Ya se ha estudiado en asignaturas como IA la existencia <strong>de</strong> estrategias generales<br />

(para cualquier problema) <strong>de</strong> búsqueda ciega y sus propieda<strong>de</strong>s <strong>de</strong> las que se<br />

mencionan algunas:<br />

• Las dos estrategias básicas son en anchura y en profundidad<br />

• En anchura siempre se pue<strong>de</strong> conseguir encontrar la solución óptima (aquella<br />

para la que se requiere un menor número <strong>de</strong> pasos)<br />

• En profundidad, excepto árboles infinitos, se suele tener oportunidad <strong>de</strong><br />

encontrar alguna solución con menos esfuerzo<br />

Análisis <strong>sintáctico</strong> <strong>de</strong>scen<strong>de</strong>nte<br />

“Top-down” con vuelta atrás lenta: conceptos<br />

• Podríamos consi<strong>de</strong>rar el análisis <strong>sintáctico</strong> top-down con vuelta atrás lenta como un<br />

caso particular <strong>de</strong> búsqueda ciega en profundidad (se <strong>de</strong>sempate <strong>de</strong> izquierda a<br />

<strong>de</strong>recha)<br />

• El criterio para <strong>de</strong>cidir si una regla es aplicable en una posición es la coinci<strong>de</strong>ncia <strong>de</strong><br />

esa posición con el no terminal que está en la parte izquierda <strong>de</strong> la regla.<br />

• No podremos continuar por un camino cuando tengamos terminales que discrepen<br />

con el programa (po<strong>de</strong>mos suponer el or<strong>de</strong>n <strong>de</strong> recorrido natural <strong>de</strong>l programa (<strong>de</strong><br />

izquierda a <strong>de</strong>recha)<br />

• Habremos terminado el proceso en dos situaciones:<br />

• Si el árbol <strong>de</strong> <strong>de</strong>rivación “se cierra” porque se ha llegado a eliminar todos los no<br />

terminales y se obtiene la misma secuencia <strong>de</strong> terminales <strong>de</strong>l programa. En este<br />

caso se ha construido un árbol <strong>sintáctico</strong> para el programa que resulta ser<br />

correcto<br />

• Si no se ha podido “cerrar” el árbol <strong>de</strong> <strong>de</strong>rivación pero se ha probado todas las<br />

reglas en cada posición y no se pue<strong>de</strong> aplicar ninguna otra opción. En ese caso<br />

se ha <strong>de</strong>mostrado que el programa es sintácticamente incorrecto.<br />

• Describiremos esta técnica mediante los siguientes ejemplos<br />

13<br />

14<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

• Análisis <strong>sintáctico</strong> <strong>de</strong> la palabra aaabbb<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a<br />

S<br />

b<br />

15<br />

16


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

17<br />

18<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

S<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

a S b a S<br />

b<br />

19<br />

20


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

S<br />

a<br />

S<br />

b<br />

S<br />

S<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

a<br />

b<br />

a<br />

S<br />

b<br />

a b a b<br />

21<br />

22<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a<br />

S<br />

b<br />

S<br />

a<br />

S<br />

b<br />

S<br />

a<br />

S<br />

b<br />

a<br />

S<br />

ba<br />

S<br />

b<br />

a<br />

S<br />

b<br />

a<br />

b<br />

23<br />

24


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

• La siguiente palaba<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a<br />

a<br />

S<br />

S<br />

S<br />

b<br />

b<br />

aaabbb<br />

G=<br />

a<br />

a<br />

S<br />

S<br />

S<br />

b<br />

b<br />

aaabbb<br />

a<br />

b<br />

a<br />

b<br />

25<br />

26<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

• Análisis <strong>sintáctico</strong> <strong>de</strong> la palabra abbb<br />

G=<br />

a<br />

a<br />

S<br />

S<br />

S<br />

b<br />

b<br />

aaabbb<br />

G=<br />

S<br />

abbb<br />

a<br />

b<br />

ACEPTADA<br />

27<br />

28


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a<br />

S<br />

b<br />

a<br />

S<br />

b<br />

29<br />

30<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a<br />

S<br />

b<br />

S<br />

a S b a S<br />

b<br />

a<br />

b<br />

a<br />

S<br />

b<br />

31<br />

32


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a S b a S<br />

b<br />

a<br />

b<br />

a<br />

S<br />

b<br />

a b<br />

33<br />

34<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

a<br />

b<br />

a<br />

S<br />

b<br />

35<br />

36


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

• Análisis <strong>de</strong> la palabra i+--i<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

RECHAZADA<br />

37<br />

38<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

- E<br />

- E<br />

39<br />

40


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

i<br />

i<br />

- E<br />

41<br />

42<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

E +<br />

- E<br />

E<br />

i<br />

- E<br />

43<br />

44


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

E<br />

- E<br />

E<br />

i<br />

+<br />

E<br />

i<br />

- E<br />

45<br />

46<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

E<br />

- E<br />

E +<br />

i -<br />

E<br />

i - E<br />

E<br />

47<br />

48


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

E<br />

- E<br />

E +<br />

i -<br />

E<br />

i - E<br />

E<br />

- E<br />

49<br />

50<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

E<br />

- E<br />

E +<br />

i -<br />

E<br />

i - E<br />

E<br />

- E<br />

- E<br />

E<br />

- E<br />

- E<br />

- E<br />

51<br />

52


Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

G=<br />

E<br />

- E<br />

E<br />

E +<br />

i -<br />

E<br />

E E<br />

i - E<br />

E<br />

i+--i<br />

G=<br />

E<br />

- E<br />

E<br />

E +<br />

i -<br />

E<br />

E E<br />

i - E<br />

E<br />

i+--i<br />

- E E<br />

- E E<br />

i<br />

- E<br />

i<br />

- E<br />

ACEPTADA<br />

53<br />

54<br />

Análisis “top-down”, vuelta atrás lenta<br />

Ejemplos previos<br />

• Consi<strong>de</strong>rar el análisis para i++i<br />

G=<br />

E<br />

i+--i<br />

Análisis “top-down”, vuelta atrás lenta<br />

Conclusiones<br />

• Como el alumno habrá observado, la presencia en la gramática <strong>de</strong> reglas recursivas<br />

por la izquierda hace que este tipo <strong>de</strong> análisis encuentre bucles infinitos <strong>de</strong> los que<br />

no pue<strong>de</strong> salir.<br />

• En las siguientes transparencias se sacará provecho <strong>de</strong> este <strong>de</strong>scubrimiento y se<br />

presentará otras propieda<strong>de</strong>s <strong>de</strong> las gramáticas interesantes para la construcción <strong>de</strong><br />

analizadores <strong>sintáctico</strong>s <strong>de</strong>scen<strong>de</strong>ntes eficientes.<br />

55<br />

56


Propieda<strong>de</strong>s <strong>de</strong> las gramáticas para los analizadores <strong>de</strong>scen<strong>de</strong>ntes<br />

Propieda<strong>de</strong>s<br />

• Uno <strong>de</strong> los objetivos <strong>de</strong> este tema es <strong>de</strong>mostrar que se pue<strong>de</strong> construir fácilmente<br />

analizadores <strong>de</strong> tipo LL(1) (la entrada se lee <strong>de</strong>s<strong>de</strong> la izquierda – left – las<br />

<strong>de</strong>rivaciones en el árbol se hacen <strong>de</strong> izquierda – left – a <strong>de</strong>recha y se necesita<br />

conocer sólo 1 símbolo <strong>de</strong> la entrada por anticipado) si la gramática se pue<strong>de</strong><br />

expresar en forma a<strong>de</strong>cuada<br />

• Propieda<strong>de</strong>s necesarias para expresar la gramática <strong>de</strong> esa forma<br />

• Eliminar recursividad por la izquierda (por su relación suele consi<strong>de</strong>rarse un<br />

paso auxiliar para la cuarta propiedad)<br />

• Eliminar símbolos inaccesibles (por su relación suele consi<strong>de</strong>rarse un paso<br />

auxiliar para la cuarta propiedad)<br />

• Eliminar reglas <strong>de</strong>l tipo A→λ<br />

• Expresión <strong>de</strong> la gramática en forma normal <strong>de</strong> Greibach<br />

• Factorización por la izquierda (que es una condición necesaria para LL(1))<br />

G=<br />

E<br />

E<br />

+<br />

i -<br />

E<br />

Forma normal <strong>de</strong> Greibach<br />

Eliminación <strong>de</strong> recursividad a izquierdas: ejemplo previo<br />

• Analícese el siguiente ejemplo<br />

E<br />

- E<br />

i+--i<br />

E<br />

i E’<br />

+ E E’<br />

- E E’<br />

- E E’<br />

i E’<br />

G=<br />

i<br />

λ<br />

57<br />

58<br />

Forma normal <strong>de</strong> Greibach<br />

Eliminación <strong>de</strong> recursividad a izquierdas: conclusiones previas<br />

Forma normal . <strong>de</strong> Greibach<br />

Eliminación <strong>de</strong> recursividad a izquierdas: ejemplo 1<br />

• Del ejemplo anterior no parece po<strong>de</strong>r <strong>de</strong>ducirse i<strong>de</strong>a intuitiva alguna<br />

• Sin embargo la técnica se pue<strong>de</strong> generalizar<br />

G=<br />

A→Aα 1<br />

|...|Aα n<br />

|β 1<br />

|...|β m<br />

A→β 1<br />

X|...|β m<br />

X<br />

X→α 1<br />

X|...|α n<br />

X|λ<br />

G’=<br />

59<br />

60


Forma normal <strong>de</strong> Greibach<br />

Lema: eliminación <strong>de</strong> recursividad a izquierdas<br />

Forma normal <strong>de</strong> Greibach<br />

Observación: modificación <strong>de</strong> reglas y gramáticas equivalentes<br />

Toda gramática in<strong>de</strong>pendiente <strong>de</strong>l contexto pue<strong>de</strong> reducirse a otra equivalente sin<br />

reglas recursivas a izquierdas<br />

• Una regla recursiva a izquierdas tiene el siguiente aspecto<br />

A→Ax,,A ∈ Σ N<br />

∧ x ∈ (Σ T<br />

∪Σ N<br />

) *<br />

• El lema se <strong>de</strong>muestra <strong>de</strong> forma constructiva realizando para cada regla recursiva el<br />

siguiente tratamiento:<br />

• Sea < Σ T<br />

, Σ N<br />

, S, P > una gramática que tiene reglas recursivas <strong>de</strong> la siguiente<br />

forma:<br />

• A→Aα 1<br />

|...|Aα n<br />

|β 1<br />

|...|β m<br />

• Don<strong>de</strong> {β i<br />

} n i=1 representa todas las partes <strong>de</strong>rechas no recursivas<br />

• Se sustituye el subconjunto anterior <strong>de</strong> reglas por<br />

• A→β 1<br />

X|...|β m<br />

X<br />

• X→α 1<br />

X|...|α n<br />

X|λ<br />

Se pue<strong>de</strong> modificar una gramática sustituyendo una regla por el<br />

conjunto <strong>de</strong> reglas obtenido al sustituir en su parte <strong>de</strong>recha todas<br />

las apariciones <strong>de</strong> un no terminal por todas las partes <strong>de</strong>rechas <strong>de</strong><br />

ese no terminal. La gramática obtenida genera el mismo lenguaje<br />

que la <strong>de</strong> partida<br />

61<br />

62<br />

Forma normal <strong>de</strong> Greibach<br />

Observación: eliminación <strong>de</strong> reglas y gramáticas equivalentes, ejemplos<br />

Forma normal <strong>de</strong> Greibach<br />

Observación: eliminación <strong>de</strong> reglas y gramáticas equivalentes, ejemplos<br />

G’=<br />

F→i (i sustituye las F <strong>de</strong>)<br />

T→FT’<br />

G’=<br />

G’=<br />

T→iT’ (iT’ sustituye<br />

las T <strong>de</strong>) E→TE’<br />

G’=<br />

63<br />

64


Forma normal <strong>de</strong> Greibach<br />

Observación: eliminación <strong>de</strong> reglas y gramáticas equivalentes<br />

Forma normal <strong>de</strong> Greibach<br />

Observación: eliminación <strong>de</strong> reglas y gramáticas equivalentes, ejemplos<br />

Se pue<strong>de</strong>n eliminar reglas <strong>de</strong> una gramática siempre que se<br />

sustituya, la parte izquierda <strong>de</strong> la regla que se elimina por su parte<br />

<strong>de</strong>recha, en todas las apariciones en otras partes <strong>de</strong>rechas<br />

• Un caso <strong>de</strong> especial interés es la posibilidad <strong>de</strong> eliminar reglas <strong>de</strong> las llamadas<br />

lambda<br />

• Una regla lambda es <strong>de</strong> la forma<br />

A→λ,,A ∈ Σ N<br />

• Y se utiliza para borrar símbolos <strong>de</strong> una palabra<br />

G’=<br />

G’=<br />

65<br />

66<br />

Forma normal <strong>de</strong> Greibach<br />

Observación: eliminación <strong>de</strong> reglas y gramáticas equivalentes, ejemplos<br />

Forma normal <strong>de</strong> Greibach<br />

Observación: eliminación <strong>de</strong> reglas y gramáticas equivalentes, ejemplos<br />

• Comprobemos algunas <strong>de</strong>rivaciones<br />

G’=<br />

G’=<br />

G=<br />

E<br />

T<br />

E<br />

+<br />

E<br />

+ T<br />

T F<br />

F i<br />

i+i+i<br />

E<br />

i E’<br />

+ T E’<br />

G’=<br />

F<br />

i<br />

i+<br />

T<br />

i<br />

i<br />

67<br />

68


Forma normal <strong>de</strong> Greibach<br />

Observación: eliminación <strong>de</strong> reglas y gramáticas equivalentes, ejemplos<br />

• Comprobemos algunas <strong>de</strong>rivaciones<br />

Forma normal <strong>de</strong> Greibach<br />

Observación: eliminación <strong>de</strong> reglas y gramáticas equivalentes, ejemplos<br />

• Comprobemos algunas <strong>de</strong>rivaciones<br />

G=<br />

T<br />

E<br />

T<br />

*<br />

F<br />

i*i*i<br />

* F T’<br />

T * F i i* F T’<br />

E<br />

i T’<br />

G’=<br />

G=<br />

T<br />

F<br />

E<br />

*<br />

E<br />

+ T<br />

F F<br />

i i<br />

i*i+i<br />

E<br />

i T’ E’<br />

* F+<br />

T<br />

G’=<br />

F<br />

i<br />

i*<br />

F<br />

i<br />

i<br />

i<br />

i<br />

i<br />

69<br />

70<br />

Forma normal <strong>de</strong> Greibach<br />

Definición<br />

Forma normal <strong>de</strong> Greibach<br />

Enunciado teorema: existencia <strong>de</strong> forma normal <strong>de</strong> Greibach<br />

• Informalmente<br />

Se dice que una gramática in<strong>de</strong>pendiente <strong>de</strong>l contexto está en forma normal <strong>de</strong><br />

Greibach si y sólo si la parte <strong>de</strong>recha <strong>de</strong> todas las reglas empieza por un símbolo<br />

terminal seguido, opcionalmente, <strong>de</strong> no terminales<br />

Todo lenguaje in<strong>de</strong>pendiente <strong>de</strong>l contexto que no contenga la palabra vacía,<br />

pue<strong>de</strong> representarse mediante una gramática en forma normal <strong>de</strong> Greibach<br />

• Formalmente:<br />

< Σ T<br />

, Σ N<br />

, S, P > in<strong>de</strong>pendiente <strong>de</strong>l contexto está en forma normal <strong>de</strong> Greibach<br />

⇔(<strong>de</strong>f)<br />

∀ r∈P r=A→ax ,, a∈Σ T<br />

∧ x∈Σ * N<br />

71<br />

72


Forma normal <strong>de</strong> Greibach<br />

Demostración teorema: existencia <strong>de</strong> forma normal <strong>de</strong> Greibach<br />

• Se realizará una <strong>de</strong>mostración constructiva mostrando el algoritmo para la<br />

transformación<br />

• La transformación consiste en los siguientes pasos:<br />

1. Si el lenguaje contiene la palabra vacía, se aña<strong>de</strong> la regla (S es el axioma)<br />

S→λ<br />

2. Se elimina todas las reglas recursivas a izquierdas aplicando el lema <strong>de</strong>scrito<br />

previamente (se han visto ejemplos previamente)<br />

3. Se establece, entre los no terminales, la siguiente relación <strong>de</strong> or<strong>de</strong>n (parcial)<br />

<strong>de</strong>ducida <strong>de</strong>l estudio <strong>de</strong> las reglas <strong>de</strong> producción<br />

• Si no hay bucles<br />

A i<br />


Forma normal <strong>de</strong> Greibach<br />

Demostración teorema: existencia <strong>de</strong> forma normal <strong>de</strong> Greibach<br />

5. Se elimina las reglas <strong>de</strong> tipo 3 (comenzando por aquella cuya parte izquierda<br />

es la primera <strong>de</strong>l or<strong>de</strong>n parcial)<br />

• Grupo 3: Reglas <strong>de</strong> la forma<br />

A→Bx,, A,B∈Σ N<br />

, x∈Σ * ∧ B


Forma normal . <strong>de</strong> Greibach<br />

Ejemplo <strong>de</strong> paso 6<br />

Forma normal . <strong>de</strong> Greibach<br />

Ejemplo <strong>de</strong> paso 6<br />

G’=<br />

G’=<br />

• Reglas <strong>de</strong> tipo 2, con el or<strong>de</strong>n E


Forma normal <strong>de</strong> Greibach<br />

Demostración teorema: existencia <strong>de</strong> forma normal <strong>de</strong> Greibach<br />

8. Queda pendiente el tratamiento <strong>de</strong> las reglas lambda<br />

• La forma normal <strong>de</strong> Greibach prohíbe estas reglas excepto para el axioma<br />

(cuando el lenguaje incluye la palabra vacía)<br />

• Habría que eliminarlas utilizando el resultado que se estudió previamente<br />

• El objetivo <strong>de</strong> este curso es el paso <strong>de</strong> la gramática a una forma<br />

compatible para analizadores <strong>sintáctico</strong>s LL(1).<br />

• Aplicaremos el siguiente tratamiento práctico:<br />

• Analizar si las reglas lambda molestan para LL(1)<br />

• En caso afirmativo se eliminarán y, en el mejor <strong>de</strong> los casos, se<br />

terminará el proceso<br />

• Pue<strong>de</strong> ser difícil cumplir todas las condiciones para LL(1) al eliminar<br />

las reglas lambda.<br />

• Pue<strong>de</strong> tenerse la habilidad para pasar a la forma compatible LL(1)<br />

• Se pue<strong>de</strong> refinar la gramática <strong>de</strong> partida para expresarla <strong>de</strong> una<br />

manera que permita llegar hasta el final<br />

G=<br />

Forma normal . <strong>de</strong> Greibach<br />

Ejemplo 1<br />

1. El lenguaje no contiene la palabra vacía, no hay que hacer nada<br />

2. Se elimina todas las reglas recursivas a izquierdas<br />

A→Aα 1<br />

|...|Aα n<br />

|β 1<br />

|...|β m<br />

A→β 1<br />

X|...|β m<br />

X<br />

X→α 1<br />

X|...|α n<br />

X|λ<br />

G’=<br />

85<br />

86<br />

Forma normal . <strong>de</strong> Greibach<br />

Ejemplo 1<br />

3. Se establece, entre los no terminales, la siguiente relación <strong>de</strong> or<strong>de</strong>n (parcial), en<br />

este caso las nuevas reglas no aportan nada al or<strong>de</strong>n. En general se pue<strong>de</strong><br />

establecer el or<strong>de</strong>n con la gramática <strong>de</strong> partida e ir completándolo si proce<strong>de</strong><br />

G=<br />

• De las reglas anteriores se <strong>de</strong>duce el siguiente or<strong>de</strong>n<br />

• De E→E+T no se <strong>de</strong>duce nada<br />

• De E→T se <strong>de</strong>duce E


6. Se elimina las reglas <strong>de</strong> tipo 2<br />

Forma normal . <strong>de</strong> Greibach<br />

Ejemplo 1<br />

G’=<br />

• Reglas <strong>de</strong> tipo 2, con el or<strong>de</strong>n E


G’=<br />

Forma normal <strong>de</strong> Greibach<br />

Ejemplo1<br />

G’=<br />

Ajustes a la forma normal <strong>de</strong> Greibach para LL(1)<br />

Cambios en el paso 8<br />

• No todas las reglas lambda son perjudiciales para conseguir expresar la<br />

gramática <strong>de</strong> una manera compatible para LL(1)<br />

• Ya que el objetivo es utilizar LL(1) parece más a<strong>de</strong>cuado tratar sólo aquellas<br />

reglas lambda que realmente molesten<br />

• Se seguirá un tratamiento práctico basado en las siguientes reflexiones:<br />

• Cuando un no terminal tiene una regla lambda, como la siguiente<br />

X→λ<br />

• Podría generarse la siguiente situación:<br />

• Que el mismo no terminal tuviera otra parte <strong>de</strong>recha (todas comenzaran<br />

por un símbolo terminal porque todas son reglas <strong>de</strong> tipo 1)<br />

X→aα,, a∈Σ T<br />

∧ α∈Σ *<br />

Y se habría terminado el proceso<br />

93<br />

94<br />

Ajustes a la forma normal <strong>de</strong> Greibach para LL(1)<br />

Cambios en el paso 8<br />

• Imaginemos un árbol genérico <strong>sintáctico</strong> para una palabra concreta (se<br />

representa en rojo los terminales).<br />

Ajustes a la forma normal <strong>de</strong> Greibach para LL(1)<br />

Cambios en el paso 8<br />

• Imagínese que se intenta realizar análisis <strong>sintáctico</strong> <strong>de</strong>scen<strong>de</strong>nte para esa<br />

palabra, y que se está justamente en el símbolo previo a la a<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

X<br />

t i<br />

t j<br />

t l<br />

t k<br />

t b<br />

t a<br />

t s<br />

t n<br />

• Si sólo queda X como no terminal se pue<strong>de</strong> seguir el árbol:<br />

X→λ<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

X→aα<br />

aα<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

X<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

XY 1<br />

...Y m<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

at i<br />

...t n<br />

• Intuitivamente la eficiencia por la que LL(1) mejora al “top down” con vuelta<br />

lenta, se basa en la “in<strong>de</strong>xación” <strong>de</strong> las partes <strong>de</strong>rechas <strong>de</strong> cada no terminal<br />

mediante el próximo terminal que hay que analizar<br />

• Esto se ocurre si cada no terminal tiene sólo una parte <strong>de</strong>recha que<br />

comience con ese terminal.<br />

• Si en esta situación no existieran reglas lambda (X→λ) se continuaría el<br />

análisis <strong>de</strong>scen<strong>de</strong>nte sin incertidumbre:<br />

t i<br />

t j<br />

t l<br />

t k<br />

t b<br />

t a<br />

t s<br />

t n<br />

t i<br />

t j<br />

t l<br />

t k<br />

t b<br />

t a<br />

t s<br />

t n<br />

95<br />

96


Ajustes a la forma normal <strong>de</strong> Greibach para LL(1)<br />

Cambios en el paso 8<br />

• Ya que se tendría el siguiente conjunto <strong>de</strong> partes <strong>de</strong>rechas para X:<br />

X→ t 1<br />

β 1<br />

···<br />

Ajustes a la forma normal <strong>de</strong> Greibach para LL(1)<br />

Cambios en el paso 8<br />

X→ t i-1<br />

β i-1<br />

X→ aα<br />

X→ t i+1<br />

β i+1<br />

···<br />

X→ t k<br />

β k<br />

,,{t 1<br />

,...,t i-1<br />

,a,t i+1<br />

,...,t k<br />

}⊆Σ T<br />

∧t p<br />

≠t q<br />

≠a ∀∈p,q∈{1,...,i-1,i+1,...k}<br />

∧{β 1<br />

,...,β i-1<br />

,a,β i+1<br />

,...,β k<br />

}⊆Σ N<br />

*<br />

• Sólo se podría elegir la resaltada y se continuaría el análisis:<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

aα<br />

Y 1<br />

...Y m<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

at i<br />

...t n<br />

• ¿Cuándo son problemáticas las reglas lambda?<br />

• Cuando originan incertidumbre sobre cuál es la siguiente regla que<br />

se tiene que aplicar<br />

97<br />

98<br />

Ajustes a la forma normal <strong>de</strong> Greibach para LL(1)<br />

Cambios en el paso 8<br />

• ¿Qué pasaría si existieran a la vez X→aα, X→λ y Y 1<br />

→aγ 1<br />

?<br />

• Se confun<strong>de</strong>n las a’s <strong>de</strong>rivadas por X (X→aα) y por Y 1<br />

, que sigue a X<br />

Borrado <strong>de</strong> X Y 1<br />

→aγ 1<br />

Ajustes a la forma normal <strong>de</strong> Greibach para LL(1)<br />

Cambios en el paso 8<br />

• Así que necesitaremos conocer<br />

• Cuál es el primer terminal que <strong>de</strong>riva X (en nuestro caso a)<br />

• Cuál es el primer terminal que es <strong>de</strong>rivado por lo que sigue a X y,<br />

por lo tanto, ¿quién sigue a X?<br />

• Las siguientes gráficas muestran los dos casos posibles<br />

Y 1<br />

→aγ 1<br />

100<br />

XY 1<br />

...Y m<br />

λ<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

at i<br />

...t n<br />

X→λ<br />

XY 1<br />

...Y m<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

at i<br />

...t n<br />

Y 1<br />

...Y m<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

aγ 1<br />

X→aα<br />

Y 2<br />

...Y m<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

at i<br />

...t n<br />

Y 1<br />

...Y m<br />

B→σXY 1<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

X Y 1<br />

...Y m<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

at i<br />

...t n<br />

σ<br />

B<br />

λ<br />

V→τIWω<br />

W→Y 1<br />

...Y m<br />

I→ξX<br />

τ IW<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

X Y 1<br />

...Y m<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

at i<br />

...t n<br />

ξ<br />

λ<br />

V<br />

ω<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

at i<br />

...t n<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

aα<br />

t 1<br />

t 2<br />

t 3<br />

t 4<br />

t 5<br />

t 6<br />

t 7<br />

t 8<br />

at i<br />

...t n<br />

99


Ajustes a la forma normal <strong>de</strong> Greibach para LL(1)<br />

Cambios en el paso 8<br />

• X es seguido por el primer símbolo <strong>de</strong>l resto (a partir <strong>de</strong> él) <strong>de</strong> las partes<br />

<strong>de</strong>rechas don<strong>de</strong> aparece (en este caso, sólo se tiene B→σXY 1<br />

y es seguido<br />

por Y 1<br />

)<br />

• Si es el último no terminal <strong>de</strong> la parte <strong>de</strong>recha, se mirará quién sigue a su<br />

padre (en este caso I→ξX, y si I sólo aparece en V→τIWω se estudiará el<br />

primer terminal que <strong>de</strong>riva <strong>de</strong> W)<br />

• Por tanto, si el primer terminal que <strong>de</strong>riva <strong>de</strong> Y 1<br />

no es a, la regla lambda no<br />

da problemas.<br />

• En otro caso sí los da y se intentará eliminarla.<br />

Forma normal <strong>de</strong> Greibach para LL(1)<br />

Nuevo final <strong>de</strong>l ejemplo 1<br />

8. Si sólo se quiere utilizar la gramática para generar un analizador <strong>sintáctico</strong><br />

<strong>de</strong>scen<strong>de</strong>nte con la técnica LL(1) tendremos que estudiar si molestan las reglas λ<br />

G’=<br />

¿Quién sigue a E’?<br />

Consultemos las partes <strong>de</strong>rechas <strong>de</strong> las reglas<br />

buscando E’<br />

• Comencemos por la primera regla lambda<br />

101<br />

102<br />

Forma normal <strong>de</strong> Greibach para LL(1)<br />

Forma normal <strong>de</strong> Greibach para LL(1)<br />

Nuevo final <strong>de</strong>l ejemplo 1<br />

Nuevo final <strong>de</strong>l ejemplo 1<br />

8. (cont.)<br />

8. (cont.)<br />

G’=<br />

¿Quién sigue a E’?<br />

Consultemos las partes <strong>de</strong>rechas <strong>de</strong> las reglas<br />

buscando E’.<br />

En las dos reglas aparece como último símbolo <strong>de</strong> la<br />

parte <strong>de</strong>recha.<br />

A E’le seguirá quien siga a las partes izquierdas <strong>de</strong><br />

esas dos reglas:<br />

G’=<br />

¿Quién sigue a E’?<br />

Consultemos las partes <strong>de</strong>rechas <strong>de</strong> las reglas<br />

buscando E’.<br />

En las dos reglas aparece como último símbolo <strong>de</strong> la<br />

parte <strong>de</strong>recha.<br />

A E’le seguirá quien siga a las partes izquierdas <strong>de</strong><br />

esas dos reglas:<br />

• E<br />

• E’<br />

En general, pue<strong>de</strong> terminarse el estudio cuando se<br />

llega:<br />

• Al axioma<br />

• Al mismo símbolo que se está estudiando<br />

• Po<strong>de</strong>mos concluir que la primera regla lambda no molesta<br />

103<br />

104


Forma normal <strong>de</strong> Greibach para LL(1)<br />

Forma normal <strong>de</strong> Greibach para LL(1)<br />

Nuevo final <strong>de</strong>l ejemplo 1<br />

Nuevo final <strong>de</strong>l ejemplo 1<br />

8. (cont.)<br />

8. (cont.)<br />

G’=<br />

¿Quién sigue a T’?<br />

Consultemos las partes <strong>de</strong>rechas <strong>de</strong> las reglas<br />

buscando T’.<br />

G’=<br />

¿Quién sigue a T’?<br />

Consultemos las partes <strong>de</strong>rechas <strong>de</strong> las reglas<br />

buscando T’.<br />

En una regla aparece seguido por E’.<br />

En dos reglas aparece como último símbolo <strong>de</strong> la<br />

parte <strong>de</strong>recha.<br />

A T’le seguirá quien siga a las partes izquierdas <strong>de</strong><br />

esas dos reglas:<br />

• Continuemos con la segunda regla lambda<br />

105<br />

106<br />

Forma normal <strong>de</strong> Greibach para LL(1)<br />

Forma normal <strong>de</strong> Greibach para LL(1)<br />

Nuevo final <strong>de</strong>l ejemplo 1<br />

Nuevo final <strong>de</strong>l ejemplo 1<br />

8. (cont.)<br />

8. (cont.)<br />

G’=<br />

¿Quién sigue a T’?<br />

Consultemos las partes <strong>de</strong>rechas <strong>de</strong> las reglas<br />

buscando T’.<br />

En una regla aparece seguido por E’.<br />

En dos reglas aparece como último símbolo <strong>de</strong> la<br />

parte <strong>de</strong>recha.<br />

A T’le seguirá quien siga a las partes izquierdas <strong>de</strong><br />

esas dos reglas:<br />

• T’<br />

• T<br />

Pue<strong>de</strong> terminarse el estudio cuando se llega al<br />

mismo símbolo<br />

G’=<br />

¿Quién sigue a T?<br />

Consultemos las partes <strong>de</strong>rechas <strong>de</strong> las reglas<br />

buscando T.<br />

• Continuemos con los símbolos no terminales que siguen a T<br />

107<br />

108


Forma normal <strong>de</strong> Greibach para LL(1)<br />

Forma normal <strong>de</strong> Greibach para LL(1)<br />

Nuevo final <strong>de</strong>l ejemplo 1<br />

Nuevo final <strong>de</strong>l ejemplo 1<br />

8. (cont.)<br />

8. (cont.)<br />

G’=<br />

¿Quién sigue a T?<br />

Consultemos las partes <strong>de</strong>rechas <strong>de</strong> las reglas<br />

buscando T.<br />

En la regla aparece seguido por E’.<br />

Recapitulando sólo tenemos que estudiar E’<br />

G’=<br />

¿Quién sigue a T?<br />

Consultemos las partes <strong>de</strong>rechas <strong>de</strong> las reglas<br />

buscando T.<br />

En la regla aparece seguido por E’.<br />

Recapitulando sólo tenemos que estudiar E’<br />

Comprobemos<br />

• El primer terminal <strong>de</strong>rivado por T’ es *.<br />

• El primer terminal <strong>de</strong>rivado por E’es +.<br />

• Como los terminales son distintos (* y +) po<strong>de</strong>mos concluir que la segunda regla<br />

lambda tampoco molesta<br />

109<br />

110<br />

Forma normal <strong>de</strong> . Greibach / LL(1)<br />

Ejemplo 2<br />

• Obtener, si es posible, la expresión a<strong>de</strong>cuada para LL(1) <strong>de</strong> la siguiente gramática<br />

utilizando como ayuda la forma normal <strong>de</strong> Greibach<br />

G 2<br />

=<br />

Forma normal <strong>de</strong> . Greibach/ LL(1)<br />

Ejemplo 2<br />

1. El lenguaje no contiene la palabra vacía, no hay que hacer nada<br />

2. No hay reglas recursivas a izquierdas, no hay que hacer nada<br />

3. Se establece, entre los no terminales, el or<strong>de</strong>n (parcial)<br />

G 2<br />

=<br />

• De las reglas anteriores se pue<strong>de</strong> <strong>de</strong>ducir los dos siguientes ór<strong>de</strong>nes<br />

• De A→Ba se <strong>de</strong>duce A


Forma normal <strong>de</strong> . Greibach / LL(1)<br />

4. Se clasifica las reglas en tres grupos<br />

Ejemplo 2: opción 1 B


Forma normal <strong>de</strong> . Greibach / LL(1)<br />

Ejemplo 2: opción 1 B


Forma normal <strong>de</strong> . Greibach / LL(1)<br />

Ejemplo 2: opción 2 A


Forma normal <strong>de</strong> . Greibach / LL(1)<br />

Ejemplo 2: opción 2 A


8. (cont.)<br />

Forma normal <strong>de</strong> Greibach / LL(1)<br />

Ejemplo 2: opción 2 A


LL(1)<br />

Conversión <strong>de</strong>s<strong>de</strong> forma normal <strong>de</strong> Greibach a LL(1)<br />

• El nuevo no terminal tendrá tantas partes <strong>de</strong>rechas como diferentes “partes<br />

no comunes” haya (en este caso K→V|W).<br />

G 2<br />

=<br />

LL(1)<br />

Conversión <strong>de</strong>s<strong>de</strong> forma normal <strong>de</strong> Greibach a LL(1)<br />

• Hay que tener la precaución <strong>de</strong> <strong>de</strong>jar las reglas en “forma normal” a<strong>de</strong>cuada:<br />

• En este caso no es complicado ya que se pue<strong>de</strong> <strong>de</strong>rivar los primeros no<br />

terminales hasta llegar a un terminal<br />

• En este caso basta aplicar una vez las reglas <strong>de</strong> V (V→bX|cY) y <strong>de</strong> W<br />

(W→dZ|eT)...<br />

G 2<br />

=<br />

133<br />

134<br />

LL(1)<br />

Conversión <strong>de</strong>s<strong>de</strong> forma normal <strong>de</strong> Greibach a LL(1)<br />

• ... y eliminar los símbolos que, parece, que quedan inaccesibles (V y W)<br />

G 2<br />

=<br />

Análisis “top-down” selectivo<br />

Concepto<br />

• También se llama “sin vuelta atrás”, en oposición a la técnica <strong>de</strong>scrita al principio<br />

<strong>de</strong>l tema<br />

• También se llama “<strong>de</strong>scenso recursivo” por la técnica <strong>de</strong> paso automático <strong>de</strong> la<br />

gramática LL(1) al analizador<br />

• Intuitivamente, la razón <strong>de</strong> su eficiencia resi<strong>de</strong> en que las partes <strong>de</strong>rechas <strong>de</strong><br />

cada no terminal pue<strong>de</strong>n consi<strong>de</strong>rarse “in<strong>de</strong>xadas” por el siguiente terminal<br />

• De hecho (consúltese la bibliografía) con LL(1) se pue<strong>de</strong> construir una tabla <strong>de</strong><br />

doble entrada (no terminales / terminales ) en la que, cada celda, está ocupada<br />

solamente por una regla que es la única opción que se pue<strong>de</strong> aplicar cuando en<br />

el “árbol <strong>sintáctico</strong>” corresponda tratar el no terminal y en el recorrido <strong>de</strong>l<br />

programa toque tratar el terminal.<br />

135<br />

136


Análisis “top-down” selectivo<br />

Paso automático <strong>de</strong> la gramática LL(1) al analizador<br />

• Según el proceso <strong>de</strong>scrito, cuando lleguemos a LL(1) tendremos estos dos tipos<br />

<strong>de</strong> reglas:<br />

• Reglas con opción λ:<br />

U→xX 1<br />

X 2<br />

...X n<br />

|yY 1<br />

Y 2<br />

...Y m<br />

|...|zZ 1<br />

...Z p<br />

|λ<br />

• Reglas sin opción λ:<br />

Análisis “top-down” selectivo<br />

Paso automático <strong>de</strong> la gramática LL(1) al analizador: reglas con λ<br />

• Se generará la siguiente función C<br />

int U(char * ca<strong>de</strong>na, int i)<br />

{<br />

if (i < 0) return i;<br />

/* Aquí propaga errores<br />

anteriores */<br />

switch (ca<strong>de</strong>na[i]) {<br />

case x;<br />

i++;<br />

i=X1(ca<strong>de</strong>na, i);<br />

i=X2(ca<strong>de</strong>na, i);<br />

···<br />

i=Xn(ca<strong>de</strong>na, i);<br />

break;<br />

case y:<br />

i++;<br />

i=Y1(ca<strong>de</strong>na, i);<br />

i=Y2(ca<strong>de</strong>na, i);<br />

···<br />

i=Ym(ca<strong>de</strong>na, i);<br />

break;<br />

case z:<br />

i++;<br />

i=Z1(ca<strong>de</strong>na, i);<br />

i=Z2(ca<strong>de</strong>na, i);<br />

···<br />

i=Zp(ca<strong>de</strong>na, i);<br />

break;<br />

}<br />

return i;<br />

}<br />

U→xX 1<br />

X 2<br />

...X n<br />

|yY 1<br />

Y 2<br />

...Y m<br />

|...|zZ 1<br />

...Z p<br />

138<br />

···<br />

137<br />

Análisis “top-down” selectivo<br />

Paso automático <strong>de</strong> la gramática LL(1) al analizador: reglas sin λ<br />

• Se generará la siguiente función C<br />

Análisis “top-down” selectivo<br />

Ejemplo completo<br />

• Se parte <strong>de</strong> la siguiente gramática in<strong>de</strong>pendiente <strong>de</strong>l contexto<br />

int U(char * ca<strong>de</strong>na, int i)<br />

{<br />

if (i < 0) return i;<br />

/* Aquí propaga errores<br />

anteriores */<br />

switch (ca<strong>de</strong>na[i]) {<br />

case x;<br />

i++;<br />

i=X1(ca<strong>de</strong>na, i);<br />

i=X2(ca<strong>de</strong>na, i);<br />

···<br />

i=Xn(ca<strong>de</strong>na, i);<br />

break;<br />

case y:<br />

i++;<br />

i=Y1(ca<strong>de</strong>na, i);<br />

i=Y2(ca<strong>de</strong>na, i);<br />

···<br />

i=Ym(ca<strong>de</strong>na, i);<br />

break;<br />

···<br />

case z:<br />

i++;<br />

i=Z1(ca<strong>de</strong>na, i);<br />

i=Z2(ca<strong>de</strong>na, i);<br />

···<br />

i=Zp(ca<strong>de</strong>na, i);<br />

break;<br />

/* El fin <strong>de</strong> ca<strong>de</strong>na va a<br />

<strong>de</strong>fault */<br />

<strong>de</strong>fault:<br />

return –n;<br />

/* El error <strong>de</strong>be ser distinto<br />

para cada regla */<br />

}<br />

return i;<br />

}<br />

G 3<br />

=<br />

139<br />

140


Análisis “top-down” selectivo<br />

Ejemplo completo<br />

• El alumno pue<strong>de</strong> comprobar que se obtiene la siguiente expresión en forma<br />

normal <strong>de</strong> Greibach<br />

• Y la siguiente expresión LL(1)<br />

Análisis “top-down” selectivo<br />

Ejemplo completo<br />

G 3<br />

=<br />

G 3<br />

=<br />

141<br />

142<br />

Análisis “top-down” selectivo<br />

Ejemplo completo<br />

• Y se pue<strong>de</strong> escribir el siguiente analizador siguiendo el esquema <strong>de</strong>scrito<br />

Análisis “top-down” selectivo<br />

Ejemplo completo<br />

• Y se pue<strong>de</strong> escribir el siguiente analizador siguiendo el esquema <strong>de</strong>scrito<br />

int E(char * ca<strong>de</strong>na, int i)<br />

{<br />

if (i < 0) return i;<br />

/* Aquí propaga errores<br />

anteriores */<br />

switch (ca<strong>de</strong>na[i]) {<br />

case ’i’:<br />

i++;<br />

i=V(ca<strong>de</strong>na, i);<br />

break;<br />

case ‘(‘:<br />

i++;<br />

i=E(ca<strong>de</strong>na, i);<br />

i=C(ca<strong>de</strong>na, i);<br />

i=V(ca<strong>de</strong>na, i);<br />

break;<br />

<strong>de</strong>fault: return –1;/*no λ*/<br />

}<br />

return i;<br />

}<br />

int V(char * ca<strong>de</strong>na, int i)<br />

{<br />

if (i < 0) return i;<br />

/* Aquí propaga errores<br />

anteriores */<br />

switch (ca<strong>de</strong>na[i]) {<br />

case ’*’:<br />

case ’/’:<br />

i++;<br />

i=T(ca<strong>de</strong>na, i);<br />

i=X(ca<strong>de</strong>na, i);<br />

break;<br />

case ‘+‘:<br />

case ‘-‘:<br />

i++;<br />

i=E(ca<strong>de</strong>na, i);<br />

break; /* λ */<br />

}<br />

return i;<br />

}<br />

int X(char * ca<strong>de</strong>na, int i)<br />

{<br />

if (i < 0) return i;<br />

/* Aquí propaga errores<br />

anteriores */<br />

switch (ca<strong>de</strong>na[i]) {<br />

case ’+’:<br />

case ’-’:<br />

i++;<br />

i=E(ca<strong>de</strong>na, i);<br />

break; /* λ */<br />

}<br />

return i;<br />

}<br />

int T(char * ca<strong>de</strong>na, int i)<br />

{<br />

if (i < 0) return i;<br />

/* Aquí propaga errores<br />

anteriores */<br />

switch (ca<strong>de</strong>na[i]) {<br />

case ’i’:<br />

i++;<br />

i=U(ca<strong>de</strong>na, i);<br />

break;<br />

case ‘(‘:<br />

i++;<br />

i=E(ca<strong>de</strong>na, i);<br />

i=C(ca<strong>de</strong>na, i);<br />

i=U(ca<strong>de</strong>na, i);<br />

break;<br />

<strong>de</strong>fault: return –2;/*no λ*/<br />

}<br />

return i;<br />

}<br />

143<br />

144


Análisis “top-down” selectivo<br />

Ejemplo completo<br />

• Y se pue<strong>de</strong> escribir el siguiente analizador siguiendo el esquema <strong>de</strong>scrito<br />

Análisis “top-down” selectivo<br />

Ejemplo completo<br />

• Y se pue<strong>de</strong> escribir el siguiente analizador siguiendo el esquema <strong>de</strong>scrito<br />

int U(char * ca<strong>de</strong>na, int i)<br />

{<br />

if (i < 0) return i;<br />

/* Aquí propaga errores<br />

anteriores */<br />

switch (ca<strong>de</strong>na[i]) {<br />

case ’*’:<br />

case ’/’:<br />

i++;<br />

i=T(ca<strong>de</strong>na, i);<br />

break; /* λ */<br />

}<br />

return i;<br />

}<br />

int F(char * ca<strong>de</strong>na, int i)<br />

{<br />

if (i < 0) return i;<br />

/* Aquí propaga errores<br />

anteriores */<br />

switch (ca<strong>de</strong>na[i]) {<br />

case ’i’:<br />

i++;<br />

break;<br />

case ‘(‘:<br />

i++;<br />

i=E(ca<strong>de</strong>na, i);<br />

i=C(ca<strong>de</strong>na, i);<br />

break;<br />

<strong>de</strong>fault: return –3;/*no λ*/<br />

}<br />

return i;<br />

}<br />

int C(char * ca<strong>de</strong>na, int i)<br />

{<br />

if (i < 0) return i;<br />

/* Aquí propaga errores<br />

anteriores */<br />

switch (ca<strong>de</strong>na[i]) {<br />

case ’)’:<br />

i++;<br />

break;<br />

<strong>de</strong>fault: return –4;/*no λ*/<br />

}<br />

return i;<br />

}<br />

145<br />

146<br />

Análisis “top-down” selectivo<br />

Análisis “top-down” selectivo<br />

Ejemplo completo<br />

Ejemplo completo<br />

• La ca<strong>de</strong>na x se analiza con la llamada<br />

• El siguiente no reconoce la ca<strong>de</strong>na<br />

axioma( x, 0);<br />

• Si el retorno es la longitud <strong>de</strong> la ca<strong>de</strong>na, se ha reconocido, en otro caso (retorno<br />

negativo) el valor indica la regla que i<strong>de</strong>ntificó el error<br />

• Po<strong>de</strong>mos mostrar los siguientes ejemplos <strong>de</strong> ejecución:<br />

E(“i + i * i”, 0)<br />

0[1]: E( “I + I * I”, 0)<br />

1[1]: V( “I + I * I”, 1)<br />

2[1]: E( “I + I * I”, 2)<br />

3[1]: V( “I + I * I”, 3)<br />

4[1]: T( “I + I * I”, 4)<br />

5[1]: U( “I + I * I”, 5)<br />

5[1]: returned 5<br />

4[1]: returned 5<br />

4[1]: X( “I + I * I”, 5)<br />

4[1]: returned 5<br />

3[1]: returned 5<br />

2[1]: returned 5<br />

1[1]: returned 5<br />

0[1]: returned 5<br />

5<br />

147<br />

E(“i + i *”, 0)<br />

0[1]: E( “I + I *”, 0)<br />

1[1]: V( “I + I *”, 1)<br />

2[1]: E( “I + I *”, 2)<br />

3[1]: V( “I + I *”, 3)<br />

4[1]: T( “I + I *”, 4)<br />

4[1]: returned -2<br />

4[1]: X( “I + I *”, -2)<br />

4[1]: returned -2<br />

3[1]: returned -2<br />

2[1]: returned -2<br />

1[1]: returned -2<br />

0[1]: returned -2<br />

-2<br />

148


Análisis <strong>sintáctico</strong><br />

Bibliografía<br />

[Alf] “Teoría <strong>de</strong> Autómatas y lenguajes formales” M. Alfonseca y otros<br />

[Hop] “Introducción a la teoría <strong>de</strong> autómatas, lenguajes y computación” Hopcroft, J.;<br />

Motwani, R.; Ullman, J.<br />

[Aho] “Compiladores. Principios, técnicas y herramientas” A. V. Aho; R. Sefthi; J. D.<br />

Ullman<br />

149

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!