TRADUCTORES E INTERPRETADORES Clase 11: Analizadores Sintácticos Descendentes
Agenda Analizadores Recursivos Descendentes. Análisis Predictivo. Analizadores LL(1). Analizadores LL(k) y LL(*).
Analizadores Recursivos Descendentes Recordemos los árboles de derivación de una gramática. Cuántos árboles de derivación diferentes puede tener una frase?
Analizadores Recursivos Descendentes Recordemos los árboles de derivación de una gramática. Cuántos árboles de derivación diferentes puede tener una frase? Qué ocurría cuando había mas de una?
Analizadores Recursivos Descendentes Recordemos los árboles de derivación de una gramática. Cuántos árboles de derivación diferentes puede tener una frase? Qué ocurría cuando había mas de una? Ambigüedad!
Analizadores Recursivos Descendentes Recordemos los árboles de derivación de una gramática. Cuántos árboles de derivación diferentes puede tener una frase? Qué ocurría cuando había mas de una? Ambigüedad! En que orden expandimos los símbolos noterminales?
Analizadores Recursivos Descendentes Recordemos los árboles de derivación de una gramática. Cuántos árboles de derivación diferentes puede tener una frase? Qué ocurría cuando había mas de una? Ambigüedad! En que orden expandimos los símbolos noterminales? Realmente importa?
Analizadores Recursivos Descendentes Si siempre escogemos el símbolo no-terminal mas derecho, tendremos una derivación más derecha.
Analizadores Recursivos Descendentes Si siempre escogemos el símbolo no-terminal mas derecho, tendremos una derivación más derecha. Si siempre escogemos el símbolo no-terminal mas izquierdo, tendremos una derivación más izquierda.
Analizadores Recursivos Descendentes Si siempre escogemos el símbolo no-terminal mas derecho, tendremos una derivación más derecha. Si siempre escogemos el símbolo no-terminal mas izquierdo, tendremos una derivación más izquierda. Y estas son las que nos interesan en esta ocasión.
Analizadores Recursivos Descendentes Cómo podemos construir un reconocedor para frases, dada una Gramática Libre de Contexto?
Analizadores Recursivos Descendentes Cómo podemos construir un reconocedor para frases, dada una Gramática Libre de Contexto? Una forma es realizando la traducción explícitamente a un Autómata de Pila.
Analizadores Recursivos Descendentes Cómo podemos construir un reconocedor para frases, dada una Gramática Libre de Contexto? Una forma es realizando la traducción explícitamente a un Autómata de Pila. Otra forma es a través de un Analizador Recursivo Descendente.
Analizadores Recursivos Descendentes Cómo podemos construir un reconocedor para frases, dada una Gramática Libre de Contexto? Una forma es realizando la traducción explícitamente a un Autómata de Pila. Otra forma es a través de un Analizador Recursivo Descendente. La clave está en ver cada símbolo no terminal como una función que: Recibe una frase. Intenta reconocer un prefijo de la frase. Devuelve el residual (sobrante) de la frase.
Analizadores Recursivos Descendentes Ejemplo: E E E E * E ( E) c
Analizadores Recursivos Descendentes Ejemplo: String E (String frase) { String tmp; E E E E * E ( E) c if (match(frase[0], ( )) tmp = E(frase.substring(1)); if (match(tmp[0], ) )) return tmp.substring(1); if (match(tmp[0], c )) return temp.substring(1); tmp = E(frase); if (match(tmp[0], + )) return E(tmp.substring(1)); else if (match(tmp[0], * )) return E(tmp.substring(1)); EN JAVA } errorhandler();
Analizadores Recursivos Descendentes Ejemplo: String E (String frase) { String tmp; E E E * E ( E) c E Qué problema tiene la función E? } if (match(frase[0], ( )) tmp = E(frase.substring(1)); if (match(tmp[0], ) )) return tmp.substring(1); if (match(tmp[0], c )) return temp.substring(1); tmp = E(frase); if (match(tmp[0], + )) return E(tmp.substring(1)); else if (match(tmp[0], * )) return E(tmp.substring(1)); errorhandler(); EN JAVA
Analizadores Recursivos Descendentes Para poder implementar un buen Analizador Recursivo Descendente, debe pedirse que la gramática no tenga recursión izquierda.
Analizadores Recursivos Descendentes Para poder implementar un buen Analizador Recursivo Descendente, debe pedirse que la gramática no tenga recursión izquierda. Siempre se puede llevar una Gramática Libre de Contexto a una equivalente, pero sin recursión izquierda?
Analizadores Recursivos Descendentes A Para poder implementar un buen Analizador Recursivo Descendente, debe pedirse que la gramática no tenga recursión izquierda. Siempre se puede llevar una Gramática Libre de Contexto a una equivalente, pero sin recursión izquierda? Si! A... 1 A... 1 m n A A'... 1 A' A' A'... A' 1 m n
Analizadores Recursivos Descendentes Para poder implementar un buen Analizador Recursivo Descendente, debe pedirse que la gramática no tenga recursión izquierda. Siempre se puede llevar una Gramática Libre de Contexto a una equivalente, pero sin recursión izquierda? Si! Y si le recursión es indirecta?
Analizadores Recursivos Descendentes Para poder implementar un buen Analizador Recursivo Descendente, debe pedirse que la gramática no tenga recursión izquierda. Siempre se puede llevar una Gramática Libre de Contexto a una equivalente, pero sin recursión izquierda? Si! Y si le recursión es indirecta? Les queda como ejercicio.
Análisis Predictivo Los Analizadores Recursivos Descendentes son fáciles de implementar. Sin embargo, pueden ser ineficientes.
Análisis Predictivo Los Analizadores Recursivos Descendentes son fáciles de implementar. Sin embargo, pueden ser ineficientes. Posiblemente tienen que realizar backtracking.
Análisis Predictivo Los Analizadores Recursivos Descendentes son fáciles de implementar. Sin embargo, pueden ser ineficientes. Posiblemente tienen que realizar backtracking. Y si pudiéramos usar algún tipo de información adicional que permita eliminar la posibilidad de backtracking? Aquí entra el análisis predictivo.
Análisis Predictivo La idea poder ver algunos símbolos de la frase por adelantado, para ayudar a tomar una decisión al analizador sobre el camino a tomar.
Análisis Predictivo La idea poder ver algunos símbolos de la frase por adelantado, para ayudar a tomar una decisión al analizador sobre el camino a tomar. A estos adelantos, les llamaremos Look-ahead s. Cada regla de la Gramática tendrá uno.
Análisis Predictivo La idea poder ver algunos símbolos de la frase por adelantado, para ayudar a tomar una decisión al analizador sobre el camino a tomar. A estos adelantos, les llamaremos Look-ahead s. Cada regla de la Gramática tendrá uno. Se definirán a partir de dos conjuntos especiales para cada símbolo: FIRST k : Primeros k símbolos terminales que puede generar el símbolo. FOLLOW k : Primeros k símbolos terminales que pueden generarse, una vez se haya terminado de expandir el símbolo en cuestión.
Análisis Predictivo FIRST: ( a : a : FIRST ( a) { a}) ( A : A P : FIRST k k ( A)) ( A, Y 1... Ym : A Y 1... Ym P : trunck ( FIRST k ( Y1 )... FIRST k ( Ym )) FIRST ( A))
Análisis Predictivo FIRST: FOLLOW: )) ( ) ( : ) ( ) (, :,,, ( )) ( ) ( : ) (, :,,, ( ) ( $ * * B FOLLOW A FOLLOW P B A FIRST V V B B A B FOLLOW FIRST P B A V V B B A S FOLLOW k k k k )) ( )) ( )... ( ( :... :..., ( )) ( : : ( }) { ) ( : : ( 1 1 1 A FIRST Y FIRST Y FIRST trunc P Y Y A Y A Y A FIRST P A A a a FIRST a a m k k k m m k k
Análisis Predictivo Look-ahead: ( A, : ( V ) LookAhead k * A P : ( A ) trunc k ( FIRST k ( ). FOLLOW k ( A)))
Analizadores LL(1) Con un look-ahead de tamaño k podemos saber que frases de tamaño k espera una regla para usarla.
Analizadores LL(1) Con un look-ahead de tamaño k podemos saber que frases de tamaño k espera una regla para usarla. Vamos a usar los look-ahead para construir un autómata que realice el reconocimiento de manera eficiente
Analizadores LL(1) Con un look-ahead de tamaño k podemos saber que frases de tamaño k espera una regla para usarla. Vamos a usar los look-ahead para construir un autómata que realice el reconocimiento de manera eficiente Y es determinista!
Analizadores LL(1) La idea del analizador LL(k) es: Construir un reconocedor descendente.
Analizadores LL(1) La idea del analizador LL(k) es: Construir un reconocedor descendente. Tanto con los siguientes k símbolos como con LookAhead k, determinar la regla a tomar en cada paso.
Analizadores LL(1) La idea del analizador LL(k) es: Construir un reconocedor descendente. Tanto con los siguientes k símbolos como con LookAhead k, determinar la regla a tomar en cada paso. Antes que nada, limitaremos en 1 la cantidad de caracteres a leer.
Analizadores LL(1) La idea del analizador LL(k) es: Construir un reconocedor descendente. Tanto con los siguientes k símbolos como con LookAhead k, determinar la regla a tomar en cada paso. Antes que nada, limitaremos en 1 la cantidad de caracteres a leer. Luego veremos el impacto que acarrea el caso general.
Analizadores LL(1) Cómo construir un analizador LL(1)? Necesitaremos construir el mecanismo de predicción. Para eso usaremos una tabla, llamada reglas. Las filas corresponderán a símbolos no terminales. Las columnas corresponderán a símbolos terminales.
Analizadores LL(1) Cómo construir un analizador LL(1)? A Dada una regla de la forma : Queremos saber que reglas aplicar dado el inicio de la entrada. ( a : afirst 1( ): reglas [ A, a] A )
Analizadores LL(1) Cómo construir un analizador LL(1)? A Dada una regla de la forma : Ahora, si FIRST 1 ( ), usaremos los símbolos que siguen a α. ( b : FIRST 1( ) b FOLLOW1 ( ) : reglas [ A, b] A )
Analizadores LL(1) Cómo construir un analizador LL(1)? A Dada una regla de la forma : Ahora, si FIRST 1 ( ), usaremos los símbolos que siguen a α. ( b : FIRST 1( ) b FOLLOW1 ( ) : reglas [ A, b] A ) Y $?
Analizadores LL(1) Cómo construir un analizador LL(1)? A Dada una regla de la forma : Ahora, si FIRST 1 ( ), usaremos los símbolos que siguen a α. ( b {$}: FIRST 1( ) b FOLLOW1 ( ) : reglas [ A, b] A )
Analizadores LL(1) Cómo construir un analizador LL(1)? A Dada una regla de la forma : Ahora, si FIRST 1 ( ), usaremos los símbolos que siguen a α. ( b {$}: FIRST 1( ) b FOLLOW1 ( ) : reglas [ A, b] A ) MUCHO MEJOR!
Analizadores LL(1) Aplicando esos pasos, se construye lo que es la tabla de reconocimiento LL(1).
Analizadores LL(1) Aplicando esos pasos, se construye lo que es la tabla de reconocimiento LL(1). Lo único que falta es... cómo usar la tabla para poder reconocer una frase?
Analizadores LL(1) Un analizador LL(1) está compuesto por: Una pila que contendrá símbolos de la gramática.
Analizadores LL(1) Un analizador LL(1) está compuesto por: Una pila que contendrá símbolos de la gramática. El sufijo de la frase original que queda por leer.
Analizadores LL(1) Un analizador LL(1) está compuesto por: Una pila que contendrá símbolos de la gramática. El sufijo de la frase original que queda por leer. La tabla de reconocimiento construida en el paso anterior.
Analizadores LL(1) Un analizador LL(1) está compuesto por: Una pila que contendrá símbolos de la gramática. El sufijo de la frase original que queda por leer. La tabla de reconocimiento construida en el paso anterior. Un mecanismo de salida, que imprima que producción se aplicó en el paso correspondiente.
Analizadores LL(1) La máquina comenzará con la siguiente configuración: La máquina comienza con el símbolo inicial de la gramática empilada. Se comienza con la frase completa.
Analizadores LL(1) La máquina comenzará con la siguiente configuración: La máquina comienza con el símbolo inicial de la gramática empilada. Se comienza con la frase completa. A RECONOCERRRRRRRRR!
Analizadores LL(1) Considere X como el tope de la pila y a el símbolo inicial de la frase. Si X es un símbolo no terminal, se consulta la casilla reglas[x,a].
Analizadores LL(1) Considere X como el tope de la pila y a el símbolo inicial de la frase. Si X es un símbolo no terminal, se consulta la casilla reglas[x,a]. Si hay una regla, X Y Y, entonces: Se desempila X. 1` 2 Se empila Y n Y 2 Y 1, tal que Y 1 quede en el tope de la pila. Y n Se imprime la producción resultante.
Analizadores LL(1) Considere X como el tope de la pila y a el símbolo inicial de la frase. Si X es un símbolo no terminal, se consulta la casilla reglas[x,a]. Si hay una regla, X Y Y, entonces: Se desempila X. 1` 2 Se empila Y n Y 2 Y 1, tal que Y 1 quede en el tope de la pila. Se imprime la producción resultante. Si no, se tranca la máquina rechazando la palabra. Y n
Analizadores LL(1) Considere X como el tope de la pila y a el símbolo inicial de la frase. Si X = a, el símbolo del tope de la pila coincide con el elemento apuntado, por lo que se desempila X y se consume un símbolo de la entrada. Si X = $ y a =, se detiene la máquina, aceptando la frase.
Analizadores LL(k) y LL(*) Observe que, aunque el uso de FIRST 1 y FOLLOW 1 está explícito en las láminas anteriores, es equivalente a usar LookAhead 1.
Analizadores LL(k) y LL(*) Observe que, aunque el uso de FIRST 1 y FOLLOW 1 está explícito en las láminas anteriores, es equivalente a usar LookAhead 1. Ahora, considere el caso general. Cómo funcionaría?
Analizadores LL(k) y LL(*) Observe que, aunque el uso de FIRST 1 y FOLLOW 1 está explícito en las láminas anteriores, es equivalente a usar LookAhead 1. Ahora, considere el caso general. Cómo funcionaría? Tomaría la decisión con los k primeros símbolos de lo que queda de entrada, considerando LookAhead k.
Analizadores LL(k) y LL(*) Observe que, aunque el uso de FIRST 1 y FOLLOW 1 está explícito en las láminas anteriores, es equivalente a usar LookAhead 1. Ahora, considere el caso general. Cómo funcionaría? Tomaría la decisión con los k primeros símbolos de lo que queda de entrada, considerando LookAhead k. Tiene sentido hablar de un analizador LL(0)?
Analizadores LL(k) y LL(*) Ahora, considere el caso general. Tomaría la decisión con los k primeros símbolos de lo que queda de entrada, considerando LookAhead k. Cómo sería el tamaño de la tabla de reconocimiento?
Analizadores LL(k) y LL(*) Ahora, considere el caso general. Tomaría la decisión con los k primeros símbolos de lo que queda de entrada, considerando LookAhead k. Cómo sería el tamaño de la tabla de reconocimiento? Explosión exponencial de espacio!
Analizadores LL(k) y LL(*) Ahora, considere el caso general. Tomaría la decisión con los k primeros símbolos de lo que queda de entrada, considerando LookAhead k. Cómo sería el tamaño de la tabla de reconocimiento? Explosión exponencial de espacio! Y cómo marcarían el final de la entrada?
Analizadores LL(k) y LL(*) Será que toda gramática genera un lenguaje LL(1)?
Analizadores LL(k) y LL(*) Será que toda gramática genera un lenguaje LL(1)? Y uno LL(k)?
Analizadores LL(k) y LL(*) Será que toda gramática genera un lenguaje LL(1)? Y uno LL(k)? Una gramática no es LL(k) si presenta algún conflicto.
Analizadores LL(k) y LL(*) Un conflicto en una gramática LL(k) surge cuando existen dos reglas con mismo símbolo no terminal a izquierda que compartan algún elemento en sus look-ahead.
Analizadores LL(k) y LL(*) Un conflicto en una gramática LL(k) surge cuando existen dos reglas con mismo símbolo no terminal a izquierda que compartan algún elemento en sus look-ahead. Aumentando la k, se puede solventar el conflicto.
Analizadores LL(k) y LL(*) Un conflicto en una gramática LL(k) surge cuando existen dos reglas con mismo símbolo no terminal a izquierda que compartan algún elemento en sus look-ahead. Aumentando la k, se puede solventar el conflicto. PERO NO ES SEGURO!
Analizadores LL(k) y LL(*) No todas las gramáticas pueden ser LL(k) para cualquier k. Las que si lo son, tienen un k mínimo que garantiza que la gramática sea LL.
Analizadores LL(k) y LL(*) No todas las gramáticas pueden ser LL(k) para cualquier k. Las que si lo son, tienen un k mínimo que garantiza que la gramática sea LL. pero el caso que se necesiten los k símbolos en el look-ahead ocurre poco!
Analizadores LL(k) y LL(*) No todas las gramáticas pueden ser LL(k) para cualquier k. Las que si lo son, tienen un k mínimo que garantiza que la gramática sea LL. pero el caso que se necesiten los k símbolos en el look-ahead ocurre poco! Para eso se introduce un grupo de analizadores sintácticos con poder
Analizadores LL(k) y LL(*) No todas las gramáticas pueden ser LL(k) para cualquier k. Las que si lo son, tienen un k mínimo que garantiza que la gramática sea LL. pero el caso que se necesiten los k símbolos en el look-ahead ocurre poco! Para eso se introduce un grupo de analizadores sintácticos con poder Los analizadores LL(*)!
Analizadores LL(k) y LL(*) Un analizador LL(*) funciona de la siguiente forma: 1. Se intenta resolver la regla con look-ahead 1. 2. Si no, entonces aumenta el look-ahead al siguiente umbral (la regla que requiera un look-ahead mayor). Si se consigue una regla, se aplica el siguiente paso. Si no, vuelve al paso 2. Este manejo de look-aheads se hace con un Autómata Finito Determinista.
Analizadores LL(k) y LL(*) Un analizador LL(*) no necesita definir un k. El mismo generador reconoce cual es el k mínimo que se necesita. El tamaño de la predicción varía dependiendo de las reglas.
Analizadores LL(k) y LL(*) Un analizador LL(*) no necesita definir un k. El mismo generador reconoce cual es el k mínimo que se necesita. El tamaño de la predicción varía dependiendo de las reglas. Es usado en la herramienta de generadores de reconocedores ANTLR.
Analizadores LL(k) y LL(*) Con esto, estudiamos la familia de los Analizadores Sintácticos Descendientes.
Analizadores LL(k) y LL(*) Con esto, estudiamos la familia de los Analizadores Sintácticos Descendientes. Existen otra familia de Analizadores Sintácticos... los Analizadores Sintácticos Ascendentes.
Analizadores LL(k) y LL(*) Con esto, estudiamos la familia de los Analizadores Sintácticos Descendientes. Existen otra familia de Analizadores Sintácticos... los Analizadores Sintácticos Ascendentes. Estos Analizadores los estudiaremos en la próxima clase.
Analizadores LL(k) y LL(*) Con esto, estudiamos la familia de los Analizadores Sintácticos Descendientes. Existen otra familia de Analizadores Sintácticos... los Analizadores Sintácticos Ascendentes. Estos Analizadores los estudiaremos en la próxima clase.