Análisis sintáctico 1
Análisis sintáctico 1. Introducción 2. Análisis descendente (top-down) 2.1 Análisis con backtracking 2.2 Análisis predictivo 2.2.1 Método recursivo 2.2.2 Método iterativo 3. Análisis ascendente 3.1 LR parsing (bottom-up) 3.1.1 SLR 3.1.2 LR canónico 3.1.3 LALR 3.2 YACC (parser generator) 2
1. Introducción Objetivo del análisis sintáctico: Conocer si la sentencia que se analiza pertenece, o no, al lenguaje (no se tiene en cuenta el aspecto semántico). Relación entre análisis léxico y sintáctico Programa Fuente Analizador Léxico (1) (2) Analizador Sintáctico (1) next token? (2) token 3
1. Introducción Construcción del analizador sintáctico (parser) By hand Lenguaje Gramática PARSER Tool 4
1. Gramáticas y tipos de análisis Nos centraremos en las gramáticas libres de contexto: (context-free grammars) (tipo 2 según Chomsky) Métodos de análisis sintáctico: A) Reconocedores universales B) Reconocedores top-down C) Reconocedores bottom-up 5
1. Métodos de reconocimiento A) Universales Ventaja: son válidos para cualquier gramática libre de contexto. Desventaja: su excesiva generalidad no permite que los reconocedores estén muy optimizados (son muy lentos) 6
1. Métodos de reconocimiento B) Métodos top-down Ventaja: Desventaja: reconocedores muy rápidos válidos para gramáticas LL(k) C) Métodos bottom-up Desventaja: Ventaja: los reconocedores son rápidos (pero no tanto como los reconocedores top-down) válidos para gramáticas SLR(k), LRc(k), LALR(k), que son un superconjunto de las gramáticas LL(k) 7
2. Análisis descendente (top-down) Fundamento básico: Generación de la sentencia mediante la left-most derivation EXPR EXPR + TERM TERM TERM TERM * FACT FACT FACT id cte ( EXPR ) 8
2. Análisis descendente (top-down) EXPR a + b * ( c + 2 ) 9
2.1 Análisis con backtracking EXPR EXPR + TERM EXPR + TERM TERM FACT FACT NO HAY MATCH- ING id id a + b * ( c + 2 ) 10
2.1 Análisis con backtracking Ventajas Desventajas Política sencilla de prueba y error. Para gramáticas de un tamaño normal no resulta aplicable debido al excesivo tiempo de computación. La aplicación del método no garantiza que la gramática no sea ambigua. 11
2.2 Análisis predictivo EXPR podemos decidir en función de un símbolo de lookahead? a + b * ( c + 2 ) símbolo de lookahead 12
Concepto de PRIMEROS Notación PRIMEROS (símbolo/cadena) = P(símbolo/cadena) P(a) = { a } a Є Vt P(N) = P(α1) U P(α2) U P(αn) N Є Vn N α1 α2 αn Si ε Є P(αi) entonces hay que añadir los SIGUIENTES(N) al conjunto de P(N) 13
Condiciones necesaria y suficiente para predecir N Є Vn N α1 α2 αn 1. P(αi) P(αj) = Ø Para todo i j 2. Si ε ЄP(αi) debe cumplirse que: S(N) P(αj) = Ø Para todo j i S(N) = SIGUIENTES(N) 14
Ejemplo EXPR EXPR + TERM TERM TERM TERM * FACT FACT FACT id cte ( EXPR ) P(EXPR)= P(EXPR) U P(TERM) = { id, cte, ( } P(TERM)= P(TERM) U P(FACT) = { id, cte, ( } P(FACT)= { id, cte, ( } No podemos realizar análisis sintáctico mediante el método de descenso (top-down) predictivo. 15
Recursividad por la izquierda Toda gramática recursiva por la izquierda no es válida para reconocimiento por descenso predictivo. N N α β Primer símbolo (β) N P(N)= P(N) U P(β) P(Nα) P(β) Ø Por tanto, no podemos discernir entre las dos opciones de la regla N la hora de realizar un descenso predictivo. 16
Eliminación de la recursividad por la izquierda L L α1 L α2 L αn β1 β2 βp Podemos generar las mismas cadenas de la siguiente forma: L C R C β1 β2 βp R α1 R α2 R αn R ε 17
Ejemplo G: EXPR EXPR + TERM TERM TERM TERM * FACT FACT FACT id cte ( EXPR ) G : EXPR TERM REXPR REXPR + TERM REXPR ε TERM FACT RTERM RTERM * FACT RTERM ε FACT id cte ( EXPR ) 18
Calculamos PRIMEROS para G P(EXPR) = P(TERM) = { id, cte, ( } P(REXPR) = { +, ε } Añadimos los S(REXPR) = { $, ) } P(TERM) = P(FACT) = { id, cte, ( } P(RTERM) = { *, ε } Añadimos los S(RTERM) = { +, $, ) } P(FACT) = { id, cte, ( } Por tanto, podemos realizar un reconocedor descendente predictivo para la gramática G. 19
Factorización EXPR TERM + EXPR TERM TERM FACTOR * TERM FACTOR FACTOR id cte ( EXPR ) En este caso tenemos una gramática para expresiones que es recursiva por la derecha. Sin embargo, no podemos utilizar un reconocedor descendente predictivo porque existen reglas cuyas opciones tienen el mismo encabezado. SOLUCIÓN Factorizar dichas reglas 20
Factorización EXPR TERM REXPR REXPR + EXPR ε TERM FACTOR RTERM RTERM * TERM ε FACTOR id cte ( EXPR ) Si realizamos el cálculo de los PRIMEROS para esta gramática modificada tenemos lo siguiente: 21
Cálculo de PRIMEROS P(EXPR) = P(TERM) = { id, cte, ( } P(REXPR) = { +, ε } Añadimos los S(REXPR) = { ), $ } P(TERM) = P(FACTOR) = { id, cte, ( } P(RTERM) = { *, ε } Añadimos los S(RTERM) = { +, ), $ } P(FACTOR) = { id, cte, ( } Luego, si podemos utilizar un reconocedor descendente predictivo 22
Implementación Reconocedores descendentes predictivos 2.2.1 Implementación recursiva 2.2.1 Implementación iterativa 23
2.2.1 Implementación recursiva PROCEDIMIENTO DE CONSTRUCCIÓN 1. Para cada regla (símbolo no terminal) debe construirse un procedimiento sin parámetros cuyo nombre será el del propio símbolo no terminal. 2. En función de los PRIMEROS, cada procedimiento implementa las diversas alternativas de su regla 3. Cada alternativa de una regla se implementa de la siguiente forma: 24
2.2.1 Implementación recursiva 3.1 Un símbolo no terminal se implementa mediante una llamada al procedimiento de dicho símbolo. 3.2 Un símbolo terminal se implementa comprobando que el símbolo de lookahead actual se corresponde con el símbolo terminal. Caso de ser cierto, el analizador léxico debe localizar el siguiente símbolo de lookahead. En caso contrario, detenemos el proceso de análisis porque existe un error sintáctico. 25
Ejemplo Utilizaremos como ejemplo la gramática de expresiones que hemos factorizado anteriormente. EXPR TERM REXPR REXPR + EXPR ε TERM FACTOR RTERM RTERM * TERM ε FACTOR id cte ( EXPR ) Construyamos los procedimientos para los dos primeros símbolos no terminales: EXPR y REXPR 26
Procedimiento EXPR (versión 1) EXPR ( ) { TERM ( ); REXPR ( ); } Esta primera versión no utiliza los PRIMEROS puesto que no existen diversas alternativas en la regla. Sin embargo, se puede realizar una detección precoz de errores si añadimos al control de la única alternativa de esta regla el conocimiento de los PRIMEROS: 27
Procedimiento EXPR (versión 2) EXPR ( ) { if ( lookahead = { id, cte, ( } ) { TERM ( ); REXPR ( ); } else error ( ); } 28
Procedimiento REXPR REXPR ( ) { if (lookahead = { + } ) / alternativa 1 { lookahead = yylex ( ); / matching del símbolo + EXPR ( ); return ( ); } if (lookahead = { ), $ } ) / alternativa 2 return ( ); } error ( ); / ninguna alternativa es válida 29
2.2.2 Implementación iterativa Se trata de construir un programa que desarrolle el proceso de análisis sintáctico descendente predictivo basándose en una tabla de reconocimiento. El programa lleva a cabo el reconocimiento de la misma forma que lo hemos desarrollado manualmente. La tabla para la gramática utilizada en la implementación recursiva es la siguiente: 30
2.2.2 Implementación iterativa cte id + * ( ) $ EXPR TERM REXPR TERM REXPR TERM REXPR REXPR + EXPR ε ε TERM FACTOR RTERM FACTOR RTERM FACTOR RTERM RTERM ε * TERM ε ε FACTOR cte id ( EXPR ) 31
Gramáticas LL(k) Toda gramática a la que se puede aplicar un reconocedor descendente predictivo pertenece a un conjunto de gramáticas denominado LL(k), siendo K el número de símbolos de lookahead que se utilizan. El conjunto LL(k) es un subconjunto del total de gramáticas libres de contexto. Por tanto, existen muchas gramáticas libres de contexto que no pueden ser analizadas mediante reconocedores descendentes predictivos. 32
3. ANÁLISIS ASCENDENTE 3.1 LR parsing (bottom-up) 3.1.1 SLR 3.1.2 LR canónico 3.1.3 LALR 3.2 YACC (parser generator) 33
3.1 LR parsing FUNDAMENTOS 1. Bottom-Up (frente a top-down) 2. Utiliza la derivación más a la derecha (right-most derivation) (frente a left-most derivation) Siglas LR: L Left to right scanning R Right-most derivation 34
Ejemplo S a A B e A A b c b B d Usemos derivaciones right-most: S aabe aade aabcde abbcde 35
Por qué no se elige derivación a izquierdas? S A B C A M N B O P C Q R M m Qué sucede al realizar el análisis bottom-up? N n O o P p Q q R r S ABC MNBC mnbc mnbc mnopc mnopc mnopc mnopqr mnopqr mnopqr 36
Implementación basada en una PILA S a A B e A A b c b B d S aabe aade aabcde abbcde PILA + acciones SHIFT + acciones REDUCE 37
PILA + SHIFT + REDUCE PILA CADENA ACCIONES abbcde$ shift a bbcde$ shift ab bcde$ reduce A b aa bcde$ shift aab cde$ shift aabc de$ reduce A Abc aa de$ shift aad e$ reduce B d aab e$ shift aabe $ reduce S aabe S $ ACEPTADA 38
Modelo general de reconocedor LR CADENA...... t1 t2 t3 t i tn $ S m V m Reconocedor LR SA LIDA (código ejecutado al reducir las reglas) S m-1 V m-1... V 1 S0 acciones goto TAB LA (generada a partir de la gramática) PILA S i Estados del reconocedor V i Símbolo del vocabulario (terminal o no terminal) 39
Ejemplo Dada la siguiente gramática para expresiones: 1) E E + T 2) E T 3) T T * F 4) T F 5) F ( E ) 6) F id La tabla de reconocimiento LR es la siguiente: 40
41 Tabla de reconocimiento R3 R3 R3 R3 10 R5 R5 R5 R5 11 R1 R1 S7 R1 9 S11 S6 8 10 S4 S5 7 3 9 S4 S5 6 R6 R6 R6 R6 5 3 2 8 S4 S5 4 R4 R4 R4 R4 3 R2 R2 S7 R2 2 O.K. S6 1 3 2 1 S4 S5 0 F T E $ ) ( * + id GOTO ACCIONES Estado
Construcción de las tablas Las tablas que utiliza un reconocedor LR se generan a partir del correspondiente autómata LR. Veamos el autómata para la siguiente gramática: S a A B e A A b c b B d 42
Autómata SLR (Simple LR) S0 S --> ^ S S --> ^ aabe S a S1 S2 S4 S5 A --> b^ S --> aab^e e S8 S1 S --> S ^ S6 A --> Ab^c c S9 S2 S --> a^abe A --> ^Abc A --> ^b A b S3 S4 S7 S8 B --> d^ S --> aabe^ S3 S --> aa^be A --> A^bc B --> ^d B b d S5 S6 S7 S9 A --> Abc^ 43
Autómata: reconocedor de prefijos válidos S a A B e A A b c b B d S ] aabe ] aad ] e aabc ] de ab ] bcde Prefijos = { S, a, aa, aab, aabe, aad, aab, aabc, ab } 44
Construcción de la tabla de reconocimiento Necesitamos conocer: 1. El autómata correspondiente 2. Los SIGUIENTES de cada símbolo no-terminal En el ejemplo que nos ocupa, los SIGUIENTES son: SIGUIENTES (S) = { $ } SIGUIENTES (A) = { d, b } SIGUIENTES (B) = { e } 45
Tabla de reconocimiento Estado a b Acciones c d e $ S Goto A B S0 S2 1 S1 O.K. S2 S4 3 S3 S6 S7 5 S4 R3 R3 S5 S8 S6 S9 S7 R4 S8 R1 S9 R2 R2 46
Ejercicio 1) E E + T 2) E T 3) T T * F 4) T F 5) F ( E ) 6) F id a) Obtener el autómata SLR y la tabla de reconocimiento b) Reconocer la cadena: id + id * ( id + id ) 47
Ejercicio: estados del autómata SLR S0: E ^ E S4:F ( ^ E ) S7: T T * ^ F E ^ E + T E ^ E + T F ^ (E) E ^ T E ^ T F ^ id T ^ T * F T ^ T * F T ^ F T ^ F S8: F ( E ^ ) F ^ (E) F ^ (E) E E ^ + T F ^ id F ^ id S9: E E + T ^ S1: E E ^ S5: F id ^ T T ^ * F E E ^ + T S6: E E + ^ T S10: T T * F ^ S2: E T ^ T ^ T * F T T ^ * F T ^ F S11: F (E) ^ F ^ (E) S3: T F ^ F ^ id 48
Ejercicio: transiciones del autómata SLR S0 S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 id S5 S5 S5 S5 + S6 S6 * S7 S7 ( S4 S4 S4 S4 ) S11 E S1 S8 T S2 S2 S9 F S3 S3 S3 S10 49
50 Ejercicio: tabla de reconocimiento SLR R3 R3 R3 R3 10 R5 R5 R5 R5 11 R1 R1 S7 R1 9 S11 S6 8 10 S4 S5 7 3 9 S4 S5 6 R6 R6 R6 R6 5 3 2 8 S4 S5 4 R4 R4 R4 R4 3 R2 R2 S7 R2 2 O.K. S6 1 3 2 1 S4 S5 0 F T E $ ) ( * + id GOTO ACCIONES Estado
Ejercicio: reconocer la cadena id + id * ( id + id ) Se deja como ejercicio 51
3. ANÁLISIS ASCENDENTE 3.1 LR parsing (bottom-up) 3.1.1 SLR 3.1.2 LR canónico 3.1.3 LALR 3.2 YACC (parser generator) 52
3.1.1 Límites de los reconocedores SLR Supongamos la siguiente gramática: 1) S L = R 2) S R 3) L * R 4) L id 5) R L Es reconocible mediante reconocimiento SLR? 53
Estados del autómata SLR S0: S ^ S S5: L id ^ S ^ L = R S ^ R S6: S L = ^ R L ^ * R R ^ L L ^ id L ^ * R R ^ L L ^ id S1: S S ^ S7: L * R ^ S2: S L ^ = R S8: R L ^ R L ^ S9: S L = R ^ S3: S R ^ S4: L * ^ R R ^ L L ^ * R L ^ id 54
Transiciones del autómata SLR S0 S1 S2 S3 S4 S5 S6 S7 S8 S9 id S5 S5 S5 = S6 * S4 S4 S4 S S1 L S2 S8 S8 R S3 S7 S9 55
Tabla de reconocimiento SLR ESTADO id ACCIONES = * $ S GOTO L R S0 S5 S4 1 2 3 S1 O.K. S2 S6 / R5 R5 S3 R2 S4 S5 S4 8 7 S5 R4 R4 S6 S5 S4 8 9 S7 R3 R3 S8 R5 R5 S9 R1 56
Conclusiones Existe una casilla de la tabla de reconocimiento (S2,=) que tiene 2 acciones: S6 : shift 6 R5 : reduce 5 Por tanto, existe un conflicto SHIFT-REDUCE y la gramática no se puede reconocer mediante un reconocedor SLR. 57
Tipos de conflictos y ambigüedad Los conflictos que pueden darse en los reconocedores ascendentes son los siguientes: 1. SHITF-REDUCE 2. REDUCE-REDUCE Toda gramática ambigua genera uno o varios conflictos en los reconocedores ascendentes. La aparición de conflictos no significa necesariamente que la gramática sea ambigua (de hecho, la gramática del ejemplo anterior no es ambigua y había un conflicto). 58
Gramática no ambigua que genera conflictos 1) S L = R 2) S R 3) L * R 4) L id 5) R L Porqué esta gramática no ambigua genera conflictos? El reconocedor SLR no contiene la suficiente información sobre la gramática. Se hace necesario utilizar reconocedores LR más precisos. 59
3.1.2 Reconocedores LR canónicos S0: S ^ S { $ } S4: L * ^ R { = } S ^ L = R { $ } R ^ L { = } S ^ R { $ } L ^ * R { = } L ^ * R { = } L ^ id { = } L ^ id { = } R ^ L { $ } S5: L id ^ { = } S1: S S ^ { $ } S6: S L = ^ R { $ } R ^ L { $ } S2: S L ^ = R { $ } L ^ * R { $ } R L ^ { $ } L ^ id { $ } S3: S R ^ { $ } S7: L * R ^ { = } 60
3.1.2 Reconocedores LR canónicos S8: R L ^ { = } S9: S L = R ^ { $ } S10: R L ^ { $ } S11: L * ^ R { $ } R ^ L { $ } L ^ * R { $ } L ^ id { $ } S12: L id ^ { $ } S13: L * R ^ { $ } 61
Tabla de transiciones S0 S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12 S13 id S5 S5 S12 S12 = S6 * S4 S4 S11 S11 S S1 L S2 S8 S10 S10 R S3 S7 S9 S13 62
63 Tabla de reconocimiento LR canónico 13 9 7 3 R 10 10 8 2 L 1 S G O T O R3 R4 R5 R1 R2 R5 O.K. $ S11 S11 S4 S4 * R5 R3 R4 S6 = S12 S12 S5 S5 id A C C I O N E S S13 S12 S11 S10 S9 S8 S7 S6 S5 S4 S3 S2 S1 S0 Estados
Conclusiones No aparece ningún conflicto. Por tanto, no era un problema de ambigüedad de la gramática, sino que el reconocedor SLR no era tan preciso como el reconocedor LR canónico. En particular, la reducción de una regla N. se realiza ante todos los SIGUIENTES(N) en SLR. Por el contrario, la reducción de una regla N. se realiza ante un subconjunto de los SIGUIENTES(N) en el reconocedor LR canónico. 64
Ejercicio Dada la siguiente gramática: 1. S CC 2. C cc 3. C d Se pide: 1. Autómata de reconocimiento LR canónico 2. Tabla de reconocimiento correspondiente 65
Estados del autómata LR canónico S0:S ^ S { $ } S4: C d ^ { c, d } S ^ CC { $ } C ^ cc { c, d } S5: S CC ^ { $ } C ^ d { c, d } S6: C c ^ C { $ } S1:S S ^ { $ } C ^ cc { $ } C ^ d { $ } S2:S C ^ C { $ } C ^ cc { $ } S7: C d ^ { $ } C ^ d { $ } S8: C cc ^ { c, d } S3:C c ^ C { c, d } C ^ cc { c, d } S9: C cc ^ { $ } C ^ d { c, d } 66
Transiciones del autómata LR canónico S0 S1 S2 S3 S4 S5 S6 S7 S8 S9 c S3 S6 S3 S6 d S4 S7 S4 S7 S S1 C S2 S5 S8 S9 67
Tabla de reconocimiento Estados c ACCIONES d $ S GOTO C S0 S3 S4 1 2 S1 O.K. S2 S6 S7 5 S3 S3 S4 8 S4 R3 R3 S5 R1 S6 S6 S7 9 S7 R3 S8 R2 R2 S9 R2 68
SLR y LR canónico: ventajas / desventajas Ventaja fundamental LR canónico Reconoce un conjunto mayor de gramáticas que SLR. Desventaja fundamental El número de estados del reconocedor aumenta de forma considerable respecto de SLR 69
3.1.3 Reconocedores LALR Se trata de un punto intermedio entre SLR y LR canónico. La idea es reducir el número de estados de un reconocedor LR canónico mediante la fusión de estados que son idénticos (salvo en la lista de SIGUIENTES asociada a cada regla). Al fusionar los estados tenemos que modificar las transiciones correspondientes. Además, la lista de SIGUIENTES de un estado fusionado es la UNION de las listas de los estados que se han fusionado. 70
Ejemplo Dada la siguiente gramática: Se pide: 1. S CC 2. C cc 3. C d 1. Autómata de reconocimiento LALR 2. Tabla de reconocimiento correspondiente 71
Estados del autómata LR canónico S0:S ^ S { $ } S4: C d ^ { c, d } S ^ CC { $ } C ^ cc { c, d } S5: S CC ^ { $ } C ^ d { c, d } S6: C c ^ C { $ } S1:S S ^ { $ } C ^ cc { $ } C ^ d { $ } S2:S C ^ C { $ } C ^ cc { $ } S7: C d ^ { $ } C ^ d { $ } S8: C cc ^ { c, d } S3:C c ^ C { c, d } C ^ cc { c, d } S9: C cc ^ { $ } C ^ d { c, d } 72
Estados del autómata LALR S0: S ^ S { $ } S47: C d ^ { c, d, $ } S ^ CC { $ } C ^ cc { c, d } S5: S CC ^ { $ } C ^ d { c, d } S89: C cc ^ { c, d, $ } S1: S S ^ { $ } S2: S C ^ C { $ } C ^ cc { $ } C ^ d { $ } S36: C c ^ C { c, d, $ } C ^ cc { c, d, $ } C ^ d { c, d, $ } 73
Tabla de reconocimiento LALR ESTADOS c ACCIONES d $ S GOTO C S0 S36 S47 1 2 S1 O.K. S2 S36 S47 5 S36 S36 S47 89 S47 R3 R3 R3 S5 R1 S89 R2 R2 R2 74
Conflictos en la fusión LALR 1 Si no existen conflictos SHIFT-REDUCE en el autómata canónico, tampoco los habrá en el autómata LALR. 2 Aunque el autómata canónico no tenga conflictos REDUCE-REDUCE, podrían aparecer este tipo de conflictos en el autómata LALR. 75
Demostración sobre conflictos shift-reduce (I) No hay conflicto S/R R1 α ^ { A } A a = Ø R2 β ^ { B } A b = Ø R3 φ ^ a { } B a = Ø R4 ρ ^ b { } B b = Ø R1 α ^ { C } C a = Ø R2 β ^ { D } C b = Ø R3 φ ^ a { } D a = Ø R4 ρ ^ b { } D b = Ø 76
Demostración sobre conflictos shift-reduce (II) R1 α ^ { A U C } R2 β ^ { B U D } R3 φ ^ a { } R4 ρ ^ b { } hay conflicto S/R al fusionar los 2 estados? (A U C) a = (A a) U (C a) = Ø (A U C) b = (A b) U (C b) = Ø (B U D) a = (B a) U (D a) = Ø (B U D) b = (B b) U (D b) = Ø Efectivamente, si no hay conflictos S/R antes de la fusión de estados, después de la fusión tampoco existen. 77
Demostración sobre conflictos reduce-reduce (I) No hay conflicto R/R R1 α ^ { A } A B = Ø R2 β ^ { B } R3 φ ^ a { } R4 ρ ^ b { } R1 α ^ { C } C D = Ø R2 β ^ { D } R3 φ ^ a { } R4 ρ ^ b { } 78
Demostración sobre conflictos reduce-reduce (II) R1 α ^ { A U C } R2 β ^ { B U D } R3 φ ^ a { } R4 ρ ^ b { } hay conflicto R/R al fusionar los 2 estados? (A U C) (B U D) = { (A U C) B } U { (A U C) D } = (A B) U (C B) U (A D) U (C D) Ø?? Ø Podrían aparecer conflictos R/R después de fusionar los estados aunque antes de la fusión no existiese ningún conflicto R/R 79