Descargar la presentación
La descarga está en progreso. Por favor, espere
1
Lenguajes de libre contexto
2
Gramáticas Una gramática es otra forma de describir un lenguaje.
Ejemplo: O S P S A T P V A el A un T niño T perro V corre V camina
3
Gramáticas O S P Una derivación de "un niño corre":
S A T P V A el A un T niño T perro V corre V camina Una derivación de "un niño corre": O S P A T P A T V un T V un T corre un niño corre
4
Gramáticas O S P Lenguaje descrito por esta gramática:
S A T P V A el A un T niño T perro V corre V camina Lenguaje descrito por esta gramática: L={"el niño corre", "el niño camina", "un niño corre", "un niño camina", "el perro corre, el perro camina", "un perro corre", "un perro camina"}
5
T niño Gramáticas Variable o "no-terminal" Regla de producción
6
Gramáticas Otro ejemplo: Lenguaje: Algunas derivaciones:
Este formalismo permite describir algunos lenguajes que no son regulares.
7
Gramática: forma general
Una gramática es una tupla G=(V,T,S,P) donde T es un conjunto finito de símbolos terminales (es el alfabeto en que estarán escritas las palabras). V es un conjunto finito de variables (símbolos que no aparecerán en la palabra final). S V es la variable de inicio. P es un conjunto finito de reglas de producción de la forma pq, donde p es de la forma (V+T)*V(V+T)* y q es de la forma (V+T)*.
8
Derivaciones T={a,b} V={S} S=S P={SaSb, S}
Una derivación es la obtención de una palabra u a partir de una palabra v, ambas pertenecientes a (V+T)*, aplicando una regla de producción: Si la regla es pq, será aplicable sólo si p está incluida en u, o sea, u=xpy. El resultado será v=xqy. Escribimos uv.
9
Derivaciones Definimos * como la cerradura transitiva de .
Es decir, u * v ssi u1,u2,...,uk tales que u u1 u2 ... uk v Además definimos que u * u para todo u. Definimos el lenguaje descrito por la gramática como el conjunto de todas las palabras de terminales que pueden derivarse a partir de S: L(G) = { wT*: S * w } A veces cuando no haya confusión posible, anotaremos * simplemente como
10
Convención sobre notación
Notación: se suelen usar en este contexto Letras minúsculas del comienzo del alfabeto para los terminales. Letras minúsculas del final del alfabeto para las palabras (de terminales, o de terminales mezclados con variables). Letras mayúsculas para las variables. Cuando por algún motivo esto pueda inducir a confusión, entonces se usan con corchetes: S. Casos típicos: cuando es inevitable usar mayúsculas en los terminales, o cuando una variable tiene un nombre natural (ejemplo: predicado).
11
Gramáticas de libre contexto
El formalismo general de gramáticas es demasiado poderoso : puede describir lenguajes más complejos que los que nos interesan (por ahora). Estudiaremos en este capítulo las gramáticas de libre contexto y sus lenguajes asociados (lenguajes de libre contexto). Nota: también lo traducen como “de contexto libre”, “independientes del contexto”, etc, etc.
12
Gramáticas de libre contexto
Def.: una gramática se dice de libre contexto (GLC) ssi en toda regla de producción pq, se tiene que pV. Es decir, las reglas son de la forma X w con w(V+T)*. ¿Por qué interesan? Los lenguajes de programación, y (salvo algunas construcciones particulares) los lenguajes naturales, son de libre contexto!!
13
(Gramáticas regulares
Un caso aún más particular son las GLC en que se pide que todas las reglas de producción sean de las formas SaT ó Sa Se les llama gramáticas lineales por la derecha. Análogamente se definen las gramáticas lineales por la izquierda, que tienen reglas de la forma STa, ó bien Sa. Una gramática es regular si es lineal por la derecha, o es lineal por la izquierda.
14
Gramáticas regulares L es un lenguaje regular ssi L=L(G) para una gramática regular G. Nota: en la clase el estado C estaba anónimo, y las producciones que incluyen C estaban resumidas en una sola, AaaB. Lo cambio aquí para respetar el formato definido en la transparencia previa. Ir derivando la palabra corresponde a ir cambiando de estado interno (la variable), y escribiendo.
15
Gramáticas regulares)
Ojo: para que G sea regular debe ser lineal por la derecha o por la izquierda, pero no puede mezclar las dos formas. Si las mezcla, puede que lo que sale ya no sea regular: SaT TSb S genera {anbn, n0}, que es el clásico ejemplo de lenguaje no regular.
16
GLC, ejemplos Volvamos al caso general de GLC. Otro ejemplo:
¿Lenguaje? {anbn+1, n0} Una notación conveniente: cuando el lado izquierdo es el mismo, agrupamos varias reglas de producción en una sola línea mediante “|”:
17
GLC, ejemplos Más ejemplos: donde T={(,)}, V={S}. ¿Lenguaje?
S (S) () S (S) (SS) ((S)S) ((S)(S)) (()(S)) (()()) da el lenguaje de los paréntesis bien balanceados.
18
GLC, ejemplos Más ejemplos: donde T={a,b}, V={S}. ¿Lenguaje?
S aSa abSba abbSbba abbbba es el lenguaje de los palíndromes de largo par: L={ w=u uR, u{a,b}*} Ejercicio: modificar la gramática para que también genere palíndromes de largo impar (p.ej., aba).
19
GLC, ejercicios Ejercicios:
¿Qué lenguajes describen las siguientes gramáticas? G1: S XaaX X aX | bX | G2: S XY X aX | bX | a Y Ya | Yb | a Escriba una gramática que describa el lenguaje de todas las expresiones regulares válidas sobre el alfabeto {a,b}.
20
GLC "prototípicas" Algunas formas típicas de LLC (lenguajes de libre contexto): Recursivos Por partes Anidados Algunos ejemplos para tener en cuenta (como “principios de diseño”): Recursivo: {anbn, n0} Lo generamos con algo de la forma SaSb El de los palíndromes es análogo. Idea: hay un "surtidor" al medio que emite letras de manera simétrica.
21
GLC "prototípicas" Por partes: L={anbnambm, n0, m0}
Lo generamos con algo de la forma SXY Luego a partir de X e Y generamos las dos partes (aprovechando que no tienen relación). En este caso L=L1L1, con L1={anbn, n0}, de modo que X e Y pueden ser el mismo: SXX XaXb |
22
GLC "prototípicas" Anidados: L={anbmambn, n0, m0}
Aquí las “partes independientes” son por un lado anbn y por otro lado bmam, que está dentro de la anterior. Generamos primero lo exterior, luego lo interior. En este caso particular, tanto lo interior como lo exterior es del tipo recursivo. SaSb | X XbXa |
23
GLC, un ejemplo más complejo
L={w{0,1}*: w tiene dos bloques de 0’s del mismo tamaño}. Permitidos: 01011, , No permitidos: , 01111 D Cantidad de 0’s: la misma a cada lado al menos uno inicio parte central final A B C A: , ó termina en 1 C: , ó comienza con 1
24
GLC, un ejemplo más complejo
De modo que descomponemos por partes, y luego aplicamos recursividad en B. inicio parte central final A B C D Cantidad de 0’s: la misma a cada lado al menos uno A → | U1 U → 0U | 1U | C → | 1U D → 1U1 | 1 S → ABC B → 0B0 | 0D0
25
Derivaciones y árboles
Cuando una derivación pasa por algún punto en que hay más de una variable, significa que habrá varias derivaciones equivalentes, según cuál sea el orden en que aplicamos las producciones: S XY aaXY aaXYb aaaaXYb aaaaXb aaaab S XY aaXY aaaaXY aaaaY aaaaYb aaaab
26
Derivaciones y árboles
Dentro de esta variedad de derivaciones equivalentes, distinguimos la derivación izquierda y la derivación derecha (anotadas por L y R respectivamente). S XY aaXY aaaaXY aaaaY aaaaYb aaaab es una derivación izquierda: en cada paso reemplazamos la variable que está más a la izquierda. Una derivación derecha sería: S XY XYb Xb aaXb aaaaXb aaaab
27
Derivaciones y árboles
Árbol de análisis sintáctico (o “árbol de derivación”): representa la derivación, sin importar el orden: SL aaaab : S XY aaXY aaaaXY aaaaY aaaaYb aaaab SR aaaab : S XY XYb Xb aaXb aaaaXb aaaab
28
Derivaciones y árboles
En la raíz va S. En las hojas, terminales o . Las derivaciones extremas, L y R, corresponden a hacer recorridos del árbol en pre-orden y post-orden, respectivamente. Nótese que en este caso hay más de una derivación, pero el árbol es único (no hay otra forma de derivar aaaab). No siempre será el caso.
29
GLC: ambigüedad x + y + z E E + E | (E) | V V x | y | z E + V x y
E E+E V+E x+E x+E+E x+V+E x+y+E x+y+V x+y+z E E+E E+E+E V+E+E x+E+E x+V+E x+y+E x+y+V x+y+z Aquí hay dos árboles distintos, cada uno con una derivación izquierda distinta.
30
GLC: ambigüedad Analizador léxico T o t a l = p r e c i + v ; Total = precio + iva ; asignación Parser Total := Expresión id id precio iva Los parseadores construyen árboles de análisis sintáctico. El árbol indica cómo se entiende el texto.
31
GLC: ambigüedad x y + z E E + E | EE | (E) | V V x | y | z
La existencia de más de un árbol de derivación puede ser entonces nefasta: E E + E | EE | (E) | V V x | y | z E + V x y z E + V x y z x y + z “Primero y+z, luego x eso” “Primero xy, luego eso + z”
32
GLC: ambigüedad Un caso clásico de ambigüedad en lenguajes de programación: dos ifs, un else. La mayoría de los lenguajes lo resuelven asignando el else al if más cercano. S if b then else a if b then S
33
GLC: ambigüedad Decimos que una gramática G es ambigua, si existe una palabra en L(G) que admite más de un árbol de derivación. Nota: puede haber más de una derivación sin que indique ambigüedad, siempre y cuando sigan el mismo árbol. Otro motivo que hace nefasta la ambigüedad: para el parser es más fácil encontrar un árbol de derivación si la solución es única.
34
GLC: ambigüedad E E + E | EE | (E) | V V x | y | z
La buena noticia: a veces podemos cambiar la gramática por otra equivalente (i.e., mismo lenguaje) pero sin ambigüedad: E E + E | EE | (E) | V V x | y | z Genera lo mismo, pero obliga al árbol a reconocer la prioridad de la multiplicación. Java o C++ aplican algo análogo para resolver los else ambiguos. E T | E + T T F | T F F (E) | V V x | y | z
35
GLC: ambigüedad Las malas noticias:
A veces un lenguaje es inherentemente ambiguo: sólo existen gramáticas ambiguas que lo describen. Si tenemos una gramática ambigua, no existe un algoritmo general que nos diga acaso es intrínsecamente ambigua. Y aún si no lo fuera, tampoco hay método infalible para “desambiguarla”.
36
GLC: ambigüedad Ejemplo de lenguaje inherentemente ambiguo (sin demostrar): Una palabra de la forma anbncn tiene dos árboles distintos. Lo que no demostraremos es que para cualquier otra gramática equivalente, pasa lo mismo. Ver Hopcroft.
37
GLC: ambigüedad Ergo: Se puede tratar de evitar la ambigüedad.
A veces hay que convivir con ella. Un lenguaje de programación debiera diseñarse con una gramática que evite la ambigüedad (tanto para evitar errores de interpretación, como para facilitar el parseo).
38
GLC: simplificación Dada una gramática G, digamos, S → aSb | bSaSb | T
T → S | si además nos dan un string w, ¿Cómo sabemos acaso wL(G)? En caso de que esté, ¿cómo obtenemos un árbol de derivación? Y en caso de obtenerlo, ¿es único?
39
GLC: simplificación w=aabbb ¿está?
S → aSb | bSaSb | T T → S | w=aabbb ¿está? Por fuerza bruta: podemos intentar generar todas las posibles derivaciones, buscando alguna que genere w. S aSb aaSbb abSaSbb ... Problema: ¿Cuándo parar? aTb bSaSb baSbaSb ... T S ...
40
GLC: simplificación w=aabbb ¿está? S aSb abSaSbb abSabb ababb
S → aSb | bSaSb | T T → S | w=aabbb ¿está? Una idea: parar cuando la palabra que tenemos exceda la longitud de w. Problema #1: si existen reglas de producción que llevan a , entonces la longitud no necesariamente va aumentando. S aSb abSaSbb abSabb ababb Para evitar esos "acortamientos", sería bueno que no hubiera producciones nulas como esa.
41
GLC: simplificación w=aabbb ¿está? S aSb aTb aSb …
S → aSb | bSaSb | T T → S | w=aabbb ¿está? Una idea: parar cuando la palabra que tenemos exceda la longitud de w. Problema #2: podemos quedarnos pegados en loops, si se dan casos en que, por ejemplo, S→T, T→S. S aSb aTb aSb … Así que sería bueno evitar situaciones de ese tipo también.
42
Eliminación de producciones nulas
Decimos que una variable X es anulable si existe una derivación X * Para determinar las variables anulables, aplicamos un algoritmo de marcado recursivo: Marcamos todas las variables X que tengan una regla de producción X. Mientras exista una regla de producción de la forma YX1...Xm donde Y no está marcado pero todos los Xi lo están, marcar Y.
43
Eliminación de producciones nulas
Para eliminar las producciones nulas, (1) Determinar todas las variables anulables, X1,...,Xk (2) Para cada producción de la forma YuXiv, agregar una producción Yuv. Más en general: si el lado derecho incluye más de una variable anulable, considerar cada combinación de anulación. Por ejemplo, si YuXabYv, y tanto X como Y son anulables, agregamos YuabYv YuXabv Yuabv
44
Eliminación de producciones nulas
Para eliminar las producciones nulas, (3) Si Xi es una producción, eliminarla. (4) Si S es anulable, entonces agregar una producción S (salvo que ya exista). Esa última salvedad es importante: Si no está en el lenguaje de la gramática, entonces S no es anulable y no habrá producciones nulas. Si está en el lenguaje de la gramática, entonces S es anulable y la única producción nula será S.
45
Eliminación de producciones nulas
Ejemplo: S a | Xb | aYa X Y | Y b | X Anulables: X e Y. Eliminamos X A partir de SXb se agrega Sb, pues X es anulable. A partir de SaYa se agrega Saa, pues Y es anulable, S a | Xb | aYa | b | aa X Y Y b | X
46
Eliminación de producciones nulas
Otro ejemplo: Gramática inicial Gramática final Sustituimos Anulables: M
47
Eliminación de producciones unitarias
Una "producción unitaria" es de la forma XY; decimos que existe una derivación unitaria entre dos variables X e Y si se tiene X * Y. Si no hay producciones nulas (y supondremos aquí que ya las eliminamos), entonces X * Y sólo es posible mediante una cadena de producciones unitarias. Producción S X - Y X S Y X Y X S S aX | Yb X S Y bY | b | X
48
Eliminación de producciones unitarias
Para eliminar derivaciones unitarias: Para cada par de variables tales que X * Y, introducimos nuevas producciones: para cada producción no-unitaria de Y, Ys1, Ys2, ..., agregamos Xs1, Xs2, ... Se hace simultaneamente para todos los pares X,Y con derivación unitaria. Después se eliminan las producciones unitarias, y todo lo redundante (que suele aparecer).
49
Eliminación de producciones unitarias
Ejemplo: S aX | Yb X S Y bY | b | X Como X * S, se agregan XaX , XYb Como Y * X... No se agrega nada. Como Y * S, se agregan YaX , YYb Finalmente, eliminamos las producciones unitarias XS y YX. La nueva gramática quedaría S aX | Yb X aX | Yb Y bY | b | aX | Yb
50
Eliminación de variables inútiles
Al ir transformando las gramáticas (manteniendo, recordemos, el mismo lenguaje) pueden aparecer variables o producciones inútiles. Dos formas típicas son: Y es inútil: no hay forma de que aparezca en una derivación! X es inútil: nunca desaparece, así que no puede formar parte de la derivación de una palabra del lenguaje.
51
Eliminación de variables inútiles
En general una variable será útil cuando exista una palabra wL(G) en cuya derivación aparezca: Si esto nunca ocurre, es inútil. Una producción es útil sólo si todas sus variables son útiles. De lo contrario, es inútil. Para determinar las variables inútiles: son aquellas que no producen strings de terminales, o bien, que no son accesibles desde S.
52
Eliminación de variables inútiles
Para encontrar las variables que producen strings de terminales, definimos un conjunto U=T. Luego iteramos: Si existe una variable XU, pero que tiene una producción Xu, uU*, entonces agregamos X a U. Si no existe ninguna variable así, salimos de la iteración. U={a,b} U={a,b,A} U={a,b,A,S} U={a,b,A,S,B}
53
Eliminación de variables inútiles
Las variables que hayan quedado fuera de U son las que no producen strings de terminales, ergo, son inútiles. Las eliminamos, así como todas las producciones en que aparezcan. U={a,b} U={a,b,A} U={a,b,A,S} U={a,b,A,S,B}
54
Eliminación de variables inútiles
A continuación eliminamos las variables que no se alcancen desde S. Eso es aplicar recorrido de grafos, de EDA: Generamos grafo de dependencia B no es alcanzable Es inútil.
55
Eliminación de variables inútiles
Simplificación de gramáticas: Eliminar producciones nulas Eliminar producciones unitarias Eliminar variables inútiles (1) y (2) son relevantes para que las cosas que siguen a continuación funcionen. (3) es útil para no acarrear lastre, que suele aparecer como subproducto de (1) y (2).
56
Aumento de longitud en la derivación
Sea G una gramática sin producciones nulas ni unitarias. Entonces, en una derivación, cada paso aumenta la longitud de la palabra, o bien lo mantiene constante pero a costa de reducir la # de variables. ¿Motivo? Cada paso de la derivación reemplaza una variable X por algo, pero ese "algo" no es ni tampoco es una variable "desnuda". Alternativas: Reemplazar por una expresión con más de un símbolo: la expresión se alarga. Reemplazar por un símbolo terminal: queda con la misma longitud, pero con una variable menos.
57
Aumento de longitud en la derivación
En ese caso sí podemos aplicar la fuerza bruta para evaluar acaso un string w pertenece a una gramática G: Probamos todas las derivaciones de largo a lo más |w| (es decir, todas las combinaciones de a lo más |w| reglas de producción). Esa es ahora una cantidad finita, así que podemos probarlas en tiempo finito. En el peor de los casos, probamos |P|+|P|2+...+|P||w| combinaciones. wL(G) ssi alguna de esas derivaciones la genera.
58
La buena y mala noticia Es buena noticia: nos da un algoritmo para saber si una palabra está en el lenguaje. La mala noticia: es pésimo. La cantidad de casos crece exponencialmente en la medida que crece |w|. Para un código Java de 200 líneas, el tiempo de ejecución sería astronómico ( 10200). Existe un algoritmo más eficiente, pero requiere transformar la gramática un poco más:
59
Forma Normal de Chomsky (FNC)
Una gramática está en la forma normal de Chomsky (FNC) si cada producción (a excepción de S, si que existe) es de una de las dos siguientes formas: XYZ o bien Xa donde, como de costumbre, X,Y,ZV, aT. Está en FNC No está en FNC
60
Forma Normal de Chomsky (FNC)
Teorema: Para toda gramática de libre contexto G, existe una gramática de libre contexto G' en forma normal de Chomsky que es equivalente a G (es decir, L(G)=L(G')). Para demostrarlo, tenemos que ver que podemos transformar cualquier GLC hasta que quede en FNC. 1. Eliminamos las producciones nulas, unitarias, e inútiles. 2. Eliminamos los lados derechos "mixtos":
61
Forma Normal de Chomsky (FNC)
Para eliminar los lados derechos mixtos, creamos una nueva variable T por cada terminal . Reemplazamos cada por el T respectivo, y agregamos un producción T. Ojo: si alguna producción ya era de la forma X, la dejamos así (no la cambiamos a XT). Así evitamos introducir producciones unitarias.
62
Forma Normal de Chomsky (FNC)
3. Reemplazamos toda producción de la forma AC1C2...Cn por una cadena de producciones AC1V1, V1C2V2, ... , Vn-2Cn-1 Cn donde los V1,...,Vn-2 son nuevas variables, intermedias.
63
Forma Normal de Chomsky (FNC)
Y listo. Llevar GLC a la forma normal de Chomsky es relativamente fácil. Tener la GLC en FNC sirve para varias cosas, prácticas y teóricas. La más importante: para parsear en tiempo polinomial en |w|.
64
CYK Algoritmo CYK (Cocke-Younger-Kasami):
Input: una GLC G en FNC, y una palabra w. Output: acaso wL(G) [y fácilmente se puede pedir que además dé un árbol de derivación, en caso de respuesta positiva] Idea: determino las variables que producen todas las subpalabras de w de largo 1. Luego las que producen todas las subpalabras de w de largo 2. Etc...
65
CYK Para una palabra de largo k dada (digamos, u), consideramos las posibles formas de descomponerla en 2 palabras más cortas. Si para una descomposición u=v1v2 se tiene que X * v1, Y * v2 (esa información ya está en la tabla), y existe ZXY (eso lo miro en la gramática), entonces Z*u. Al terminar: wL(G) ssi S es una de las variables que producen w.
66
CYK Ejemplo, con gramática:
Subpalabras de largo k, partiendo de posición j k \ j 1 2 3 4 5 y palabra
67
CYK Variables que generan las subpalabras de largo 1
68
CYK Variables que generan las subpalabras de largo 2
69
CYK Variables que generan las subpalabras de largo 5 (o sea, w)
70
CYK Es fácil modificar CYK para que me entregue un árbol de derivación: cada vez que ponemos una variable en la tabla, debemos recordar por qué la pusimos. Luego con esa información recuperamos el árbol. CYK llena una tabla de tamaño |w|2. Para cada item de la tabla hay que hacer algo de trabajo. Se puede demostrar que el tiempo de ejecución es |w|3. Mucho mejor que |P||w|.
71
PDA (Autómatas de pila)
Antes teníamos la correspondencia lenguajes regulares autómatas finitos. También para los LLC existe, no sólo un tipo de gramática, sino también un tipo de máquina que los reconoce. Como los lenguajes regulares son un subconjunto propio de los LLC, el nuevo tipo de máquina es una generalización del que teníamos antes.
72
PDA (Autómatas de pila)
Input Pila Estados PDA Al AF le agregamos una pila (stack). Memoria potencialmente infinita, pero de acceso restringido.
73
PDA (Autómatas de pila)
El resultado es un autómata de pila, autómata apilador, o en inglés pushdown automaton (PDA). A medida que el PDA lee su input, puede sacar o guardar símbolos en la pila. Sus cambios de estados, y lo que haga con la pila, dependerán de lo que va leyendo en el input y de lo que saque de la pila. PDA
74
PDA (Autómatas de pila)
No determinismo: Los PDA que veremos, salvo que se indique lo contrario, son no deterministas : hay transiciones , puede haber más de una transición para una misma situación, etc... Lenguaje reconocido: El lenguaje reconocido por el PDA será el conjunto de palabras para las cuales existe una secuencia de transiciones que concluye con la palabra leída completa, y en estado de aceptación. Es decir, igual que en AFND+.
75
PDA (Autómatas de pila)
La pila tiene su propio alfabeto, (que puede coincidir en parte con el del input). Existe un símbolo especial $ que señala "el fondo" de la pila (algunos libros usan z0, u otro). Al comienzo es lo único que la pila contiene. leo del input saco de la pila guardo en En el grafo de transiciones se anota lo que se saca y guarda en la pila.
76
input pila tope Reemplaza
77
input pila tope Guarda ("push")
78
input pila tope Saca ("pop")
79
input pila tope Sin cambio
80
PDA (Autómatas de pila)
No determinismo Transición
81
PDA (Autómatas de pila)
Formalmente, un PDA es una tupla M = ( Q, , q0, F ) Q es un conjunto finito de estados es el alfabeto de entrada es el alfabeto de la pila q0 es el estado inicial FQ son los estados de aceptación es la función de transición, : Q({})({}) 2Q({})
82
PDA, ejemplo Recordatorio: también se escribe a veces como “”, o también como “”. En los monos que siguen, está como porque eran muchos para cambiarlos! Ejemplo:
83
PDA, ejemplo Input Pila estado actual
84
PDA, ejemplo Input Pila
85
PDA, ejemplo Input Pila
86
PDA, ejemplo Input Pila
87
PDA, ejemplo Input Pila
88
PDA, ejemplo Input Pila
89
PDA, ejemplo Input Pila
90
PDA, ejemplo Input Pila
91
PDA, ejemplo Input Pila acepta
92
PDA, ejemplo En general, el lenguaje que este PDA acepta es
93
PDA, otro ejemplo Otro ejemplo, ahora con lenguaje:
94
PDA, otro ejemplo Input Pila
95
PDA, otro ejemplo Input Pila
96
PDA, otro ejemplo Input Pila
97
PDA, otro ejemplo Input Pila
98
PDA, otro ejemplo Input Pila
99
PDA, otro ejemplo Input Pila
100
PDA, otro ejemplo Input Pila acepta
101
Un ejemplo más: Vimos que la gramática de abajo genera el lenguaje L={w{0,1}*: w tiene 2 bloques de 0’s del mismo tamaño} Ejemplos de strings en L: 01011, , Ejemplos de strings fuera de L: , 01111 A B C A, parte inicial: , o termina en 1 C, parte final: , o comienza con 1 D B, parte central: zona D, rodeada por bloques de 1 o más 0’s. D, centro del centro: parte y termina con 1. [transparencia 23] A → | U1 U → 0U | 1U | C → | 1U D → 1U1 | 1 S → ABC B → 0B0 | 0D0
102
Un ejemplo más: He aquí un PDA que reconoce ese mismo lenguaje: B A D
e, e / e 1, e / e 0, e / 0 q0 q1 q2 q3 1, e / e e, e / e 0, e / e C 0, e / e 1, e / e q4 1, e / e 1, e / e 1, e / e 1, $ / $ q6 q5 0, 0 / e q7 e, $ / $
103
Guardando strings String guardado
Permitiremos ahora guardar strings en la pila: tope pila Guarda “cda” string guardado
104
Guardando strings El poder de cómputo no cambia, pues
es equivalente a tener
105
Y otro ejemplo...
106
Input Pila
107
Input Pila
108
Input Pila
109
Input Pila
110
Input Pila
111
Input Pila
112
Input Pila
113
Input Pila acepta
114
Idea: este PDA guarda en la pila sólo lo que está en exceso, respecto a na=nb.
Se usó esta vez 0 y 1 en la pila, para representar a y b respectivamente. Esto es frecuente: distinguir los alfabetos ayuda a no confundirse.
115
PDA: descripción instantánea
Tiempo atrás definimos la configuración o descripción instantánea de un AF (la “foto” del AF en un momento dado) como (q,w), donde q era el estado actual y w era la parte del input que faltaba por leer. Es similar para PDA, pero ahora la “foto” debe incluir el contenido de la pila. (q,w,v) q Q, el estado actual v , el contenido actual del stack w , lo que falta por leer en el input
116
PDA: descripción instantánea
Input Instante 4: Pila
117
PDA: descripción instantánea
Input Instante 5: Pila
118
PDA: descripción instantánea
Escribimos (q1,bbb,aaa$)(q2,bb,aa$) y el cómputo completo será (q0,aaabbb,$) (q1,aaabbb,$) (q1,aabbb,a$) (q1,abbb,aa$) (q1,bbb,aaa$) (q2,bb,aa$) (q2,b,a$) (q2,,$) (q3,,$) Abreviando podemos decir que (q0,aaabbb,$) (q3,,$) A veces se pone * para especificar que se refiere a más de un paso.
119
Lenguaje por estado de aceptación
Podemos entonces definir formalmente el lenguaje aceptado por un PDA M=(Q, , q0, F) como L(M) = { w*: qfF,v*, (q0,w,$)(qf,,v) } Recuérdese que los PDA son no-deterministas, así que para que wL(M) basta que exista alguna cadena de cómputos que sirva.
120
Lenguaje por pila vacía
Otra forma de asociar un lenguaje a un PDA es definir N(M) = { w*: qQ, (q0,w,$)(q,,$) } Es decir: el “estado de aceptación” es cualquier estado, pero con la pila vacía, y la palabra de entrada completamente leída. Se demuestra (no es difícil) que las nociones son equivalentes: si L=L(M1) para un PDA M1, existe un PDA M2 con L=N(M2), y viceversa:
121
Lenguaje por pila vacía
Si tenemos un PDA que reconoce por estado de aceptación, y queremos uno que reconozca por pila vacía, hacemos que desde los estados de aceptación pase (con ) a un estado de "limpieza" de la pila. $ $ Ese z0 es un "falso piso", de modo que la pila sólo estará de verdad vacía al llegar a p.
122
Lenguaje por pila vacía
Al revés, si tenemos uno que reconoce por pila vacía, y queremos uno que reconozca por estado de aceptación: desde todos los estados ponemos una transición y se vaya a un estado de aceptación. , $/ , $/ , $/Z0$ , $/ , $/
123
PDA y GLC Teorema: L es reconocido por algún PDA ssi L es un lenguaje de libre contexto. Demostración, sólo la idea: Hacia un lado es fácil: veamos que si G es una gramática de libre contexto, entonces existe un PDA M con L(M)=L(G). Primero, recordemos como es una derivación izquierda:
124
GLC PDA Consideremos una derivación izquierda de aabbcbaa con la gramática G. G: S aSa | YZ Y bY | Z cZ | Y S aSa aaSaa aaYZaa aabYZaa aabbYZaa aabbZaa aabbcZaa aabbcYaa aabbcbYaa aabbcbaa Nótese que: Lo que va quedando a la izquierda se “congela”, y no se vuelve a mirar. Lo que está a la derecha es una pila! S a aa Y Zaa aab aabb Z aabbc aabbcb
125
GLC PDA Sea G=(V,T,S,P) una gramática de libre contexto.
Construimos el PDA M=(Q, , q0, F) con Q={q0, q1, q2} F={q2} =T =VT{$} se construye como sigue: Para cada aT Para cada producción pq en P
126
GLC PDA Idea: Lo que está en la pila es lo que falta “procesar”.
Si vemos ahí un terminal, significa que lo generó nuestro último reemplazo. Por lo tanto, tiene que tenerlo el input. Si es una variable, la tenemos que reemplazar por alguna de sus producciones.
127
GLC PDA S aSa aYZa abYZa abZa abcZa abcYa Gramática: S aSa | YZ
(q0,abcba,$) (q1,abcba,S$) (q1,abcba,aSa$) (q1,bcba,Sa$) (q1,bcba,YZa$) (q1,bcba,bYZa$) (q1,cba,YZa$) (q1,cba,Za$) (q1,cba,cZa$) (q1,ba,Za$) (q1,ba,Ya$) (q1,ba,bYa$) (q1,a,Ya$) (q1,a,a$) (q1,,$) (q2,,$) Gramática: S aSa | YZ Y bY | Z cZ | Y Ejemplo: derivación izquierda (a la idem), y cómputo en el PDA (a la derecha). S aSa aYZa abYZa abZa abcZa abcYa abcbYa abcba
128
PDA GLC En dirección contraria es más complicado.
No lo veremos en detalle. Cada libro da una versión un poco distinta. Todas son variaciones en torno a lo que sigue; para dudas, ver el Hopcroft en inglés (v. 2). Consideremos un PDA M=(Q, , q0, F) en la forma en que los definimos al comienzo (escribiendo símbolos de a uno en la pila, no strings).
129
PDA GLC Las transiciones entonces son de la forma
donde la a, la X y/o la Y pueden eventualmente ser . Usaremos aquí mayúsculas para los elementos de , para distinguirlos de los terminales en la gramática. Supondremos que el PDA acepta por pila vacía. Queremos una gramática que genere el mismo lenguaje.
130
PDA GLC En la gramática que se define, los terminales serán (el alfabeto de entrada del PDA). El símbolo de inicio, S, será un símbolo especial. El resto de las variables corresponderán a los elementos de Q({})Q; los escribiremos de la forma [pXq]. V = {S} Q({})Q
131
PDA GLC Las reglas de producción se definen con la intención de que [pXq] produzca exactamente el conjunto de palabras que, leídas en el PDA, pueden llevarnos desde el estado p hasta el estado q, sacando una X de la pila (y sin meternos más abajo): [pXq] * w (p, w, X) * (q, , )
132
PDA GLC gramática pda Primero se define S[q0Z0p] para todo pQ.
[pXq] * w (p, w, X) * (q, , ) Primero se define S[q0Z0p] para todo pQ. Ese Z0 es el "falso piso": al sacarlo, se vacía la pila, y podemos aceptar (si el input se acabó). Si los [q0Z0p] cumplen lo de arriba, estamos bien.
133
PDA GLC A continuación, para cada transición como la de arriba, se agregan las reglas de producción [pXr] a [qYr] para todo rQ Idea: una forma de ir de p a r sacando una X de la pila, es leer una a del input, y luego ir de q a r de alguna forma que saque Y de la pila. Nota: Si a=, tendremos [pXr] a [qYr].
134
PDA GLC Para hacer la demostración, se demuestra
[pXq] * w (p, w, X) * (q, , ) Cada implicación se demuestra por inducción; ver Hopcroft en caso de incredulidad. Esta construcción no se usa mucho; la otra tampoco. Sirven básicamente para convencerse de la equivalencia PDAGLC.
135
PDA y determinismo Un DPDA es un deterministic pushdown automaton: lo mismo que un PDA, pero sin ambigüedad en ningún paso. No lo demostraremos formalmente, pero se puede demostrar lo siguiente: si anotamos por LM la clase de lenguajes reconocidos por cada tipo de autómata, tenemos que LAFND+ = LAFD LDPDA LPDA y las inclusiones son propias. Así que acá el no-determinismo sí cambia los lenguajes.
136
PDA y determinismo Un ejemplo de lenguaje que está en LDPDA pero no está en LAFD es {anbn:n0} La primera b "me avisa" que tengo que cambiar de estado. Gracias a eso es determinista.
137
PDA y determinismo Un ejemplo de lenguaje que está en LPDA pero no está en LDPDA es {w=u uR : u{a,b}* } Idea: Para reconocer 0n10n necesito que el segundo grupo de 0's "mate" al primero en el stack ...pero entonces ya no podría reconocer 0n10n0n10n, que también está en L.
138
Lema de bombeo para LLC Ahora veamos ejemplos de lenguajes que no están en LPDA; es decir, que no son de libre contexto. Para eso, la herramienta de demostración será el: Lema de bombeo para LLC: sea L un lenguaje de libre contexto. Entonces existe un nN tal que si wL, |w|>N, entonces w puede descomponerse como w = uvxyz de modo tal que |vxy| n, |vy| > 0 uvkxykz k0
139
Lema de bombeo para LLC w = uvxyz |vxy| n, |vy| > 0, uvkxykz k0 Idea: En la derivación, alguna variable R debe aparecer en la producción a partir de si misma. Eso permite bombear: en lugar de producir Rx la segunda vez que aparece, volvemos a hacer Rvxy, y así tantas veces como queramos.
140
Lema de bombeo para LLC
141
Lema de bombeo para LLC La idea, más en detalle:
Si L es LLC, existe una gramática G=(V,T,S,P) en forma normal de Chomsky que lo genera. Si el árbol de derivación de una palabra w es de altura h, entonces |w|2h (pues en el caso extremo, voy reemplazando cada símbolo por 2). Sea n=2|V|+2. Si |w|n, entonces su árbol de derivación es de altura al menos |V|+2. Consideremos un camino de longitud máxima desde S hasta una hoja (terminal).
142
Lema de bombeo para LLC Tiene que haber al menos alguna variable repetida a lo largo de ese camino. Escogemos R como la última repetición que vemos, al ir de arriba hacia abajo. uvkxykz k0 sale de lo anterior, y del mono. |vy| > 0, pues de lo contrario habría producciones unitarias (y no hay, pues estamos en FNC). |vxy| n, pues de lo contrario R no era la última repetición (se aplicaría a |vxy| el argumento inicial). "QED"
143
Lema de bombeo para LLC, ejemplo
Ejemplo: L={anbncn: n0} no es de libre contexto. Supongamos que sí lo es, y sea m la constante de bombeo. Tomemos w=ambmcm. w tendría una descomposición w = uvxyz con |vxy| m, |vy| > 0, uvkxykz k0. Nótese que wL, |w|a=|w|b=|w|c.
144
Lema de bombeo para LLC, ejemplo
Ejemplo: L={anbncn: n0} no es de libre contexto. Para que uv2xy2z esté en L, vy debe cumplir también |vy|a=|vy|b=|vy|c Pero como |vxy| m, vy no puede incluir letras de los tres tipos! ¡Contradicción! Ejercicio: Usar bombeo para demostrar que el lenguaje {w=u u : u{a,b}* } no es de libre contexto.
145
Lema de bombeo para LLC Warning:
Las demostraciones por bombeo en LLC suelen ser bastante más complicadas que para lenguajes regulares (el ejemplo aquí fue excepcionalmente corto). Nótese que no sabemos nada sobre el u en w=uvxyz. Por lo tanto, a diferencia del bombeo en lenguajes regulares, no podemos asegurar que lo que bombeamos esté al comienzo. Eso obliga, en general, a considerar hartos casos (de posibles ubicaciones de vxy dentro de w).
146
Propiedades de clausura
Sean L1 y L2 dos lenguajes de libre contexto, descritos por las gramáticas G1=(V1,T1,S1,P1) y G2=(V2,T2,S2,P2). Entonces: L1 L2 es de libre contexto En efecto, lo genera la gramática G=(V,T,S,P) con V = V1 V2 {S} T = T1 T2 S una variable nueva P = P1 P2 {S S1|S2}
147
Propiedades de clausura
De manera similar, L1L2 es de libre contexto Tomamos G=(V,T,S,P) con V = V1 V2 {S} T = T1 T2 S una variable nueva P = P1 P2 {S S1S2}
148
Propiedades de clausura
También se tiene que: L1* es de libre contexto Tomamos G=(V,T,S,P) con V = V1 {S} T = T1 S una variable nueva P = P1 {S S S1 | }
149
Propiedades de clausura
Por otro lado, L1 L2 no necesariamente es de libre contexto Contraejemplo: L1={anbncm, n0, m0} y L2={anbmcm, n0, m0} son de libre contexto [ejercicio!], pero L1 L2 = {anbncn: n0} no lo es.
150
Propiedades de clausura
También se tiene que L1C no necesariamente es de libre contexto. Demostración: Los LLC son cerrados bajo la unión. Si además fueran cerrados para el complemento, entonces serían cerrados para la intersección (por leyes de Morgan!). Y acabamos de ver que no lo son.
151
Propiedades de clausura
Lo que sí se cumple es que para L3 regular, L1 L3 es de libre contexto Idea de la demostración: Consideramos M=(Q, , q0, F) un PDA que reconoce L1, y M'=(Q', ', q'0, F') un AFD que reconoce L3. Construimos un PDA con estados QQ', que simulará simultáneamente M y M' sobre un mismo input. Aceptamos la palabra si al final tanto M como M' aceptan.
152
Propiedades de clausura
Lo que sí se cumple es que para L3 regular, L1 L3 es de libre contexto Aplicaciones de eso: 1) Probemos que L={anbn: n100} es de libre contexto. Notamos que L = L1 L3, donde L1 = {anbn} L3 = {a,b}* \ {a100b100} Sabemos que L1 es un LLC; por otro lado, L3 es regular. L es regular.
153
Propiedades de clausura
Lo que sí se cumple es que para L3 regular, L1 L3 es de libre contexto Aplicaciones de eso: 2) Probemos que L={w{a,b,c}*: |w|a=|w|b=|w|c} no es de libre contexto. Por contradicción: si lo fuera, al intersectarlo con a*b*c* (que es regular!) obtendríamos un LLC. Pero L a*b*c* = {anbncn}, que no es LLC.
154
Problemas de decisión asociados a LLC
Problema de membresía: Dada una gramática de libre contexto G y una palabra w, ¿wL(G)? Respuesta: Algoritmo de parseo exhaustivo (requiere haber eliminado producciones nulas y unitarias). Algoritmo CYK (requiere FNC).
155
Problemas de decisión asociados a LLC
Problema de vacuidad: Dada una gramática de libre contexto G, ¿L(G)=? Respuesta: Aplicar la eliminación de variables inútiles. Ver acaso S es una variable inútil.
156
Problemas de decisión asociados a LLC
Problema de finitud: Dada una gramática de libre contexto G, ¿es L(G) infinito? Respuesta: Eliminar variables inútiles, producciones nulas, producciones unitarias. Hacer un grafo de dependencia entre las variables. L(G) es infinito ssi existe algún ciclo en ese grafo.
157
Problemas de decisión asociados a LLC
Problema de finitud:
158
Problemas de decisión asociados a LLC
Problema de igualdad: Dadas dos gramáticas de libre contexto G1 y G2, ¿L(G1)=L(G2)? Respuesta: NO EXISTE algoritmo general que responda esa pregunta. Por lo tanto, es un problema de decisión indecidible. Ese tema ya viene.
159
Un poco más sobre parseo
Los LLC nos interesan principalmente porque se usan. Y para usarlos, hay que parsearlos. ¿Cuando se parsean LLC? Respuesta: al procesar... Lenguajes de programación. Lenguajes de marcas ("ML") Lenguajes humanos (casi, casi) Veamos el caso de los "ML"
160
HTML como GLC El lenguaje de marcas (markup language) más conocido: HTML. <html> <body> <h4>Un ejemplo de listas anidadas:</h4> <ul> <li>Cafe</li> <li>Te <li>Te negro</li> <li>Te verde</li> </ul> </li> <li>Leche</li> Ese fue un <br> ejemplo. </body> </html> Un ejemplo de listas anidadas: Cafe Te Te negro Te verde Leche Ese fue un ejemplo.
161
HTML como GLC <ul> <li>Cafe</li> <li>Te <li>Te negro</li> <li>Te verde</li> </ul> </li> <li>Leche</li> Ese fue un <br> ejemplo. Hay marcas que comienzan y cierran entornos: <tag> ... </tag> Algunos tags van solos, como el <br>. Claramente hay una estructura gramatical.
162
HTML como GLC Doc | Elemento Doc
<ul> <li>Cafe</li> <li>Te <li>Te negro</li> <li>Te verde</li> </ul> </li> <li>Leche</li> Ese fue un <br> ejemplo. Doc | Elemento Doc Elemento Texto | <ul>Lista</ul> Texto | Caracter Texto Caracter <br> | a | b | ... | z | A | B... Lista | ElementoLista Lista ElementoLista <li>Doc</li> | <li>Doc Pues HTML no exige el </li> de cierre. Pero lo recomienda, para simplificar el parseo.
163
Marcado semántico Solían usarse los tags del html para darle formato al texto: <i>...</i> ponía texto en itálicas, <b>...</b> lo ponía en negritas, etc. En HTML más reciente, se prefiere una marcación semántica. Por ejemplo <em>...</em> para una frase con énfasis. Luego al desplegar el documento se puede usar itálicas (por ejemplo) para indicar ese énfasis. Ventajas: La forma (CSS) y el contenido (HTML) se especifican por separado. La marcación semántica permite lectura vía software.
164
Marcado semántico <H1>Hot Cop</H1> <i> by Jacques Morali, Henri Belolo</i> <ul> <li>Producer: Jacques Morali <li>Publisher: PolyGram Records <li>Length: 6:20 <li>Written: 1978 <li>Artist: Village People </ul> En el XML se generaliza la idea, para todo tipo de información. <SONG> <TITLE>Hot Cop</TITLE> <COMPOSER>Jacques Morali</COMPOSER> <COMPOSER>Henri Belolo</COMPOSER> <COMPOSER>Victor Willis</COMPOSER> <PRODUCER>Jacques Morali</PRODUCER> <PUBLISHER>PolyGram Records</PUBLISHER> <LENGTH>6:20</LENGTH> <YEAR>1978</YEAR> <ARTIST>Village People</ARTIST> </SONG> <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl=" <xsl:template match="/"> <html> <head><title>Song</title></head> <body><xsl:value-of select="."/></body> </html> </xsl:template> <xsl:template match="TITLE"> <h1><xsl:value-of select="."/></h1> ...
165
XML El XML (eXtensible Markup Language) se usa mucho para comunicar y almacenar información en la web. XHTML (HTML post XML) Feeds RSS Documentos (p.ej., docx o xmlx de Microsoft) Archivos gráficos (SVG) Música; matemáticas; wikipedia; transacciones financieras; servicios web; etc etc <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" " <svg width="100%" height="100%" version="1.1" xmlns=" <rect x="20" y="20" rx="20" ry="20" width="250" height="100" style="fill:red;stroke:black;stroke-width:5;opacity:0.5"/> </svg>
166
XML y DTD De esa misma flexibilidad se deduce que no es un lenguaje; es más bien una forma de definir un lenguaje. El lenguaje mismo se define en el DTD (Document Type Definition). Cualquiera puede inventar su XML, y publicar el DTD. Por eso es buena costumbre incluir una referencia al DTD en el XML. <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" " <svg width="100%" height="100%" version="1.1" xmlns=" <rect x="20" y="20" rx="20" ry="20" width="250" height="100" style="fill:red;stroke:black;stroke-width:5;opacity:0.5"/> </svg>
167
DTD Y el DTD es... una gramática de libre contexto.
Para ser más precisos: es una GLC extendida : se permite que al lado derecho de las producciones aparezcan expresiones regulares. S (a+c)* (X+Y) X a* Y b* No es difícil demostrar que para una GLC extendida siempre existe una GLC "normal" equivalente. Nos deshacemos de las ER agregando variables y producciones.
168
DTD El DTD es una gramática de libre contexto. Forma:
<!DOCTYPE nombre-del-DTD [ lista de definiciones de elementos ]> Definición de elemento: <!ELEMENT nombre-del-elemento (descripción)>
169
DTD La descripción es una expresión regular: Base:
Los nombres de otros elementos #PCDATA, es cualquier texto Operadores: | unión , concatenación * clausura de Kleene: 0 o más ocurrencias + clausura positiva: 1 o más ocurrencias ? opcional: 0 o 1 ocurrencias
170
DTD Ejemplo DTD: <!DOCTYPE PcSpecs [ <!ELEMENT PCS (PC*)>
<!ELEMENT PC (MODEL, PRICE, PROC, RAM, DISK+)> <!ELEMENT MODEL (#PCDATA)> <!ELEMENT PRICE (#PCDATA)> <!ELEMENT PROC (MANF, MODEL, SPEED)> <!ELEMENT MANF (#PCDATA)> <!ELEMENT SPEED (#PCDATA)> <!ELEMENT RAM (#PCDATA)> <!ELEMENT DISK (HARDDISK | CD | DVD )> <!ELEMENT HARDDISK (MANF, MODEL, SIZE)> <!ELEMENT SIZE (#PCDATA)> <!ELEMENT CD (SPEED)> <!ELEMENT DVD (SPEED)> ]>
171
DTD Fragmento de un XML según ese DTD <PCS> <PC>
<MODEL>4560</MODEL> <PRICE>$2295</PRICE> <PROCESSOR> <MANF>Intel</MANF> <MODEL>Pentium</MODEL> <SPEED>4Ghz</SPEED> </PROCESSOR> <RAM>8192</RAM> <DISK> <HARDDISK> <MANF>Maxtor</MANF> <MODEL>Diamond</MODEL> <SIZE>2000Gb</SIZE> </HARDDISK> </DISK> <DISK><CD><SPEED>32x</SPEED></CD></DISK> </PC> <PC> ….. </PC> </PCS> Fragmento de un XML según ese DTD
172
XML Moralejas: Las gramáticas sirven para hacer legibles (humanamente, o automáticamente) conjuntos de datos de casi cualquier tipo. Por facilidad de parseo, lo que se usa son GLC (y rara vez hace falta más). Todo lenguaje decente hoy por hoy tiene una (o más) buena librería para parsear xml. El XML es nuestro amigo.
173
Parseo y compiladores El otro uso (más clásico, pero 100% vigente) de las GLC: lenguajes de programación. Análisis léxico ("lexer") T o t a l = p r e c i + v ; Total = precio + iva ; asignación Análisis sintáctico ("parser") Expresión Total := id id Análisis semántico (chequeo de tipos, etc) precio iva Generación de código
174
Parseo y compiladores Parsear un string: determinar acaso pertenece al lenguaje de la gramática, y si es así, determinar un árbol de derivación. El algoritmo CYK es demasiado lento para parsear código, y no hay algoritmos más rápidos para GLC arbitrarias. Lo que se hace es usar GLC que se puedan parsear con algoritmos más rápidos. Para efectos prácticos, eso se traduce en LLC deterministas.
175
Parseo y compiladores Dos aproximaciones: Top down:
Partimos de la raíz del árbol de derivación (S) Tomamos una regla de producción, e intentamos calzarla con el input. Si en algún momento no podemos avanzar, nos devolvemos por la rama y probamos otra cosa (backtracking). Bottom up: Vamos procesando las hojas, creciendo hacia la raíz. A medida que leemos el input, los posibles árboles se codifican en un estado interno.
176
Parseo y compiladores Dentro de bottom up, parseadores LR(1):
L: lee el input de izquierda (L) a derecha. R: reproduce una derivación derecha (R). 1: puede "espiar" 1 símbolo hacia adelante. LR(k): idem, pero espiando k símbolos. ¿Qué significa eso?
177
Parseo y compiladores S Tc T TA | A A aTb | ab
Input Acción a ab A T Ta Taa Taab TaA TaT TaTb TA Tc S abaabbc baabbc aabbc abbc bbc bc c shift reduce Leemos el input de izquierda a derecha. Vamos guardándolo en una pila (pasos "shift"). Si se detecta en la pila algo que corresponde al lado derecho de una producción, se reemplaza (pasos "reduce").
178
Parseo y compiladores S Tc T TA | A A aTb | ab
Input Acción a ab A T Ta Taa Taab TaA TaT TaTb TA Tc S abaabbc baabbc aabbc abbc bbc bc c shift reduce Si desandamos lo andado, lo que tenemos es una derivación derecha. S T A T T A A a b a a b b c
179
Parseo y compiladores ¿Qué acción realizar en cada paso?
Decimos que una palabra w es un "item válido completo" si es el lado derecho de alguna producción de la gramática ("aTb"). Decimos que es un "item válido incompleto" si es un prefijo de un ítem válido ("aT"). Entonces, hay dos casos en que la acción está clara.
180
Parseo y compiladores Si hay un único item válido, y está completo, reemplazarlo (REDUCE). Si no hay ningún item válido completo, seguir leyendo (SHIFT). Casos problemáticos: Más de un item válido completo (conflicto R/R, dos opciones de reduce). Algunos items válidos completos, otros incompletos (conflicto S/R: ¿shift o reduce?).
181
Parseo y compiladores Aquí entra la cantidad de símbolos:
Un parseador LR(k) "espía" los primeros k símbolos del input restante, y usa eso para resolver el conflicto. Una gramática LR(k) es una que admite un parseador de ese tipo: con k símbolos todo conflicto se resuelve. En particular, una gramática LR(0) es una en que el conflicto jamás se produce.
182
Parseo y compiladores Entonces, parser LR(k):
L: lee el input de izquierda (L) a derecha. R: reproduce una derivación derecha (R). k: puede "espiar" k símbolo hacia adelante. Se puede demostrar que: Toda gramática LR(k), k>1, se puede convertir en una gramática LR(1) equivalente. L es un LLC determinista L admite una gramática LR(k), para algún k.
183
Lenguajes de libre contexto (LLC)
Parseo y compiladores Lenguajes Lenguajes de libre contexto (LLC) Java, Perl, Python, etc... LLC deterministas LR(0) LR(1) Lenguajes regulares
184
YACC Tiempo atrás mencionamos LEX, que a partir de una lista de expresiones regulares y código asociado, genera un analizador léxico. YACC es el hermano de LEX: a partir de una gramática y código asociado, genera un analizador sintáctico (un parseador). YACC: "yet another compiler compiler".
185
YACC El programa generado por YACC recibirá como input los tokens producidos por el programa generado por LEX. Compilador (o lo que queramos hacer) ER + código GLC + código La parte que uno tiene que hacer LEX YACC ER + código GLC + código "lexer" "parser" input tokens árbol Compilador (o lo que queramos hacer)
186
YACC En algunos casos el código que asociamos al parsear puede ser suficiente para nuestros fines; en esos casos no necesitamos hacer nada más con el output del parser. YACC genera un parser LALR(1): es LR(1), optimizado. Por lo tanto, nuestra gramática debiera ser LR(1). Si no, habrá conflictos sin resolver. Se pueden especificar precedencias para resolver conflictos (la alternativa es cambiar la gramática).
187
YACC YACC informa sobre los conflictos (R/R, S/R); eso ayuda a evitarlos! En ayudantía verán más sobre LEX y YACC; la tarea 2 consiste en usarlos.
Presentaciones similares
© 2024 SlidePlayer.es Inc.
All rights reserved.