La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Tema 4. Gramáticas y Análisis Sintáctico PARSER

Presentaciones similares


Presentación del tema: "Tema 4. Gramáticas y Análisis Sintáctico PARSER"— Transcripción de la presentación:

1 Tema 4. Gramáticas y Análisis Sintáctico PARSER
Lección 11,12,13 Gramáticas Libres del Contexto

2 Definición de Gramática
Una gramática G es una tupla (T,N,I,P) donde: T conjunto de símbolos terminales. N conjunto de símbolos no terminales. IÎN símbolo inicial. P conjunto de producciones. Una producción es de la forma (T|N)+ ® (T|N)* L={x Î T*| I x} es el lenguaje generado por la gramática G. abj adj es un paso de derivación si b®d Î P representa la aplicación iterada de pasos de derivación. Notación: Letras mayúsculas representan símbolos no terminales. Letras minúsculas representan símbolos terminales. * *

3 La gramática G=(N,T,I,P) donde,
Ejemplo de Gramática La gramática G=(N,T,I,P) donde, N={I,A,B} T={x,(,),+,-,*,/} P={ I®I+I I®I-I I®A A®A*A A®A/A A®(I) A®x } Secuencias generadas por G: x, x*x x*x+x x*(x/x) x-x+x*x/x

4 Pasos de Generación Secuencia: x*x+x I I+I A+I A*A+I A*A+A
x*A+A x*x+A x*x+x Arbol sintáctico: I I I A A A * A x x x

5 Clasificación de las Gramáticas
Regulares Producciones: N®TN N®T Analizador: autómata finito determinista. Complejidad del análisis: lineal Libres del Contexto N®(T|N)* Analizador: autómata con pila. Dependientes del Contexto a®b, donde a,b Î (T|N)* y |a| £ |b| Complejidad del análisis: exponencial Generales Complejidad del análisis: no se puede con memoria finita.

6 Gramáticas de los Lenguajes de Programación
Un lenguaje de programación se puede generar con una gramática dependiente del contexto. Las declaraciones provocan la necesidad de analizar el contexto. No utilizaremos estas gramáticas por la complejidad temporal de su analizador. Solución: Utilizar una gramática libre del contexto que tiene una complejidad lineal y dejar las características del lenguaje dependientes del contexto para el análisis semántico.

7 Notación BNF Extendida
Regla BNF: no terminal ::= expresión BNF Terminal: Forma única: secuencia de caracteres que lo forma. Ej. if, +, then, for Forma variable: nombre que lo identifica. Ej. identificador, numero, string, carácter, literal No Terminal: nombre entre < y > Ej. <programa>, <lista de argumentos>, <expresión>, <instrucción> Secuencia vacía: l Operadores: Unión: a | b Secuencia: a b Opcional: [a]= l | a Repetición: {a}= l | a | a a | a a a |...

8 Gramática simplificada de la declaración de una variable en C.
Ejemplo Gramática simplificada de la declaración de una variable en C. <dec>::=<tipo> <var> {, <var>}; <tipo>::=[signed|unsigned] (int|char) <var>::={*} identificador {‘[‘ número ‘]’} Símbolos terminales: signed, unsigned, int, char, identificador, número, ‘[‘, ‘]’, ‘,’ Símbolos no terminales: <dec>, <tipo>, <var> Símbolo inicial: <dec> Secuencias válidas: int a,**b[3][4]; unsigned char *p; signed char str[100];

9 Estructura Sintáctica de un Lenguaje y su Gramática
Gramática de expresiones aritméticas de números y variables. Operaciones: +,-, *, /, - (cambio de signo), paréntesis. <expresión>::=[-]<operando> {(+|-|*|/) [-]<operando>} <operando>::=‘(‘<expresión>‘)’ | identificador | número Secuencias valida: a+10*30/(-bd+2) Arbol sintáctico generado para a+b*c <expresión> <operando> <operando> * <operando> identificador identificador identificador Este árbol sintáctico no representa el orden en que se han de realizar + y *.

10 Prioridad de las Operaciones y el Arbol Sintáctico
Nueva gramática: <expresión>::=<término>{(+|-) <término>} <término>::=<factor>{(*|/) <factor>} <factor>::=[-](‘(‘ <expresión> ‘)’ | identificador | número) Arbol sintáctico generado para a+b*c <expresión> <término> <término> <factor> <factor> * <factor> identificado identificador identificador En este árbol cada operador se agrupa con sus operandos y las operaciones más prioritarias están más abajo.

11 Asociatividad y el Arbol Sintáctico
Operación asociativa: aàbàc = aà(bàc) = (aàb)àc Ej. +, * Operación asociativa por la izquierda: aàbàc = (aàb)àc Ej. -, / <operación>::=<operando>{à<operando>} <operación> <operando> à <operando> à <operando> Operación asociativa por la derecha: aàbàc = aà(bàc) Ej. = (asignación) <operación>::=<operando>[à<operación>] <operando> à <operación> <operando> à <operando>

12 Ambigüedad Gramatical
Una gramática es ambigua si puede generar una secuencia de símbolos con dos árboles sintácticos diferentes. Ejemplo: <a> ::= <a> (+ | *) <a> | número Secuencia: 1*2+3 Arboles sintácticos generados: <a> <a> <a> * <a> <a> <a> número <a> <a> <a> * <a> número número número número número Una gramática no se puede utilizar para la realización de un compilador por que no especifica la estructura sintáctica del lenguaje.

13 Diagramas Sintácticos
No Terminal Diagrama sintáctico de un símbolo no terminal No Terminal Símbolo no terminal Terminal Símbolo Terminal Ejemplo: <sumas>::= número {+ número} sumas número número +

14 Diagramas sintácticos para expresiones aritméticas.
Ejemplo Diagramas sintácticos para expresiones aritméticas. expresión término + término - término factor * factor / factor - identificador factor número ) ( expresión

15 Paso de BNF a Diagramas Sintácticos
A cada símbolo no terminal le corresponde una única regla. Por cada regla se crea un único diagrama sintáctico. <no terminal>::= expresión BNF Aplicar las siguientes reglas de conversión para pasar de la expresión BNF a su diagrama sintáctico. Diagrama sintáctico de la expresión BNF No terminal <no terminal> No Terminal Terminal Terminal l

16 Paso de BNF a Diagramas Sintácticos
a1 a2 ... an Diag. sint. de a1 Diag. sint. de a2 Diag. sint. de an a1 | a2 | ... | an Diag. sint. de a1 Diag. sint. de a2 Diag. sint. de an

17 Paso de BNF a Diagramas Sintácticos
Diag. sint. de a {a} Diag. sint. de a

18 Ejemplo de Paso de BNF a Diagrama Sintáctico
Gramática de instrucciones PASCAL simplificada: <instrucción>::= if <condición> then <instrucción> [else <instrucción>] Diagrama sintáctico de if <condición> then <instrucción> [else <instrucción>] instrucción

19 Ejemplo de Paso de BNF a Diagrama Sintáctico
Diagrama sintáctico de if <condición> then <instrucción> [else <instrucción>] instrucción Diag. if Diag. <condición> Diag. then Diag. [else <instrucción>] Diag. <instrucción> if Diag. if then Diag. then Diag. <condición> condición Diag. <instrucción> instrucción

20 Ejemplo de Paso de BNF a Diagrama Sintáctico
Diag. [else <instrucción>] Diag. sint. de else <instrucción> Diag. else <instrucción> Diag. else Diag. <instrucción> else Diag. else Diag. <instrucción> instrucción instrucción if condición then instrucción else instrucción

21 Gramática LL(1) Simple Un parser para gramáticas libres de contexto debe utilizar Backtracking Reducir las gramáticas utilizables a aquellas que permitan un reconocimiento determinista, en base al primer símbolo terminal de la secuencia. Una gramática LL(1) simple es aquella gramática libre de contexto sin reglas l y para cada símbolo A Î N las alternativas para A empiezan con un símbolo terminal distinto. A ® a1a1| a2a2 ... | anan , ai ¹ aj para i ¹ j y ai Î T para 1 £ i £ n

22 Ejemplo de Gramáticas LL(1) Simple
S ® aS S ® bA A ® d A ® ccA Reconocer: aabccd S a b A c d

23 Conjunto de Primeros de una Secuencia de Terminales y no Terminales
Primeros: concepto "aÎ T+ Primero(a) = { x | a Þ x... y x Î T} Gramática LL(1) sin reglas l es: una gramática libre de contexto en la que para todas las reglas de la forma A ® a1| a2 ... | an , los conjuntos Primero(a1), Primero(a2),..., Primero(an) son disjuntos. Primero(ai) Ç Primero(aj) = f " i ¹ j Ejemplo: S ® ABe Primero(S) = {a,b,c,d} S ® C A ® dB Primero(A) = {a,c,d} A ® aS A ® c B ® AS Primero(B) = {a,b,c,d} B ® b C ® b Primero(C) = {b} *

24 Gramáticas LL(1) con reglas l
Primeros: concepto "aÎ (T|N)+ Primero(a) = { w | a Þ w ... y w Î T} Siguientes: concepto "AÎ N Siguiente(A) = { w | S Þ aAg w Î Primero(g) y S es el símbolo inicial y w Î T} Gramática LL(1) con reglas l es una gramática libre de contexto en la que para cada par de reglas de la forma A ® a y A ® b se cumple que: Primero(a ° Siguiente(A)) Ç Primero(b ° Siguiente(A)) = f O lo que es lo mismo, para todas las reglas de la forma A ® a1| a2 ... | an : Primero(ai) Ç Primero(aj) = f " i ¹ j y si ai Þ l, entonces Primero(aj) Ç Siguiente(A) = f " jÎ1..n * * *

25 Cálculo del Conjunto de Símbolos Anulables
Un símbolo AÎN es anulable si y solo si A Þ l Cálculo del conjunto de Símbolos Anulables: Anulables0={AÎN| A® l } Repetir Anulablesn+1=AnulablesnÈ {BÎN| A® a1a2 ...am y "iÎ1..m aiÎAnulablesn} Hasta que Anulablesn==Anulablesn+1 *

26 Ejemplo: Cálculo del Conjunto de Símbolos Anulables
Gramática: I® DIa I® vI A® f A® l B® +I B® l C® AB D® CA Aplicación del Algoritmo Anulables0={A,B} Anulables1={A,B,C} Anulables2={A,B,C,D}

27 Cálculo del Conjunto de Primeros de los no Terminales
"AÎN Si AÎAnulables entonces P0(A)={l} sino P0(A)=Æ Repetir " producción A ® a de G Pn+1(A)= Pn(A) È PrimerosDe(a) Hasta que "AÎN : Pn(A)== Pn+1(A) PrimerosDe(l)={l} PrimerosDe(ab)={a} ,aÎT PrimerosDe(Ab)= ,AÎN si lÎPn(A) entonces (Pn(A)-{l})ÈPrimerosDe(b) sino Pn(A)

28 Ejemplo de Cálculo de Primeros
Gramática: I®TB T®FC B®+TB|-TB|l F®x C®*FC|/FC|l Anulables={B,C} Cálculo del conjunto de primeros P(I) P(T) P(B) P(F) P(C) 0 Æ Æ {l} Æ {l} 1 Æ Æ {l,+,-} {x} {l,*,/} 2 Æ {x} {l,+,-} {x} {l,*,/} 3 {x} {x} {l,+,-} {x} {l,*,/} 4 {x} {x} {l,+,-} {x} {l,*,/}

29 Cálculo del Conjunto de Siguientes
"AÎN Si A es el inicial entonces S0(A)={l} sino S0(A)=Æ Repetir " producción A ® aBb de G Sn+1(B)= Sn(B) È PrimerosDe(b) È si lÎ PrimerosDe(b) entonces Sn(A) sino Æ Hasta que "AÎN : Sn(A)== Sn+1(A)

30 Ejemplo de Cálculo de Siguientes
Gramática: I®TB T®FC B®+TB|-TB|l F®x C®*FC|/FC|l Primeros P(I) P(T) P(B) P(F) P(C) {x} {x} {l,+,-} {x} {l,*,/} Cálculo del conjunto de siguientes S(I) S(T) S(B) S(F) S(C) 0 {l} Æ Æ Æ Æ 1 {l} {l,+,-} {l} {l,*,/} Æ 2 {l} {l,+,-} {l} {l,*,/} {l,+,-} 3 {l} {l,+,-} {l} {l,*,/} {l,+,-}

31 Cálculo de Primeros y Siguientes en BNF
P(a1 a2 ... an)=P(a1) P(a1|a2|...|an)=P(a1)ÈP(a2)È ... ÈP(an) P([a]b)=P(a)ÈP(b) P({a}b)=P(a)ÈP(b) P(l) en <A>::= ... l es S(<A>) Siguientes Problema: Estas definiciones generan recursividades infinitas que tras su estudio se pueden eliminar

32 Analizador Sintáctico Dirigido por Tabla
Simbolo Terminal t; Parser(n) { if (predicción[t,n]==E) error(); p=Producciones[predicción[t,n]]; while (p!=NULL) { if (p->symÎT) if (t==p->sym) t=leer_símbolo(); else error(); else Parser(p->sym); p=p->siguiente; } Producciones[P]: tabla donde los símbolos de cada producción forman una lista encadenada predicción[T,N]: tabla que dado un símbolo no terminal y el terminal leído especifica que producción hay que aplicar. sym siguiente

33 Ejemplo: Analizador Sintáctico Dirigido por Tabla
Gramática I®TB T®FC B®+TB|-TB|l F®x C®*FC|/FC|l Tabla de Producciones 1 T B 2 F C 3 + T B 4 - T B 5 6 x 7 * F C 8 / F C 9

34 Ejemplo: Analizador Sintáctico Dirigido por Tabla
Cálculo de la tabla de predicción predicción[t,n]=E si no hay ninguna producción de n cuyos primeros contengan t. predicción[t,n]=al número de producción de n tal que t pertenezca a sus primeros Tabla de predicción Terminales È {l} + - * / x l I E E E E 1 E T E E E E 2 E No terminales B 3 4 E E E 5 F E E E E 6 E C 9 9 7 8 E 9

35 Construcción de un Parser a Partir de los Diagramas Sintácticos (I)
Programa principal Símbolo SLA; /* Símbolo leído */ main() { SLA=leer_símbolo(); Inicial(); if (SLA!=l) Error(); }

36 Construcción de un Parser a Partir de los Diagramas Sintácticos (II)
Diagrama sintáctico del No terminal No terminal noterminal ( ) { Parser[Diagrama sintáctico] }; Diag. sint. de a1 de a2 de an { Parser[a1] Parser[a2] ... Parser[an] }

37 Construcción de un Parser a Partir de los Diagramas Sintácticos (III)
Diag. sint. de a2 de a1 de an switch (SLA) { case ( Primero(a1)) : Parser[a1] break; case (Primero(a2)) : Parser[a2] break; ... case (Primero(an)) : Parser[an] break; default: error(); }

38 Construcción de un Parser a Partir de los Diagramas Sintácticos (VI)
Diag. sint. de a while (SLAÎPrimero(a) ) Parser[a] No Terminal Noterminal( ); Terminal if (SLA == Terminal) leer_símbolo(); else error()

39 Construcción de un Parser a Partir de la Descripción BNF (I)
Programa principal Simbolo SLA; /* Simbolo leido */ main() { SLA=leer_símbolo(); Inicial(); if (SLA!=l) Error(); } <no terminal>::= expresión BNF no_terminal ( ) { Parser[expresión BNF] };

40 Construcción de un Parser a Partir de la Descripción BNF (II)
Parser[a1 a2 ... an] { Parser[a1] Parser[a2] ... Parser[an] } Parser[a1 | a2 | ... | an] switch (SLA) { case ( Primero(a1)) : Parser[a1] break; case (Primero(a2)) : Parser[a2] break; case (Primero(an)) : Parser[an] break; default: error();

41 Construcción de un Parser a partir de la descripción BNF (III)
while (SLAÎPrimero(a) ) Parser[a] Parser[<no terminal>] Noterminal( ); Parser[ Terminal] if (SLA== Terminal) leer_símbolo(); else error();

42 Tratamiento de los Errores en Análisis Descendente
Tratamiento de errores: Detectar sólo el primero Detectar el máximo (razonable) Sincronizar después del error Prever errores típicos y cambiar la gramática a otra que los acepte dando warnings. Corregir el error: Decidir cual ha sido el error y reconstruir el programa fuente eliminando dicho error Consideraciones: No se pueden solucionar correctamente todos los casos. Hay que considerar la psicología del programador. Como mínimo tratar correctamente los errores más comunes. Minimizar: Error no detectados Falsas alarmas

43 Sincronización Después de Error
Después de un error se leen símbolos hasta encontrar uno que pertenezca al conjunto de sincronización Saltar símbolos hasta encontrar uno correcto y continuar (se supone que era código adicional erróneo) Saltar símbolos hasta encontrar uno correcto como siguiente del símbolo no terminal que se está analizando y retornar para continuar con ese símbolo siguiente (se supone que falta un trozo y se continua en un nivel superior) El conjunto de sincronización se puede formar a partir del cálculo de los símbolos que pueden seguir a un momento dado del análisis sintáctico. Acumular los símbolos de estructuras mayores en el conjunto de sincronización.

44 Ponderación de la secuencia:
Corrección de Errores Después de un error añadir o quitar símbolos hasta poder continuar el análisis sintáctico. Añadir: ir hacia delante dentro de la gramática. Quitar: ir hacia atrás dentro de la gramática. En el caso que varias correcciones sean válidas se seleccionará la de menor peso. Ponderación de la secuencia: A cada inserción de un símbolo se le asocia un peso según lo fácil que sea dejarselo. A cada eliminación de un símbolo se le asocia un peso según lo fácil que sea ponerlo de más.

45 Tema 4. Análisis Sintáctico Ascendente (Bottom-Up)
Lecciones 17,18

46 Análisis Sintáctico Ascendente (Bottom-Up)
Un analizador sintáctico ascendente construye el árbol sintáctico de abajo a arriba, por lo tanto parte de los símbolos terminales que agrupan o reducen en símbolos no terminales Ejemplo Gramática I®I+I | I-I | A A®A*A | A/A | (I) | num Expresión 1+2*3 Derivación: I => I+I => num+I => num+A => num+A*A => num+num*A => num+num*num La reducción de símbolos supone ir de derecha a izquierda en los pasos de derivación * 3 num+num*num A I

47 Familias de gramáticas
Gramáticas LR(k) El conjunto de las gramáticas LR(k) es el conjunto de las gramáticas libres del contexto no ambiguas El conjunto de las gramáticas LR(k) contiene las gramáticas LL(k). k es el número de símbolos que hay que considerar hacia delante antes de que el analizador sintáctico realice una acción. Solo se consideran las gramáticas LR(0) y LR(1) ya que para k>1 el análisis tiende ha ser demasiado costoso. Familias de gramáticas demasiado costoso LR(k) LR(1) LALR(1) SLR(1) LL(1) demasiado simple LR(0) equivalentes por transformación

48 Bases del Análisis Sintáctico con Gramáticas LR(k) (I)
Derivación de más a la derecha (rightmost derivation) de una secuencia de símbolos X es I => a1 => a2 => a1 =>...=> am = X donde para todo i Î [1..m-1] fBt => fbt, ai= fBt, B®bÎP, t Î T* Como ha de actuar el analizador de una gramática LR(k) f es una secuencia de símbolos terminales y no terminales donde se han realizado todas las reducciones posibles. b es la nueva reducción que podemos realizar y la sustituimos por el símbolo no terminal B que la genera t es el resto de símbolos de la secuencia que faltan por procesar. La decisión de que reducción se ha de realizar se toma en base a f b y a los k primeros símbolos de t si la gramática es LR(k).

49 Bases del Análisis Sintáctico con Gramáticas LR(k) (II)
Knuth demostró que se pueden reconocer los prefijos f válidos mediante un autómata finito. hay que considerar que el número de prefijos f puede ser infinito. Una vez reconocido el prefijo y leídos los k primeros símbolos de t hay una única reducción válida a aplicar. Como es un parser LR Es una máquina con como entrada la secuencia a analizar una pila un mecanismo de control finito formado por: estados de lectura Lee un símbolo, lo pone en la pila y salta a un nuevo estado estados reductores sustituyen la secuencia b que encuentra en la pila por B. un estado inicial no es necesario

50 Gramática LR(0) Gramática S®E# E®T | E+T | E - T T®i | (E) E®E+T S®E#
Estado reductor Estado de lectura E®E+T S®E# 8 5 # T + 1 6 E i - i 3 7 + T i T®i ( 9 i E®E-T ( - ( T 2 11 4 10 ) T E E®T T®(E) (

51 Trazado Secuencia: i-(i+i)# Paso Pila Entrada Prefijo Grupo
1 0 i3 -(i+i)# i i 2 0 T2 -(i+i)# T T 3 0 E1 -(i+i)# E 4 0 E (i+i)# E- 5 0 E1 -7 (4 i+i)# E-( 6 0 E1 -7 (4 i i)# E-(i i 7 0 E1 -7 (4 T i)# E-(T T 8 0 E1 -7 (4 E i)# E-(E 9 0 E1 -7 (4 E i)# E-(E+ 10 0 E1 -7 (4 E10 +6 i )# E-(E+i i 11 0 E1 -7 (4 E10 +6 T )# E-(E+T E+T 12 0 E1 -7 (4 E )# E-(E E+T 13 0 E1 -7 (4 E10 ) # E-(E) (E) 14 0 E1 -7 T # E-T E-T 15 0 E # E 16 0 E1 # E# Aceptado

52 Gramáticas SLR(1), LR(1), LALR(1):
Gramáticas no LR(0) Gramática LR(0) S®E# E®T | E+T | E - T T®i | (E) Gramática No LR(0) S ® E# E ® E - T E ® T T ® F ^ T T ® F F ® (E) F ® i Gramáticas SLR(1), LR(1), LALR(1): Se decide cual es el estado siguiente de una reducción a partir del estado de la pila y el símbolo leído hacia delante Los tres tipos de gramáticas se diferencian en el tratamiento del símbolo leído hacia delante. Para aplicar una de estas dos reducciones hay que leer el siguiente símbolo


Descargar ppt "Tema 4. Gramáticas y Análisis Sintáctico PARSER"

Presentaciones similares


Anuncios Google