lenguajes de libre contexto. gramáticasgramáticas una gramática es otra forma de describir un...
TRANSCRIPT
Lenguajes de libre contextoLenguajes de libre contexto
GramáticasGramáticasGramáticasGramá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
GramáticasGramáticasGramáticasGramáticas
O S P 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
GramáticasGramáticasGramáticasGramáticas
O S P 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"}
GramáticasGramáticasGramáticasGramáticas
Variable o "no-terminal"
T niño
Regla de producción
Terminal
GramáticasGramáticasGramáticasGramáticas
S
aSbS
abaSbS
aabbaaSbbaSbS
aaaabbbbaaaaSbbbb
aaaSbbbaaSbbaSbS
}0:{ nbaL nn
Otro ejemplo:
Algunas derivaciones:
Lenguaje:
Este formalismo permite describir algunos lenguajes que no son regulares.
Gramática: forma generalGramática: forma generalGramática: forma generalGramá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)*.
DerivacionesDerivacionesDerivacionesDerivaciones
•T={a,b}•V={S}•S=S•P={SaSb, S}
S
aSbS
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.
abaSbS
DerivacionesDerivacionesDerivacionesDerivaciones
Definimos * como la cerradura transitiva de .
Es decir, u * v ssi u1,u2,...,uk tales queu 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
Convención sobre notaciónConvención sobre notaciónConvención sobre notaciónConvenció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).
Gramáticas de libre contextoGramáticas de libre contextoGramáticas de libre contextoGramá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.
Gramáticas de libre contextoGramáticas de libre contextoGramáticas de libre contextoGramá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!!
(Gramáticas regulares(Gramáticas regulares(Gramáticas regulares(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.
Gramáticas regularesGramáticas regularesGramáticas regularesGramáticas regulares
L es un lenguaje regular ssi L=L(G) para una gramática regular G.
Ir derivando la palabra corresponde a ir cambiando de estado interno (la variable), y escribiendo.
SFV
A
B
a
a
a
b
a
aB
bBB
aBC
aCA
BS
aAS
C
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 definito en la transparencia previa.
Gramáticas regulares)Gramáticas regulares)Gramáticas regulares)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 :
•SaT•TSb•S
genera {anbn, n0}, que es el clásico ejemplo de lenguaje no regular.
GLC, ejemplosGLC, ejemplosGLC, ejemplosGLC, ejemplos
Volvamos al caso general de GLC. Otro ejemplo:
T
aTbT
TbS
¿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 “|”:
|aTbT
TbS
GLC, ejemplosGLC, ejemplosGLC, ejemplosGLC, ejemplos
Más ejemplos:
|)(| SSSS
donde T={(,)}, V={S}. ¿Lenguaje?
S (S) ()
S (S) (SS) ((S)S) ((S)(S)) (()(S)) (()())
da el lenguaje de los paréntesis bien balanceados.
GLC, ejemplosGLC, ejemplosGLC, ejemplosGLC, ejemplos
Más ejemplos:
|| bSbaSaS
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).
GLC, ejerciciosGLC, ejerciciosGLC, ejerciciosGLC, ejercicios
Ejercicios:
•¿Qué lenguajes describen las siguientes gramáticas?
G2: S XYX aX | bX | aY Ya | Yb | a
G1: S XaaXX aX | bX |
•Escriba una gramática que describa el lenguaje de todas las expresiones regulares válidas sobre el alfabeto {a,b}.
GLC "prototípicas"GLC "prototípicas"GLC "prototípicas"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 SaSbEl de los palíndromes es análogo.Idea: hay un "surtidor" al medio que emite letras de manera simétrica.
GLC "prototípicas"GLC "prototípicas"GLC "prototípicas"GLC "prototípicas"
•Por partes: L={anbnambm, n0, m0}
Lo generamos con algo de la forma SXYLuego 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:
SXXXaXb |
GLC "prototípicas"GLC "prototípicas"GLC "prototípicas"GLC "prototípicas"
•Anidados: L={anbmambn, n0, m0}
Aquí las “partes independientes” son anbn y 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 | XXbXa |
GLC, un ejemplo más complejoGLC, un ejemplo más complejoGLC, un ejemplo más complejoGLC, un ejemplo más complejo
L={w{0,1}*: w tiene dos bloques de 0’s del mismo tamaño}.
Permitidos: 01011, 001011001, 10010101001No permitidos: 01001000, 01111
10010011010010110 inicio parte central final
A B C
A: , ó termina en 1
C: , ó comienza con 1
00110100D
Cantidad de 0’s: •la misma a cada lado•al menos uno
GLC, un ejemplo más complejoGLC, un ejemplo más complejoGLC, un ejemplo más complejoGLC, un ejemplo más complejo
De modo que descomponemos por partes, y luego aplicamos recursividad en B.
10010011010010110 inicio parte central final
A B C
00110100D
Cantidad de 0’s: •la misma a cada lado•al menos uno
A → | U1U → 0U | 1U | C → | 1U
D → 1U1 | 1
S → ABC
B → 0B0 | 0D0
Derivaciones y árbolesDerivaciones y árbolesDerivaciones y árbolesDerivaciones 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:
|
|
YbY
aaXX
XYS
S XY aaXY aaXYb aaaaXYb aaaaXb aaaab
S XY aaXY aaaaXY aaaaY aaaaYb aaaab
Derivaciones y árbolesDerivaciones y árbolesDerivaciones y árbolesDerivaciones 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).
|
|
YbY
aaXX
XYS
S XY aaXY aaaaXY aaaaY aaaaYb aaaab
es una producció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
Derivaciones y árbolesDerivaciones y árbolesDerivaciones y árbolesDerivaciones y árboles
S
YX
a a X Y b
a a X
SL aaaab :
S XY aaXY aaaaXY aaaaY aaaaYb aaaab
SR aaaab :
S XY XYb Xb aaXb aaaaXb aaaab
Árbol de análisis sintáctico (o “árbol de derivación”): representa la derivación, sin importar el orden:
Derivaciones y árbolesDerivaciones y árbolesDerivaciones y árbolesDerivaciones 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.
S
YX
a a X Y b
a a X
•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.
GLC: ambigüedadGLC: ambigüedadGLC: ambigüedadGLC: ambigüedad
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) | V V x | y | z
x + y + z
E
E E+
E E+V
V Vx
y z
E
E E+
E E+ V
V 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.
GLC: ambigüedadGLC: ambigüedadGLC: ambigüedadGLC: ambigüedad
•Los parseadores construyen árboles de análisis sintáctico.•Ese árbol indica cómo se entiende el texto.
Analizador léxico
Parser
precio
id + id
Expresión
asignación
:=Total
iva
Total = precio + iva ;
T o t a l = p r e c i o + i v a ;
GLC: ambigüedadGLC: ambigüedadGLC: ambigüedadGLC: ambigüedad
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
x y + z
E
E EE E+V
V Vx
y z
E
E E+
E E V
V V
x y
z
“Primero y+z, luego x eso”
“Primero xy, luego eso + z”
GLC: ambigüedadGLC: ambigüedadGLC: ambigüedadGLC: ambigüedad
Un caso clásico de ambigüedad en lenguajes de programación: dos ifs, un else.
S
ifif then S else S
if then S
S
ifif then S
ifif then S else S
La mayoría de los lenguajes lo resuelven asignando el else al if más cercano.
GLC: ambigüedadGLC: ambigüedadGLC: ambigüedadGLC: 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.
GLC: ambigüedadGLC: ambigüedadGLC: ambigüedadGLC: ambigüedad
•La buena noticia: a veces podemos cambiar la gramática por otra equivalente (i.e., mismo lenguaje) pero sin ambigüedad:
E T | E + TT F | T FF (E) | VV x | y | z
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.
GLC: ambigüedadGLC: ambigüedadGLC: ambigüedadGLC: 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”.
GLC: ambigüedadGLC: ambigüedadGLC: ambigüedadGLC: ambigüedad
Ejemplo de lenguaje inherentemente ambiguo (sin demostrar):
}{}{ mmnmnn cbacbaL
||11
aAbA
AcSS
||22
bBcB
BaSS
21 | SSS
•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.
GLC: ambigüedadGLC: ambigüedadGLC: ambigüedadGLC: 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).
GLC: simplificaciónGLC: simplificaciónGLC: simplificaciónGLC: simplificación
Dada una gramática G, digamos,
S → aSb | bSaSb | TT → 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?
GLC: simplificaciónGLC: simplificaciónGLC: simplificaciónGLC: simplificación
S → aSb | bSaSb | TT → S |
S aSb
bSaSb
T
aaSbbabSaSbbaTb
S
baSbaSb...
w=aabbb ¿está?
Por fuerza bruta: podemos intentar generar todas las posibles derivaciones, buscando alguna que genere w.
Problema:
¿Cuándo parar?
...
...
GLC: simplificaciónGLC: simplificaciónGLC: simplificaciónGLC: simplificación
S → aSb | bSaSb | TT → 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.
GLC: simplificaciónGLC: simplificaciónGLC: simplificaciónGLC: simplificación
S → aSb | bSaSb | TT → 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.
Eliminación de producciones nulasEliminación de producciones nulasEliminación de producciones nulasEliminació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.
Eliminación de producciones nulasEliminación de producciones nulasEliminación de producciones nulasEliminació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
Eliminación de producciones nulasEliminación de producciones nulasEliminación de producciones nulasEliminació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.
Eliminación de producciones nulasEliminación de producciones nulasEliminación de producciones nulasEliminación de producciones nulas
Ejemplo:
S a | Xb | aYaX 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 | aaX YY b | X
Eliminación de producciones nulasEliminación de producciones nulasEliminación de producciones nulasEliminación de producciones nulas
SustituimosM
M
aMbM
aMbS
abM
aMbM
abS
aMbS
Gramática inicial
Anulables: M
Otro ejemplo:
Gramática final
Eliminación de producciones Eliminación de producciones unitariasunitarias
Eliminación de producciones Eliminación de producciones unitariasunitarias
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 -
S Y -
X S X S
X Y -
Y X Y X
Y S Y X S
S aX | YbX SY bY | b | X
Eliminación de producciones Eliminación de producciones unitariasunitarias
Eliminación de producciones Eliminación de producciones unitariasunitarias
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).
Eliminación de producciones Eliminación de producciones unitariasunitarias
Eliminación de producciones Eliminación de producciones unitariasunitarias
Ejemplo: S aX | YbX SY 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 | YbX aX | YbY bY | b | aX | Yb
Eliminación de variables inútilesEliminación de variables inútilesEliminación de variables inútilesEliminació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:
aXX
XS
S
aSbS
bXY
X
aXX
XS
X es inútil: nunca desaparece, así que no puede formar parte de la derivación de una palabra del lenguaje.
Y es inútil: no hay forma de que aparezca en una derivación!
Eliminación de variables inútilesEliminación de variables inútilesEliminación de variables inútilesEliminación de variables inútiles
En general una variable será útil cuando exista una palabra wL(G) en cuya derivación aparezca:
wuXvS •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.
Eliminación de variables inútilesEliminación de variables inútilesEliminación de variables inútilesEliminació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.
aCbC
aaB
aA
CAaSS
|| U={a,b}
U={a,b,A}U={a,b,A,S}U={a,b,A,S,B}
Eliminación de variables inútilesEliminación de variables inútilesEliminación de variables inútilesEliminació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.
aCbC
aaB
aA
CAaSS
|| U={a,b}
U={a,b,A}U={a,b,A,S}U={a,b,A,S,B} aaB
aA
AaSS
|
Eliminación de variables inútilesEliminación de variables inútilesEliminación de variables inútilesEliminació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:
aaB
aA
AaSS
|
S A B
Generamos grafo de
dependencia
B no es alcanzable Es inútil.
aA
AaSS
|
Eliminación de variables inútilesEliminación de variables inútilesEliminación de variables inútilesEliminación de variables inútiles
Simplificación de gramáticas:
(1)Eliminar producciones nulas
(2)Eliminar producciones unitarias
(3)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).
Aumento de longitud en la derivaciónAumento de longitud en la derivaciónAumento de longitud en la derivaciónAumento 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.
Aumento de longitud en la derivaciónAumento de longitud en la derivaciónAumento de longitud en la derivaciónAumento 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.
La buena y mala noticiaLa buena y mala noticiaLa buena y mala noticiaLa buena y mala noticia
Es buena noticia: existe 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 algoritmo más eficiente, pero requiere transformar la gramática un poco más.
Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)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.
bA
SAA
aS
ASS
aaA
SAA
AASS
ASS
Está en FNC
No está en FNC
Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)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, inútiles.2. Eliminamos los lados derechos "mixtos":
Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)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.
AcB
aabA
ABaS
cT
bT
aT
ATB
TTTA
ABTS
c
b
a
c
baa
a
Ojo: si alguna producción ya era de la forma X, la dejamos así (no la cambiamos a XT). Así evitamos introducir producciones unitarias.
Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)
3. Reemplazamos toda producción de la forma AC1C2...Cn por una cadena de produccionesAC1V1, V1C2V2, ... , Vn-2Cn-1 Cn
donde los V1,...,Vn-2 son nuevas variables, intermedias.
cT
bT
aT
ATB
TTTA
ABTS
c
b
a
c
baa
a
cT
bT
aT
ATB
TTV
VTA
BTV
AVS
c
b
a
c
ba
a
a
2
2
1
1
Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)Forma Normal de Chomsky (FNC)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|.
cT
bT
aT
ATB
TTV
VTA
BTV
AVS
c
b
a
c
ba
a
a
2
2
1
1
CYKCYKCYKCYK
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...
CYKCYKCYKCYK
•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.
wL(G) ssi al final S es una de las variables que producen w.
CYKCYKCYKCYK
Ejemplo, con gramática:
bB
ABB
aA
BBA
ABS
aabbby palabra
a
a b b b
aa ab bb bb
aab abb bbb
aabb abbb
aabbb
Subpalabras de largo k, partiendo de posición j
k \ j 1 2 3 4 5 1
2
3
4
5
CYKCYKCYKCYK
aA
aA
bB
bB
bB
aa ab bb bb
aab abb bbb
aabb abbb
aabbb
bB
ABB
aA
BBA
ABS
Variables que generan las subpalabras de largo 1
CYKCYKCYKCYK
aA
aA
bB
bB
bB
aa abS,B
bbA
bbA
aab abb bbb
aabb abbb
aabbb
bB
ABB
aA
BBA
ABS
Variables que generan las subpalabras de largo 2
CYKCYKCYKCYKaA
aA
bB
bB
bB
aa abS,B
bbA
bbA
aabS,B
abbA
bbbS,B
aabbA
abbbS,B
aabbbS,B
bB
ABB
aA
BBA
ABS
Variables que generan las subpalabras de largo 5 (o sea, w)
CYKCYKCYKCYK
•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|.
PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)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.
PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)
•Al AF le agregamos una pila (stack). Memoria potencialmente infinita, pero de acceso restringido.
•El resultado es un autómata de pila, autómata apilador, o en inglés pushdown automaton (PDA).
Input Pila
Estados
PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)
•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.
•Los PDA que veremos, salvo que se indique lo contrario, son no deterministas : hay transiciones , más de una transición para una misma situación, etc...
•Hay más de una forma de definir el lenguaje reconocido; de momento será "a la antigua", mediante estados de aceptación.
PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)
Un poco de notación extra:
•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. Al comienzo es todo lo que la pila contiene.
Pila
$
q1 q2a, b c
leo del input
saco guardo
•En el grafo de transiciones tendremos que anotar lo que se saca y guarda en la pila.
q1 q2a, b c
a
b tope
input
pila
a
Reemplazaeh
$eh
$
c
q1 q2ca ,
a a
Guardab
eh
$eh
$
bc
input
pilatope
("push")
q1 q2ba,
a a
Sacab
eh
$eh
$
input
pila
tope
("pop")
q1 q2 ,a
a a
Sin cambiob
eh
$eh
$
btope
input
pila
q1
q2a, b c
q3a, b c
q1 q2cb,
No determinismo Transición
PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)
Recordatorio: también se escribe a veces como “” o bien como “”.
PDA (Autómatas de pila)PDA (Autómatas de pila)PDA (Autómatas de pila)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({})
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
Ejemplo: (ojo, aquí )
,
a, a
b, a q0 q1 q2 q3
b, a
, $ $
a, a
b, a 0q q1 q2 q3
Input
a a a b b b
estadoactual
b, a
, , $ $
Pila
$
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
a, a
b, a q0 q1 q2 q3
Input
a a a b b b
b, a
, , $ $
$
Pila
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
a, a
b, a q0 q1 q2 q3
Input
a a a b b b
$
a
b, a
, , $ $
Pila
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
a, a
b, a q0 q1 q2 q3
Input
a a a b b b$
aa
b, a
, , $ $
Pila
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
a, a
b, a q0 q1 q2 q3
Input
a a a b b b
$
aaa
b, a
, , $ $
Pila
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
a, a
b, a q0 q1 q2 q3
Input
a a a b b b
$
aaa
b, a
, , $ $
Pila
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
a, a
b, a q0 q1 q2 q3
Input
a a a b b b$
a
b, a
, , $ $
a
Pila
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
a, a
b, a q0 q1 q2 q3
Input
a a a b b b$
b, a
, , $ $
a
Pila
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
a, a
b, a q0 q1 q2 q3
Input
a a a b b b
b, a acepta
, , $ $
$Pila
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
PDA, ejemploPDA, ejemploPDA, ejemploPDA, ejemplo
}0:{ nbaL nn
a, a
b, a q0 q1 q2 q3
b, a
, , $ $
En general, el lenguaje que este PDA acepta es
PDA, otro ejemploPDA, otro ejemploPDA, otro ejemploPDA, otro ejemplo
, $ $q1 q2
bb
aa
,
,
, q0
bb
aa
,
,
}{)( RwwML
Input
Pila
$
, $ $q1 q2
bb
aa
,
,
, q0
bb
aa
,
,
a ab b
PDA, otro ejemploPDA, otro ejemploPDA, otro ejemploPDA, otro ejemplo
Input
a ab
Pila
$
, $ $q1 q2
bb
aa
,
,
, q0
bb
aa
,
,
ab
PDA, otro ejemploPDA, otro ejemploPDA, otro ejemploPDA, otro ejemplo
Input
Pila
$
, $ $q1 q2
bb
aa
,
,
, q0
bb
aa
,
,
aa ab b
b
PDA, otro ejemploPDA, otro ejemploPDA, otro ejemploPDA, otro ejemplo
Input
Pila
$
, $ $q1 q2
bb
aa
,
,
, q0
bb
aa
,
,
aa ab b
b
PDA, otro ejemploPDA, otro ejemploPDA, otro ejemploPDA, otro ejemplo
Input
Pila
$
, $ $q1 q2
bb
aa
,
,
, q0
bb
aa
,
,
aa ab b
b
PDA, otro ejemploPDA, otro ejemploPDA, otro ejemploPDA, otro ejemplo
Input
Pila
$
, $ $1q q2
bb
aa
,
,
, q0
bb
aa
,
,
a ab b a
PDA, otro ejemploPDA, otro ejemploPDA, otro ejemploPDA, otro ejemplo
Input
Pila
$
, $ $q1
bb
aa
,
,
, q0
bb
aa
,
,
a ab b
acepta
q2
PDA, otro ejemploPDA, otro ejemploPDA, otro ejemploPDA, otro ejemplo
Guardando stringsGuardando stringsGuardando stringsGuardando strings
q1 q2a, b w
Símbololeído
Símbolosacado
Stringguardado
Guardando stringsGuardando stringsGuardando stringsGuardando strings
q1 q2a, b cdf
a
b top
input
pila
a
Guardar
eh h
e
cdf
stringguardado
$ $
Y otro ejemplo...Y otro ejemplo...Y otro ejemplo...Y otro ejemplo...
$$, q1 q2
a, $ 0$a, 0 00a,1
b, $ 1$b, 1 11b, 0
}:{)( ba nnwML
Input
a ab b ba
$
Pila
$$, q1 q2
a, $ 0$a, 0 00a,1
b, $ 1$b, 1 11b, 0
Input
a ab b ba
$
Pila
0
$$, q1 q2
a, $ 0$a, 0 00a,1
b, $ 1$b, 1 11b, 0
Input
a bb b a
$
Pila
a
$
$$, q1 q2
a, $ 0$a, 0 00a,1
b, $ 1$b, 1 11b, 0
0
Input
a bb b a
$
Pila
a
1
$$, q1 q2
a, $ 0$a, 0 00a,1
b, $ 1$b, 1 11b, 0
Input
a bb b a
$
Pila
a
11
$$, q1 q2
a, $ 0$a, 0 00a,1
b, $ 1$b, 1 11b, 0
Input
a bb b a
$
Pila
a
1
$$, q1 q2
a, $ 0$a, 0 00a,1
b, $ 1$b, 1 11b, 0
1
Input
a bb b a
$
Pila
a
1
$$, q1 q2
a, $ 0$a, 0 00a,1
b, $ 1$b, 1 11b, 0
Input
a bb b a a
$
Pila
$$, q1 q2
a, $ 0$a, 0 00a,1
b, $ 1$b, 1 11b, 0
acepta