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 q, se produce la reducción de w a u1Av – si u=u1q y A – 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 cada variable A∈ V © Manuel Mucientes wi) particionan LAk(A) para 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 LAk(uAv, A w)=FIRSTk(wv) w es • 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 © Manuel Mucientes w)=trunck(FIRSTk(w1)...FIRSTk(wn)FIRSTk(v1)...FIRSTk(vm)) 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