Lenguaje Libre Del Contexto
Lenguaje Libre Del Contexto
Lenguaje Libre Del Contexto
N→w
Definición de la Gramática
Producción
Donde cualquier símbolo No Terminal del lado derecho de la producción puede ser
remplazado por cualquier definición de ese mismo terminal del lado derecho.
Ejemplo: S → E
E→E+E
E → num
Ejemplo
Un ejemplo de una Gramática Libre del contexto que reconoce operaciones de suma
y multiplicación con números enteros, como {5, 52+3, (1+3)*4}
Arboles de derivación
Hay un único nodo distinguido, llamado raíz (se dibuja en la parte superior) que no
tiene arcos incidentes.
Todo nodo c excepto el nodo raíz está conectado con un arco a otro nodo k, llamado
el padre de c (c es el hijo de k). El padre de un nodo, se dibuja por encima del nodo.
Todos los nodos están conectados al nodo raíz mediante un único camino.
Los nodos que no tienen hijos se denominan hojas, el resto de los nodos se
denominan nodos interiores.
Propiedades de un árbol de derivación.
Sea G = (N,T,S,P) una gramática libre de contexto, sea A Є N una variable. Diremos
que un árbol TA = (N,E) etiquetado es un árbol de derivación asociado a G si verifica
las propiedades siguientes:
Para cada cadena del lenguaje generado por una gramática es posible construir (al
menos) un árbol de derivación, en el cual cada hoja tiene como rótulo uno de los
símbolos de la cadena.
Para cada cadena del lenguaje generado por una gramática es posible construir (al
menos) un árbol de derivación, en el cual cada hoja tiene como rótulo uno de los
símbolos de la cadena.
T U N U {λ}
y el árbol de derivación:
Si leemos las etiquetas de las hojas de izquierda a derecha tenemos una sentencia.
Llamamos a esta cadena la producción del árbol de derivación.
Ejemplo
Derivación a la izquierda:
Derivación a la derecha:
Una GLC se dice que está en Forma Normal de Chomsky (FNC) si todas sus
producciones son de la forma:
Algoritmo FNC:
Para cada producción de la forma
(a)Para cada αi, si αi es terminal
- Se añade la producción Ca → a
- Se cambia αi por Ca en A → α1..αn
2. Para cada producción de la forma A → B1...Bm, m ≥ 3
(a) Se añaden (m-2) no terminales D1, D2, ..., Dm-2 (distintos para cada producción)
S XM
M SY
Xx
Yy
Mientras que la siguiente gramática que genera el mismo lenguaje no la tiene
S xSy
S xy
Para obtener la forma normal de Chomsky
Paso 1
Introducir los nuevos no terminales YZ y convertir la gramática anterior en la
siguiente:
S ZMZ
MN
Zz
Yy
Nx
Paso 2
Lo siguiente es reemplazar la regla S ZMZ por el par de reglas S ZR; R MZ, mientras
que M YMY se reemplaza por M YP; P MY para obtener la siguiente gramática:
S ZR
R MZ
MN
M YP
P MY
Zz
Yy
Nx
Paso 3
Finalmente la regla M N se reemplaza por la regla M x, produciendo así la siguiente
gramática ya que tiene la forma normal de Chomsky.
S ZR
R MZ
Mx
M YP
P MY
Zz
Yy
Nx
S ZR zMZ zYPZ zyPZ zyMYZ zyxYZ zyxyZ zyxyz
Ambigüedad Transitoria:
Este tipo de ambigüedad puede llegar a ser eliminada realizando una serie de
transformaciones sobre la gramática original. Una vez que se logra lo anterior, la
gramática queda lista para ser reconocida por la mayor parte de los analizadores
sintácticos. (Se le considera "ambigüedad" porque existen métodos para realizar
análisis sintáctico que no aceptan gramáticas con estas características)
ELIMINACIÓN DE LA AMBIGÜEDAD.
FIRST: Sea G:= (V; ∑; Q0; P) una gramática libre de contexto. Para cada forma
sentencial α Є (V U ∑)* y para cada k Є N definiremos la función.
En otras palabras, el operador FIRST k asocia a cada forma sentencial los primeros
k símbolos de cualquier forma terminal alcanzable desde α mediante derivaciones
“masa a izquierda".
Es una producción entonces, para todo i (con i variando desde 1 hasta k) tal que Y1
, Y2 , ..., Yi-1 sean todos no terminales y FIRST(Y1), FIRST(Y2), ..., FIRST(Yi-1)
contengan todos λ, se añaden todos los símbolos no nulos de FIRST(Yi ) a
FIRST(X). Finalmente, si λ está en FIRST (Yj) para j = 1, 2, ..., k (o sea, en todos),
entonces se añade λ a FIRST(X). Dicho de otra forma, lo anterior significa que todos
los elementos de FIRST (Y1), excepto λ, pertenecen también a FIRST(X). Si Y1 no
deriva λ, entonces ya ha terminado el cálculo de FIRST(X), pero en caso contrario,
es decir, si Y1= * => λ, entonces todos los elementos de FIRST (Y2) excepto λ
pertenecen también a FIRST(X), y así sucesivamente. Finalmente, si todos los Yi
derivan λ, entonces λ se añade a FIRST(X).
FOLLOW: Se define FOLLOW(A), para él no terminal A, como el conjunto de
terminales a que pueden aparecer inmediatamente a la derecha de A en alguna
forma sentencia, es decir, el conjunto de terminales a tal que haya una derivación
de la forma S= * =>αAaβ para algún α y β. Si A puede ser el símbolo de más a la
derecha en alguna forma sentencia, entonces $ está en FOLLOW(A).
2. Si existe una producción A → αBβ, entonces todo lo que esté en FIRST (β),
excepto λ, está en FOLLOW (B).
CARÁCTERISTICAS
El análisis sintáctico descendente (ASD) intenta encontrar entre las producciones de la gramática la
derivación por la izquierda del símbolo
Factorizar: Se trata de rescribir las producciones de la gramática con igual comienzo para retrasar la
decisión hasta haber visto lo suficiente de la entrada como para elegir la opción correcta.
EJEMPLO
Análisis Sintáctico Descendente Con Retroceso.
El método parte del axioma inicial y aplica todas las posibles reglas al no terminal más a la izquierda.
Se usa el retroceso para resolver la incertidumbre.
Sencillo de implementar.
Muy eficiente.
Tipos
Análisis ascendente con retroceso
Al igual que ocurría con el caso descendente, este tipo de análisis intenta probar todas las posibles
operaciones (reducciones y desplazamientos) mediante un método de fuerza bruta, hasta llegar al
árbol sintáctico, o bien agotar todas las opciones, en cuyo caso la cadena se rechaza.
En el análisis con retroceso no se permiten las reglas ԑ, puesto que estas se podrán aplicar de forma
indefinida.
El análisis ascendente sin retroceso busca una derivación derecha de la cadena de entrada de
forma determinista
La L viene de la lectura de la cadena de entrada de izquierda a derecha.
La R de producir un árbol de derivación derecho.
La k indica el número de símbolos que es necesario leer a la entrada para tomar la decisión de
qué producción emplear.
Un parser del tipo shift-reduce puede verse como un autómata de pila determinista extendido que
realiza el análisis de abajo hacia arriba.
Dada una cadena de entrada w, simula una derivación más a la derecha.
¿Cuál es su diferencia?
En el análisis sintáctico descendente: se construye el árbol sintáctico arriba hacia abajo y se utiliza
más reglas.
En el análisis sintáctico ascendente: se construye el árbol sintáctico de abajo hacia arriba, lo cual
disminuye el número de reglas mal aplicadas con respecto al caso descendente.
Otros
• Analizador sintáctico descendente recursivo
• Chart parser
• Left corner parser
• Analizador sintáctico LR
• Analizador sintáctico LL
Indicar los errores de forma clara y precisa. Debe informar mediante los
correspondientes mensajes del tipo de error y su localización
Recuperarse del error, para poder seguir examinando la entrada
Distinguir entre errores y advertencias. Las advertencias se suelen utilizar para
informar sobre sentencias válidas pero que, por ser poco frecuentes, pueden
constituir una fuente de errores lógicos
No ralentizar significativamente la compilación.
Un buen compilador debe conocer los errores que se pueden producir, con lo que
se consigue simplificar su estructura. Si el propio compilador está preparado para
admitir incluso los errores más frecuentes, entonces se puede mejorar la respuesta
ante esos errores incluso corrigiéndolos.
Transiciones de estado.
-V.- Crear y.output archivo, que contiene una descripción de las tablas de análisis
sintáctico y de los conflictos que surgen de las ambigüedades de la gramática.
-D.- Crea y.tab.h archivo, que contiene declaraciones #define que asocian yacc-
asignado códigos simbólicos `` 'con nombres de token-declarada por el usuario'.
Incluirlo en los archivos de base distintos de y.tab.c para dar acceso a los códigos
simbólicos.
-s stem .- y cambiar el prefijo de la y.tab.c nombres de archivo, y.tab.h, y.debug, y
y.output para frenar.
-S.- Escribir un analizador que utiliza Stdio en lugar de las rutinas de impresión en
libc.
El analizador acepta entrada de texto UTF (ver utf (6)), que tiene un par de efectos.
En primer lugar, el valor de retorno de yylex () ya no cabe en un corto; segundo, el
valor de partida para no terminales es ahora 0xe000 en lugar de 257.
El analizador generado puede ser recursiva: acciones pueden llamar a yyparse, por
ejemplo, para poner en práctica una especie de instrucción # include en un
intérprete.
YACC