You are on page 1of 36

Tema 6:

Compiladores e intérpretes

Teoría de autómatas y lenguajes formales I


Bibliografía

• Sudkamp, T. A. “Languages and machines: an


introduction to the theory of computer science”.  
Addison Wesley. 1997.
– capítulos 4, 15 y 16
• Aho A., Sethi R. and Ullman J. “Compiladores. 
Principios, técnicas y herramientas”. Addison‐
Wesley. 1990. 
– capítulo 1

© Manuel Mucientes Tema 6: Compiladores e intérpretes 2


Introducción
• Un compilador es un programa que lee un programa escrito en
un lenguaje (fuente) y lo traduce a un programa equivalente en
otro lenguaje (objeto)

• El primer compilador FORTRAN necesitó de 18 años de trabajo


para su implantación
• Hoy en día existen técnicas sistemáticas para manejar muchas
de las tareas que surgen en la compilación, y herramientas
software que facilitan el diseño

© Manuel Mucientes Tema 6: Compiladores e intérpretes 3


Sistema para procesamiento de un lenguaje

© Manuel Mucientes Tema 6: Compiladores e intérpretes 4


Fases de un compilador

© Manuel Mucientes Tema 6: Compiladores e intérpretes 5


Traducción de una proposición

© Manuel Mucientes Tema 6: Compiladores e intérpretes 6


Análisis sintáctico
• Tres tipos generales de analizadores sintácticos

– métodos universales de análisis sintáctico


• algoritmos de Cocke-Younger-Kasami y de Early

– descendentes
• construyen árboles de análisis sintáctico desde arriba (raíz) hasta abajo
(hojas)

– ascendentes

© Manuel Mucientes Tema 6: Compiladores e intérpretes 7


Análisis descendente en anchura

© Manuel Mucientes Tema 6: Compiladores e intérpretes 8


Análisis descendente en anchura
• Se obtiene una derivación si la entrada pertenece al lenguaje
• Puede no ser capaz de determinar si una cadena no está en el lenguaje
– camino infinito: recursividad por la izquierda
– solución: conocer la longitud de la cadena
• para ello son necesarios analizadores de varias pasadas
• Implementación práctica: crecimiento exponencial del árbol

© Manuel Mucientes Tema 6: Compiladores e intérpretes 9


Análisis descendente en profundidad

© Manuel Mucientes Tema 6: Compiladores e intérpretes 10


Análisis descendente en profundidad (II)
• No está garantizado que se encuentre una derivación para
todas las cadenas del lenguaje
– se puede entrar en caminos infinitos
• Ejemplo: cadena de entrada (b) + b

© Manuel Mucientes Tema 6: Compiladores e intérpretes 11


Análisis ascendente
• Se construirán las derivaciones más a la derecha
• Reducción: dada w=u1qu2, y A q, entonces v=u1Au2
• Ejemplo: reducción de la cadena (b) + b a S

• Generación de todas las posibles reducciones de una cadena


– w=uv
– si u=u1q y A q, se produce la reducción de w a u1Av
– hay que probar con todas las posibles combinaciones de u y v

© Manuel Mucientes Tema 6: Compiladores e intérpretes 12


Análisis ascendente en anchura

• Si la cadena forma parte del lenguaje, siempre se encontrará su derivación más a la derecha
• Para gramáticas cuyas reglas tengan todas una longitud de su parte derecha mayor que 1, está
garantizado que la longitud del árbol no puede exceder la de la cadena, asegurando la terminación
del análisis con una derivación o un fallo

© Manuel Mucientes Tema 6: Compiladores e intérpretes 13


Análisis ascendente en profundidad

• En la pila se almacena [u, i, v], donde uv es la forma sentencial que se va a


reducir, e i el identificador de la regla usada en la reducción
• El axioma de la gramática debe ser no recursivo
– cualquier GIC se puede transformar a una equivalente con axioma no recursivo
– otra posibilidad es eliminar la condición que restringe las reducciones con S, y
cambiar la condición de finalización del lazo desde (u=S) a (u=S y v=λ)
© Manuel Mucientes Tema 6: Compiladores e intérpretes 14
Análisis ascendente en profundidad (II)
• Ejemplo: construir la derivación para (b + b) para la gramática AE

© Manuel Mucientes Tema 6: Compiladores e intérpretes 15


Predicción en analizadores descendentes
• Construcción de la derivación más a la izquierda para p
– las derivaciones serán de la forma S * uAv
• u es el prefijo de p
– analizando lo que resta de cadena de entrada se puede reducir el
número de reglas de A que es necesario examinar
• Se asumirá que las gramáticas no tienen símbolos inútiles
• Ejemplo: derivación de la cadena acbb para la gramática

© Manuel Mucientes Tema 6: Compiladores e intérpretes 16


Predicción en analizadores descendentes (II)
• Sea G = (V, Σ, P, S) una GIC, y A∈ V
– conjunto predictivo de la variable A: LA( A) = {x | S →* uAv →* ux ∈ Σ*}
– conjunto predictivo de la regla A w:
LA( A → w) = {x | wv →* x ∈ Σ* , donde S →* uAv}
• Los conjuntos LA(A wi) satisfacen:
n
– LA( A) = U LA( A → wi )
i =1
• para cualquier GIC
– LA( A → wi ) ∩ LA( A → w j ) = ∅ para todo 1 <= i <= j <= n
• para una GIC fuertemente LL(k)
• Ejemplo: cadena ab: predicción de tres símbolos

© Manuel Mucientes Tema 6: Compiladores e intérpretes 17


Predicción en analizadores descendentes (III)
• Ejemplo: cadena abc: predicción de cuatro símbolos

© Manuel Mucientes Tema 6: Compiladores e intérpretes 18


Predicción en analizadores descendentes (IV)
• Sea G = (V, Σ, P, S) una GIC, y k>0 un número natural
– trunck ( X ) = {u | u ∈ X con u ≤ k , o uv ∈ X con u = k}
– LAk(A) = trunck(LA(A))
– LAk(A w) = trunck(LA(A w))

• Ejemplo: conjuntos predictivos de longitud 3

© Manuel Mucientes Tema 6: Compiladores e intérpretes 19


FIRST
• Sea G una GIC. Para cada cadena u ∈ (V ∪ Σ)* y k>0
– FIRSTk (u ) = trunck ({x | u →* x, u ∈ Σ*})
• Ejemplo:

• Para cada k>0,


– FIRSTk(λ) = {λ}
– FIRSTk(a) = {a}
– FIRSTk (au ) = {av | v ∈ FIRSTk −1 (u )}
– FIRSTk(uv) = trunck(FIRSTk(u) FIRSTk(v))
– si A w es una regla de G, entonces FIRSTk ( w) ⊆ FIRSTk ( A)

© Manuel Mucientes Tema 6: Compiladores e intérpretes 20


FOLLOW
• Sea G una GIC. Para cada variable A∈ V y k>0
– FOLLOWk ( A) = trunck ({x | S → uAv, y x ∈ FIRSTk (v)})
*

• Ejemplo:

• Para todo k>0, FOLLOWk(S) contiene λ (S es el axioma de


G)

© Manuel Mucientes Tema 6: Compiladores e intérpretes 21


Conjunto predictivo
• Sea G una GIC. Para todo k>0, A∈ V y regla A u1u2 . . . un
– LAk(A) = trunck(FIRSTk(A) FOLLOWk(A))
– LAk(A w) = trunck(FIRSTk(w)FOLLOWk(A)) =
trunck(FIRSTk(u1)...FIRSTk(un)FOLLOWk(A))
• Ejemplo:

© Manuel Mucientes Tema 6: Compiladores e intérpretes 22


Gramáticas fuertemente LL(k)
• Las gramáticas fuertemente LL(k) (Left –la cadena se lee de
izqda. a dcha.- Left –derivación más a la izqda.-) garantizan
que los conjuntos predictivos LAk(A) están particionados por los
conjuntos LAk(A wi) para cada variable A∈ V
• Cuando se predice con k símbolos, es útil concatenar un
marcador de final de cadena, #k, al final de cada cadena del
lenguaje
– si S (axioma) es no recursivo, se añade #k al final de cada regla de S
– en caso contrario, se crea un nuevo axioma S’ y la regla S’ S#k
• Sea G una GIC con marcador final #k. G es fuertemente LL(k)
si siempre que existan dos derivaciones más a la izquierda
– S * u1Av1 * u1xv1 * u1zw1
– S * u2Av2 * u2yv2 * u2zw2
– donde ui, wi, z ∈ Σ* y |z|=k. Entonces x = y

© Manuel Mucientes Tema 6: Compiladores e intérpretes 23


Construcción de FIRSTk

• Ejemplo: First2

© Manuel Mucientes Tema 6: Compiladores e intérpretes 24


Construcción de FOLLOWk
Para A u1 ... un

FL(ui) = FL(ui) U trunck { Firstk (ui+1) ...


Firstk (un) FL´(A) }

• Ejemplo:

© Manuel Mucientes Tema 6: Compiladores e intérpretes 25


Un ejemplo
• Ejemplo: conjuntos predictivos de longitud 2 para la
gramática

– LAk(A w) = trunck(FIRSTk(u1)...FIRSTk(un)FOLLOWk(A))

• G es fuertemente LL(2), pues los conjuntos LAk(A wi) particionan LAk(A) para
cada variable A∈ V
© Manuel Mucientes Tema 6: Compiladores e intérpretes 26
Una gramática fuertemente LL(1)

© Manuel Mucientes Tema 6: Compiladores e intérpretes 27


Analizador fuertemente LL(k)

• Ejemplo: análisis de la cadena (b + b)# para la siguiente


gramática fuertemente LL(1)

© Manuel Mucientes Tema 6: Compiladores e intérpretes 28


Gramáticas LL(k)
• Sea G una GIC con marcador final #k. G es LL(k) si siempre
que existan dos derivaciones más a la izquierda
– S * uAv * uxv * uzw1
– S * uAv * uyv * uzw2
– donde ui, wi, z ∈ Σ* y |z|=k. Entonces x = y
• Las gramáticas fuertemente LL(k) requieren que exista una
única regla de A que pueda derivar la cadena predictiva z
desde cualquier forma sentencial que contenga A
• Las gramáticas LL(k) sólo requieren que la regla sea única
para una forma sentencial dada, uAv

© Manuel Mucientes Tema 6: Compiladores e intérpretes 29


Gramáticas LL(k) (II)
• Sea G una GIC, y uAv una forma sentencial de G
– el conjunto predictivo de la forma sentencial uAv es
LAk(uAv)=FIRSTk(Av)
– el conjunto predictivo de la forma sentencial uAv y la regla A w es
LAk(uAv, A w)=FIRSTk(wv)
• Para seleccionar de forma única una regla para la forma
sentencial uAv , el conjunto LAk(uAv) debe estar particionado
por los conjuntos LAk(uAv, A wi)
– si la gramática es fuertemente LL(k), esto está garantizado y la
gramática también será LL(k)

© Manuel Mucientes Tema 6: Compiladores e intérpretes 30


Gramáticas LL(k) (III)
• Ejemplo: una gramática LL(k) no necesita ser fuertemente
LL(k)

– es fuertemente LL(3), es LL(2), pero no fuertemente LL(2)


• Ejemplo: la siguiente gramática es LL(3), pero no es
fuertemente LL(k) para ningún k

© Manuel Mucientes Tema 6: Compiladores e intérpretes 31


Gramáticas LL(k) (IV)
• El análisis determinístico con gramáticas LL(k) requiere la
construcción de los conjuntos predictivos para las formas
sentenciales generadas durante el análisis
• LAk(uAv, A w) donde w=w1 ... wn y v=v1 ... vm será:
– LAk(uAv, A w)=trunck(FIRSTk(w1)...FIRSTk(wn)FIRSTk(v1)...FIRSTk(vm))

© Manuel Mucientes Tema 6: Compiladores e intérpretes 32


Gramáticas LR(k)
• Analizadores ascendentes

• LR
– left: se lee la cadena de entrada de izquierda a derecha
– right: se selecciona la derivación más a la derecha

• Un analizador ascendente determinista trata de reducir la


cadena de entrada al símbolo inicial de la gramática

© Manuel Mucientes Tema 6: Compiladores e intérpretes 33


Problemas finales
• Dada la gramática G=({a, b}, {S, A, B}, P, S), donde P viene
dada por:
• S→C
• C → aC | AB | B
• A → abA | ab
• B → ba | BB
– Obtener el árbol de derivación para el análisis descendente en
profundidad con la cadena “aababa”. Mostrar la configuración del
árbol y de la pila en cada instante.
– ¿Es la gramática fuertemente LL(2)? Para probarlo es obligatorio
construir los conjuntos FIRST y FOLLOW (para todas las variables).

© Manuel Mucientes Tema 6: Compiladores e intérpretes 34


Problemas finales (II)
• Dada la gramática G=({a, b}, {S, A, B}, P, S), donde P viene
dada por:
• S → aAbB | bAbB
• A → ab | a
• B → aB | b
– Obtener el árbol de derivación para el análisis descendente en
profundidad con la cadena “babab”. Mostrar la configuración del
árbol y de la pila en cada instante.
– ¿Es la gramática fuertemente LL(2)? Para probarlo es obligatorio
construir los conjuntos FIRST y FOLLOW (para todas las variables).

© Manuel Mucientes Tema 6: Compiladores e intérpretes 35


Problemas finales (III)
• El lenguaje {aiabci | i > 0} es generado por las gramáticas:

– Construir los conjuntos FIRST y FOLLOW de todas las variables, así


como los conjuntos predictivos para cada una de las reglas.
– Determinar cuántos símbolos son necesarios para realizar la
predicción en cada una de las variables.
– Estimar si la gramática es fuertemente LL(k) para algún valor de k.

© Manuel Mucientes Tema 6: Compiladores e intérpretes 36