Conferencia # 3
Gramáticas de Libre Contexto (GLC)
Sumario:
1. Introducción
2. Árbol de Derivación
3. Ambigüedad
Objetivos:
- Sistematizar el uso de las GLC como mecanismo de representación de lenguajes, enmarcado dentro del
esquema generador.
- Conocer el concepto de árbol de derivación y su relación con la secuencia de derivaciones para obtener
una sentencia.
- Aprender a usar los árboles de derivación como instrumento para demostrar la ambigüedad de una
gramática.
1. Introducción
La importancia de las Gramáticas de Libre Contexto (GLC) viene dada por el hecho de que las mismas se
utilizan para definir la sintaxis de la mayoría de los Lenguajes de Programación. Asimismo mas adelante
veremos que el problema del Análisis Sintáctico se reduce a encontrar el conjunto de derivaciones entre la
cadena y el axioma de la Gramática, la cual por tratarse de un Lenguaje de Programación será una GLC.
Las gramáticas constituyen la mejor vía para la descripción sintáctica de los lenguajes de programación. Existen
diversas razones que justifican tal afirmación:
- Las gramáticas brindan una especificación sintáctica precisa de los lenguajes de programación.
- Para ciertas clases de gramáticas pueden construirse analizadores sintácticos eficientes que determinan
si el programa fuente está bien escrito. El proceso de construcción del parser puede además, revelar
ambigüedades sintácticas no detectadas en la fase de diseño del lenguaje.
- Una gramática bien diseñada puede ayudar a la traducción del programa fuente en código objeto y a la
detección de errores.
- Nuevas construcciones pueden añadirse al lenguaje de forma fácil si este está descrito a través de una
gramática.
Ver por 4) p. 159
De las cuatro clases de gramáticas de la jerarquía de Chomsky, las GLC son las mas importantes desde el
punto de vista de la aplicación en los lenguajes de programación y compiladores. Una GLC puede ser utilizada
para especificar la estructura sintáctica de un lenguaje de programación y además constituye la base para los
diferentes esquemas de traducción.
Durante el proceso de compilación podemos utilizar la estructura sintáctica que una GLC le impone a un
programa para determinar su traducción. Utilizando las reglas sintácticas y la secuencia de producciones
usadas para derivar una cadena podemos obtener la estructura sintáctica de la cadena (o programa). O sea, el
analizador sintáctico de un compilador es un mecanismo que trata de determinar si una cadena puede ser
derivada a través de una GLC.
Ver en 4) p. 172-173: ER vs. GLC.
2. Árbol de Derivación
Como hemos visto, es posible encontrar múltiples derivaciones “diferentes” para una misma sentencia, esta
diversidad está estrechamente relacionada con todos los posibles ordenes diferentes en que se vayan
construyendo las diferentes formas sentenciales. Es importante conocer cuando dos derivaciones diferentes son
equivalentes. De aquí surge la necesidad de definir un instrumento que nos permita representar en forma
integrada todas las derivaciones diferentes para una misma sentencia. Además, hemos definido al parser como
un algoritmo que responde si una cadena de entrada es una sentencia válida del lenguaje o no, y construye
adicionalmente la estructura sintáctica de dicha cadena, en caso de ser correcta.
El concepto de árbol de derivación surge como solución a las dos problemáticas anteriores: sirve para
representar la estructura sintáctica de una sentencia del lenguaje, y unifica en una sola representación todas las
derivaciones posibles para obtener dicha sentencia.
Definición (Árbol de Derivación): Un árbol de derivación en una gramática de libre contexto G = (N, , P, S)
es un árbol ordenado y etiquetado en el cual cada nodo tiene como etiqueta un símbolo de N {}, y
cumple que: si un nodo interior tiene etiqueta A y sus descendentes directos tienen etiquetas X 1 X2 ... Xn,
entonces A X1 X2 ... Xn es una regla de producción en G.
Un árbol D es un árbol de derivación en una gramática G = (N, , P, S ) si:
1. La raíz de D es S.
2. Si D1, D2, ... Dk son los subarboles descendentes directamente de un nodo con etiqueta A, y la raíz de D i es
Xi, para todo i desde 1 hasta k, entonces A X1 X2 ... Xk P.
Ejemplo:
Sea la Gramática G(S) = ( {S}, {a, b}, P, S) donde P se define como:
P: S aSbS | bSaS |
Entonces:
S S S
a S b S
b S a S
Representan tres árboles diferentes.
Nótese cómo diferentes derivaciones poseen el mismo árbol (tercer árbol anterior):
S aSbS abSaSbS abaSbS ababS abab
S aSbS aSb abSaSb abSab abab
Se asume como orden entre los nodos de un árbol de derivación aquel que resulta tomando las hojas desde la
izquierda, sobre la base de asumir que si un nodo se encuentra a la derecha de otro nodo, sus descendientes
también lo están. Evidentemente se tiene que dos nodos diferentes están en un mismo camino o uno es anterior
al otro.
Definición (Frontera): La frontera de un árbol de derivación es la cadena que se obtiene concatenando las
hojas del árbol de derivación en orden.
En virtud de la definición anterior podemos establecer el siguiente resultado: Si es una forma sentencial final
de una gramática G de libre contexto, entonces existe un árbol de derivación con frontera .
Definición (Corte): Sea D un árbol de derivación de una Gramática Libre de Contexto. Un corte de D es un
conjunto C de nodos tales que:
1. No existen dos nodos de C en el mismo camino.
2. No puede añadirse un nodo mas a C sin violar 1.
Definición (Frontera interior): Una frontera interior de un árbol D es la cadena que se obtiene concatenando
por su orden los nodos de un corte.
Ejemplos:
S
a S b S
b S a S
abSabS
(a): Corte de un árbol de (b): Frontera interior correspondiente
derivación al corte de (a)
Relación entre los árboles sintácticos y las derivaciones
Los árboles de derivación son una vía adecuada para representar las derivaciones en una gramática. Cada
derivación de una forma sentencial tiene un árbol con frontera .
Podemos, por lo tanto, ver los árboles de derivación como una representación gráfica de una secuencia de
derivaciones en la que se pierde el orden en que se hacen las sustituciones. Así, por ejemplo, para la gramática
E E+E | E*E | (E) | a (3.1)
podemos encontrar dos secuencias de derivaciones distintas para la sentencia a+a:
EE+Ea+Ea+a
EE+EE+aa+a
Sin embargo, el árbol de derivación para ambas derivaciones es el mismo:
E
E + E
a a
Definición (Derivación más a la izquierda): Si en el proceso de obtención de las derivaciones S=0, 1, ...n
siempre se reemplaza el no terminal mas a la izquierda en cada derivación, entonces la derivación se denomina
Derivación mas a la Izquierda (DMI) (LMD), y se denota como:
S *LM n LM Left most
Análogamente se puede definir la Derivación mas a la Derecha, la cual se denota como:
S *RM n RM Right most
Las variaciones en el orden en que se aplican las producciones podemos eliminarlas si consideramos
solamente las derivaciones mas a la izquierda (o mas a la derecha). No es difícil comprobar que cada árbol
sintáctico está asociado con una única derivación mas a la izquierda y una única derivación mas a la derecha.
Sin embargo, no debemos asumir que para una sentencia dada existe un único árbol sintáctico o una única
derivación mas a la izquierda o mas a la derecha.
Ejemplo: Para la gramática (3.1) existen dos derivaciones mas a la izquierda diferentes para la sentencia
a+a*a:
E E+E a+E a+E*E a+a*E a+a*a
E E*E E+E*E a+E*E a+a*E a+a*a
con sus dos árboles sintácticos correspondientes:
E
E * E
E + E a
a a
(a) (b)
Fig. 1. Dos árboles sintácticos para la sentencia a+a*a.
Nótese que el árbol sintáctico de la figura (a) refleja la precedencia usual de los operadores + y *, mientras que
el de la figura (b), no. Esto es, es normal que el operador * tenga mayor prioridad que +, de forma que podamos
evaluar normalmente la expresión a+b*c como a+(b*c) y no como (a+b)*c.
Es posible demostrar que si S = 01...n son derivaciones desde el axioma S hasta una sentencia de una GLC,
entonces existe un árbol de derivación D en dicha gramática, en el cual 0, 1...n-1 son fronteras interiores y n
es la frontera.
Análogamente podemos afirmar que si en el árbol de derivación D asociado a una GLC G, con frontera ,
entonces
S *G
3. Ambigüedad
Definición (Gramática ambigua): Se dice que una gramática de libre contexto es ambigua, si para al menos
una sentencia existe mas de un árbol de derivación.
O sea, que una gramática ambigua es aquella que produce mas de una derivación mas a la izquierda o mas de
una derivación mas a la derecha para la misma sentencia. Para ciertos tipos de analizadores sintácticos es
necesario que la gramática no sea ambigua, porque en caso de serlo no pueden determinar cuál árbol sintáctico
construir para la sentencia.
En algunos casos es posible trabajar con gramáticas ambiguas conjuntamente con reglas que eliminan la
ambigüedad, o sea, reglas que nos permiten desechar los árboles sintácticos incorrectos y quedarnos
solamente con el correcto.
Ejemplo: Sea la gramática G = ({E, T}, {a, *, +, (, )}, P, S) donde P se define como:
P: E E+E | E*E | T
T (E) | a
Ejercicio propuesto: Obtener al menos dos árboles de derivación para la sentencia a+a*a