GRAMÁTICAS Y LENGUAJES ÍNDICE: - DEFINICIONES DE TEORÍA DE LENGUAJES FORMALES...............................................2 - DEFINICIÓN FORMAL DE GRAMÁTICA .............................................................................4 - GRAMÁTICA RECURSIVA .....................................................................................................9 - GRAMÁTICA AMBIGUA .........................................................................................................9 - EJERCICIOS............................................................................................................................. 13 - RELACIONES .......................................................................................................................... 21 - PROPIEDADES DE UNA RELACIÓN.................................................................................. 21 - PRODUCTO DE DOS RELACIONES ................................................................................... 21 - SUMA DE RELACIONES (UNIÓN) ...................................................................................... 22 - CIERRE TRANSITIVO ........................................................................................................... 23 - IMPLEMENTACIÓN DE UNA RELACIÓN EN LA MAQUINA ....................................... 24 - RELACIONES BINARIAS APLICADAS A LENGUAJES FORMALES ........................... 26 - RESTRICCIONES DE UNA GRAMÁTICA.......................................................................... 28 - CHEQUEO DE LAS RESTRICCIONES DE LA GRAMÁTICA ......................................... 29 - NOTACIÓN BNF EXTENDIDA (EBNF) .............................................................................. 31 - DIAGRAMAS SINTÁCTICOS ............................................................................................... 33 - JERARQUÍA DE GRAMÁTICAS DE CHOMSKY .............................................................. 35 - REFERENCIAS ........................................................................................................................ 38 1 Gramáticas y Lenguajes GRAMÁTICAS Y LENGUAJES Está relacionado con los analizadores léxico y sintáctico. DEFINICIONES DE TEORÍA DE LENGUAJES FORMALES: * LENGUAJE: Conjunto finito o infinito de sentencias. * SENTENCIA: Secuencia de símbolos terminales. Desde el punto de vista de los lenguajes formales, una sentencia podría ser un programa y un lenguaje de programación sería el conjunto de todos los posibles programas que se pudieran escribir. * GRAMÁTICA: Conjunto finito de reglas que definen un lenguaje. Para un lenguaje dado pueden haber diferentes gramáticas, pero una gramática genera un único lenguaje y además permite definir la estructura sintáctica de las sentencias. * METALENGUAJE: Es un lenguaje que nos permite definir a otro lenguaje. Tipos de metalenguajes: Notación BNF (Backus-Normal-Form). -Esta notación está compuesta por reglas o producciones. (Notación de Backus y Naur) Principal responsable del desarrollo del FORTRAN. Trabajó en el ALGOL ┌─ que generaría el Pascal. -TERMINAL Unidad mínima sintáctica en que están compuestos los programas (lenguajes) (TOKEN). -NO TERMINAL "Estructuras" de los programas. * SÍMBOLO: * ALFABETO: o Vocabulario terminal en relación con el lenguaje, VT es el conjunto de símbolos terminales que se utiliza para formar sentencias. { begin,if,var,... } S Є VT S = símbolo terminal. 2 Gramáticas y Lenguajes * SECUENCIA O STRING: Se puede representar en forma de letras: x = 'ABCD' A,B,C,D ε VT La longitud de una secuencia de símbolos terminales se representa: │x│ = 4. * CONCATENACION: Es una operación sobre strings; dada x e y se concatenan poniendo una detrás de otra: x ='ABCD' y ='EF' xy = z ='ABCDEF' │xy│ = │x│ + │y│ * CABEZA DE UNA SECUENCIA: Subsecuencia que arranca a partir del primer símbolo: cabezas de x = { 'A' , 'AB' , 'ABC' , ... } Head * COLA DE UNA SECUENCIA: Subsecuencia que arranca a partir del último símbolo: colas de z = { 'F' , 'EF' , 'DEF' , ... } Tail * PRODUCTO DE CONJUNTOS DE SECUENCIAS: Dados los conjuntos de secuencias A y B, el producto es: C = { xy / x Є A /\ y Є B } A = { abc,ca,cc } C = A * B B = { aa,c } C = { abcaa,abcc,caaa,cac,ccaa,ccc } * POTENCIA N-ESIMA DE UNA SECUENCIA: Es una concatenación "n" veces: n Xn = XXXXX...X X = ab X3 = ababab * POTENCIA N-ESIMA DE UN ALFABETO V: Vn = Conjunto de todas las secuencias de longitud n que se pueden formar a partir de V = { S1...Sn / S1,S2,...,Sn Є V } V = { a,b,c } V3 = { aaa,aab,aac,aba,aca,... } 3 Gramáticas y Lenguajes * CIERRE TRANSITIVO (+): (positive closure). V i V 1 V 2 V 3 ... V i 1 V+ ═══> Todas las posibles secuencias no nulas que se pueden formar con los símbolos de V de longitud arbitraria. * SECUENCIA NULA = ε: V0 = { ε } │ε│ = 0 * CIERRE TRANSITIVO REFLEXIVO (*): * 0 + V = V V = V i = { }V + i=0 L = lenguaje L V * V*V = V+ = VV* │xn│ = n │x│ DEFINICIÓN FORMAL DE GRAMÁTICA: Una gramática es una cuádrupla (R , Z , VT , VN) donde: VN = Conjunto finito de símbolos no terminales. VT = Conjunto finito de símbolos terminales. Z = Símbolo no terminal principal, es el que aparece en la raíz del árbol. Z ε VN. R = Es un conjunto finito de pares, llamados reglas de sustitución o también, producciones, tal que cada producción (x,α) se escribe x → α ó x ::= α ; donde x Є V+ y α Є V* V =V N V T a Є VT (letras minúsculas). A Є VN (letras mayúsculas). x , y , z Є VT* └────┬────┘ secuencias de símbolos terminales. 4 Gramáticas y Lenguajes α ,ß , ... Є V* R = { Z α1 , N2 α2 ,...} secuencias Con el símbolo G(Z) se suele denotar a una gramática cuyo símbolo principal es Z. El lenguaje definido por la gramática G se denota por L(G). El proceso de sustitución se representa por "═══>" y determina la derivación; en sentido inverso se denomina reducción. ASG ═══> VAR = EXP ; ═══> VAR = TER REX ; ASG ═══>2 VAR = TER REX ; ═══> derivación simple ═══>2 derivación múltiple. Z ═══>+ x Є L (aplicamos una o más reglas de la gramática). + ASG ═══> VAR = TER REX ; Z ═══>* α Z ═══>0 α (aplicamos ninguna o más reglas de la gramática). Z = α Z ═══>+ α Z ═══>* α ó Z = α Si partimos del símbolo principal: Z ═══>* α Є V* α = forma sentencial Z ═══>+ x Є VT* x = sentencia x Є L(G) Se define lenguaje de una gramática G: L(G) = { x / Z ═══>G+ x Sea el árbol: /\ x Є VT* } Z ┌─────────┼─────────┐ A = B │ ┌────┴────┐ n x y │ │ 1 ; 5 Gramáticas y Lenguajes expresando su derivación: Z ══> A = B ══> n = B ══> n = x y ══> n = 1 y ══> n = 1 ; Z ═══>+ n = 1 ; Otras posibles derivaciones: Z ══> A = B ══> n = B ══> n = x y ══> n = x ; ══> n = 1 ; Z ══> A = B ══> A = x y ══> n = x y ══> n = x ; ══> n = 1 ; por tanto el árbol refleja las posibles derivaciones de una forma única. Se define frase a las secuencias que se pueden generar de un símbolo. N ═══>+ α B ═══>+ x y α es frase de N frase simple B ═══>+ 1 y frases de B. B ═══>+ 1 ; B ═══>+ x ; Las frases simples son aquéllas que se generan con la aplicación de una derivación simple; son empleadas en el programa de reconocimiento (parsing), que consiste en, dada una sentencia y una gramática, calcular una derivación para esa sentencia: Z ══> ... ══> ... ══> sentencia. esto lo realiza el análisis sintáctico. Es importante la localización de las frases simples, pues nos permitirá obtener las formas sentenciales. Si tenemos tres secuencias concatenadas de la siguiente forma: Z ══>+ α ß τ si Z ══>+ α A B y 6 A ══>+ ß entonces ß es frase de A. Gramáticas y Lenguajes La derivación canónica (rightmost derivation) consiste: dada una forma sentencial aplicamos la gramática al símbolo no terminal más a la derecha (en la reducción estará situado más a la izquierda). Z A = B A = x y A = x ; A = 1 ; n = 1 ; se representa por ══>C ó ══>rm Nos interesa realizar reducciones canónicas, ya que origina, en un conjunto de símbolos, una frase simple situada a la izquierda. A la frase simple más a la izquierda de una forma sentencial se le llama handle o pivote. handle ==> n , 1 , ; , x y , A = B El handle es interesante en un proceso de reconocimiento, ya que a la hora de construir el árbol no interesa almacenar en memoria todo el lenguaje fuente, además es normal que se lea de izquierda a derecha, y conforme se vaya leyendo el texto fuente ir construyendo el árbol: Z │ ┌────────────┬───────┴──────┬───────────┐ │ │ │ │ │ Q R │ │ ┌─────┴─┐ ┌──┴──────┐ │ │ │ │ │ │ │ │ N F G │ │ │ ┌─┴──┐ │ ┌────┼────┐ │ │ a b c d e f g h ├── (marca de final) 7 Gramáticas y Lenguajes La mayoría de los procedimientos de reconocimiento intentan que el método pueda trabajar con la misma cantidad de información antes de empezar a reducir. Todo esto lo utiliza el método ascendente. (1) bc se reducen a N sin conocer el resto. Por tanto, vamos a tener un conjunto de gramáticas asociadas a métodos de reconocimiento. Suponiendo una gramática que permite (1), realizamos dicha reducción y así eliminamos almacenamiento de memoria, quedándonos sólo con la sentencia N. La forma sentencial canónica sería: aN resto de fichero fuente; que va estar compuesto de dos partes: lo almacenado en memoria (aN) y lo que queda por leer del texto fuente. A continuación leeríamos "d", que sería el handle y lo reduciríamos a F, luego tendríamos: a N F a Q (disminuiremos capacidad de almacenamiento) Handle y así sucesivamente: a Q e f g h a Q G h handle a Q R Z En la práctica, suele ser difícil construir gramáticas en las que solamente leyendo el último elemento de la reducción se produzca ésta; como vemos hace falta también el siguiente elemento. El nombre del método suele tener un número entre paréntesis, que es el número de símbolos necesarios para realizar la reducción. Lo más normal es que sea uno (1). 8 Gramáticas y Lenguajes GRAMÁTICA RECURSIVA: Es aquélla en la que un símbolo no terminal puede ser definido a partir de ese mismo símbolo no terminal: Si N V N t.q. N + N , V * N │ ┌──┴──┐ │ │ │ │ └─────┘ α N ß (el lenguaje se convierte en infinito) La gramática es recursiva por la izquierda si α = ε, es decir: N ═══>+ N ß N │ ┌─┴─┐ │ │ │ │ └───┘ N ß generalmente no se suele admitir, ya que se llamaría a sí misma continuamente y nunca terminaría el proceso (es más problemática en reconocedores sintácticos). La gramática es recursiva por la derecha si ß = ε : N │ ┌─┴─┐ │ │ └───┘ α N N ═══>+ α N GRAMÁTICA AMBIGUA: Cuando una misma sentencia puede generarse mediante dos árboles distintos. Es decir, existe una doble interpretación. En general no es deseable: Z Z+Z│a 9 Gramáticas y Lenguajes Z │ ┌──────┴──┬────┐ │ │ │ Z │ Z │ │ │ ┌────┼────┐ │ │ │ │ │ │ │ Z │ Z │ │ │ │ │ │ │ a + a + a Z │ ┌────┬──┴──────┐ │ │ │ Z │ Z │ │ │ │ │ ┌────┼────┐ │ │ │ │ │ │ │ Z │ Z │ │ │ │ │ a + a + a Si no interesa una gramática de este tipo, deberíamos intentar cambiar de gramática de forma que ambas definieran el mismo lenguaje: Z Z Z + N │ N │ ┌────────┴──┬─────┐ N a │ │ │ Z │ N │ │ │ ┌─────┼─────┐ │ │ │ │ │ │ │ Z │ N │ │ │ │ │ │ │ │ │ │ │ │ N │ │ │ │ │ │ │ │ │ a + a + a - Se puede, dada una gramática recursiva por la izquierda, construir una gramática no recursiva por la izquierda conservando el lenguaje que genera. Para ello debemos saber qué lenguaje es el generado por una gramática dada: Dada G(Z): Z a │ b │ c │ Z a │ Z b │ Z c │ Z 0 │ Z 1 Objetivo ══► L(G) VT = { a, b, c, 0, 1 } VN = { Z } L = { x / Z ═══>+ x /\ x Є VT* } Z ═══> a ═══> a a Z ═══> Z a ═══> b a ═══> c a 10 Gramáticas y Lenguajes L = { a,b,c,aa,ba,ca,ab,bb,cb,ac,bc,cc,a0,b0,c0,a1,... } al ser una gramática recursiva, el lenguaje es infinito: Z ═══> Z a ═══> ═══> ═══> ═══> ═══> Z Z Z Z Z a b c 0 1 a a a a a en definitiva, por extensión no lo podemos especificar: L = secuencias de {a, b, c, 0, 1} que comienzan por { a, b, c } o también: L = { x y1 ... yn } n 0 /\ x Є { a, b, c } /\ yi Є VT Veamos ahora el proceso inverso: definir un lenguaje y construir su gramática: L = conjunto de naturales pares VT = { 0, 1, 2, 3,..., 9 } Todo número par constará de tres partes: {1..9} ┌───┬──────────────────┬───┐ │ P │ I │ U │ └───┴──────────────────┴───┘ {0..9} par = {0,2,4,6,8} excepto cuando son números de una o dos cifras. En general la gramática será: N P I U P 1 │..│ 9 I I0 │ I1 │ I2 │...│ I9 │ 0 │...│ 9 I I D │ D D 0 │..│ 9 U 0 │ 2 │ 4 │ 6 │ 8 simplificando 11 N │ ┌─────┼──────┐ │ │ │ P I U │ │ │ │ ┌─┴─┐ │ ┌┴┐ ┌───┐ ┌┴┐ └─┘ └───┘ └─┘ Gramáticas y Lenguajes N │ ┌─────┼─────┐ │ │ │ P I U │ │ │ │ ┌─┴─┐ │ │ │ │ │ │ I D │ │ │ │ │ │ │ │ │ │ D │ │ │ │ │ │ 3 4 5 6 Nº = 3456 - Si nº = 34 - Si nº = 2 N │ ┌─────┼─────┐ │ │ │ P I U │ │ │ │ │ │ 3 ε 4 luego: I I D │ ε N │ ┌─────┼─────┐ │ │ │ P I U │ │ │ │ │ │ ε 2 Si P lenguaje: 1 │ 2 │..│ 9 │ ε se generaría una secuencia que no está en el entonces: N P I U │ 2 │ 4 │ 6 │ 8 N │ ┌───────┼───────┐ │ │ │ P I U │ │ │ │ ┌─┴───┐ │ │ │ │ │ │ I D │ │ │ │ │ │ ┌─┴─┐ │ │ │ │ │ │ │ │ I D │ │ │ │ │ │ │ ε ε 0 5 0 12 Gramáticas y Lenguajes EJERCICIOS: 1.- a) Sea L = { a bn a / n 0 } hallar la gramática. L = { a b a, a b b a, a a, ... } VT* S T b) a T a T b │ ε n 0 L = { an bn / n > 0 } L = { a b, a a b b, a a a b b b, ... } VT+ S a S b │ a b Estos dos ejemplos corresponden a gramáticas libres de contexto que se utilizan para lenguajes de programación. También existen gramáticas más complicadas, dependientes del contexto como: L = { an bn an / n > 0 } EJERCICIOS: Construir el árbol dada la sentencia: G1 expresión E T │ E + T │ E - T término T F │ T * F │ T / F factor F ( E ) │ i E ══► símbolo principal VT = { +, -, *, /, (, ), i } VN = { E, T, F } Sentencia mínima ══► i E ═══> T ═══> F ═══> i E ═══>+ i 13 E │ │ T │ │ F │ │ i árbol mínimo Gramáticas y Lenguajes Sentencia: ( i ) E │ │ T │ │ F │ ┌─────┼─────┐ │ │ │ │ E │ │ │ │ │ │ │ │ T │ │ │ │ │ │ │ │ F │ │ │ │ ( i ) sentencia: i*i Sentencia: i * i + i E │ ┌───────────┼─────┐ │ │ │ E │ T │ │ │ │ │ │ T │ F │ │ │ ┌─────┼─────┐ │ │ │ │ │ │ │ T │ F │ │ │ │ │ │ │ │ │ │ │ │ F │ │ │ │ │ │ │ │ │ │ │ │ │ │ i * i + i 14 E │ │ T │ ┌─────┼─────┐ │ │ │ T │ F │ │ │ │ │ │ F │ │ │ │ │ │ │ │ i * i Gramáticas y Lenguajes Sentencia: i * ( i + i ) E │ │ T │ ┌─────┬─────┴───────────┐ │ │ │ T │ F │ │ │ │ │ ┌───────────┼───────────┐ F │ │ │ │ │ │ │ E │ │ │ │ │ │ │ │ │ ┌─────┼─────┐ │ │ │ │ │ │ │ │ │ │ │ E │ T │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ T │ F │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ F │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ i * ( i + i ) ¿ Cuáles son las frases que hay en E + T * F, y de ellas cuáles son simples ? ┌─────────┐ │ │ frases └─────────┘ E │ ┌─────┬──┴────────┐ │ │ │ │ │ T │ │ │ │ │ ┌─────┼─────┐ │ │ │ │ │ E + T * F frase simple (handle) Para un árbol podemos tener múltiples derivaciones pero también es posible que una gramática nos permita, para una sentencia, construir varios árboles. A esta gramática se le denomina gramática ambigua y, en principio, no es deseable (la vimos antes): Sea G2 : E ─── E + E │ E - E │ E * E │ E / E │ ( E ) │ i 15 Gramáticas y Lenguajes L(G1) = L(G2) E A1 │ i * i + i ┌────────┴──┬─────┐ │ │ │ E │ E │ │ │ ┌─────┼─────┐ │ │ │ │ │ │ │ E │ E │ │ │ │ │ │ │ i * i + i E │ ┌─────┬──┴────────┐ │ │ │ E │ E │ │ │ │ │ ┌─────┼─────┐ │ │ │ │ │ │ │ E │ E │ │ │ │ │ i * i + i E * E + E frases simples. existe solapamiento. Lo que interesa es que el árbol refleje la gramática utilizada, por ejemplo, en G1 se refleja que el producto es prioritario con respecto a la suma. En algunos métodos de reconocimiento nos interesa construir una gramática ambigua siempre que pudiésemos reducir el tamaño de los árboles, pero siempre necesitaríamos un mecanismo adicional para realizar el árbol de forma única. EJERCICIOS: a) L = { 1n 0m / n > m > 0 } n > m ══ n = 2, 3, ... m = 1, 2, ... L = { 110, 1110, ... , 11100, 111100, ... , 1111000, ... } Lo descomponemos en LA = 1p igual número de 1 que de 0 al menos un 1 p > 0 LB = 1q 0q L = LA LB q > 0 S A B A A 1 │ 1 B 1 B 0 │ 1 0 16 Gramáticas y Lenguajes S │ ┌───────┴─────────┐ │ │ A B │ │ ┌──┴──┐ ┌────────┼────────┐ │ │ │ │ │ A │ │ B │ │ │ │ │ │ │ │ │ ┌──┴──┐ │ │ │ │ │ │ │ 1 1 1 1 0 0 L = { 1n 0n 1m 0m / n,m 0 } b) LA = { 1m 0m / m 0 } 0n L = LA LA = LA2 / n 0 } LA = { 1n S A A A 1 A 0 │ ε ε pertenece a L Gramática Ambigua para ε S │ ┌──┴──┐ │ │ A A │ │ │ │ ε ε c) L = { 1n 0m 1m 0n / n,m 0 } S 1 S 0 │ A A 0 A 1 │ ε 17 S │ - - - - -┼─────────┐ │ │ │ A A A │ │ │ ε ┌─────┼─────┐ │ │ │ │ ε │ A │ │ │ │ │ ┌──┼──┐ │ │ │ │ │ │ │ │ A │ │ │ │ │ │ │ │ │ │ │ │ 1 1 ε 0 0 Gramáticas y Lenguajes d) L = { 1n 0n } U { 0m 1m } LA LA LB = { ε } LB LA = { ε, 10, 1100, ... } LB = { ε, 01, 0011, ... } L = { ε, 10, 1100,.., 01,0011,... } S A │ B A 1 A 0 │ ε B 0 B 1 │ ε L = { 13n+2 0n / n 0 } e) m,n 0 S 1 1 A A 1 1 1 A 0 │ ε 13n+2 0n = 12 13n 0n = 12 (13)n 0n ó S 1 1 1 S 0 │ 1 1 f) L = {1, 0,de igual número de ceros y unos, no importa el orden } L = {ε, 1 0, 0 1, 1 1 0 0, 0 0 1 1, 1 0 1 0, 0 1 0 1, 1 0 0 1, 0 1 1 0, ... } (NO)A 1 0 A │ 0 1 A │ A 1 0 │ A 0 1 │ 1 A 0 │ 0 A 1 │ A A │ ε o también: g) A A A │ 1 A 0 │ 0 A 1 │ ε L = { 1n 0m 1p / n+p > m 0 } m = 0,1,... p+n = 1,... ┌───────┐┌───┐ │1 1 0 0││0 1│1 └───────┘└───┘ S 1 A B C A │ A B C A 1 B 1 B 0 │ ε C 0 C 1 │ ε A A 1 │ ε ┌───────────┐ 1│1 1 1 0 0 0│1 └───────────┘ n(0) = n(1) Gramática Ambigua El Lenguaje no puede ser generado por una gramática independiente del contexto, sino por una dependiente del contexto. 18 Gramáticas y Lenguajes EJERCICIOS: Dada una gramática ver el lenguaje que genera: a) S 1 0 S 0 │ a A S 1 0 S 0 A b A │ a S a A A b A A a S │ ┌──────┼──────┐ │ │ │ (1 0)n S 0n │ ┌───┼───┐ │ │ │ a bm a L = { (1 0)n a bm a 0n / n,m 0 } b) S S S │ 1 A 0 S S S A 1 A 0 │ ε S 1 A 0 A 1 A 0 A ε S │ ┌───┴───┐ │ │ S S │ │ ┌─┴─┐ ┌─┴─┐ │ │ │ │ S S S S Cada S genera una secuencia 1m 0m L = { 1m1 0m1 1m2 0m2 ... 1mk 0mk / mi > 0 i=1..k n L={ ( 1 m m 0 ) / m > 0, n > 0 } i=1 19 k > 0 } m > 0 Gramáticas y Lenguajes c) S 1 A │ B 0 S 1 A A 1 A │ C S B 0 B B 0 │ C A 1 A C 1 C 0 │ ε A C B B 0 B C C 1 C 0 C ε 1 1q 0n = 1r 0n r > n 0 1n 0m 0 = 1n 0p p > n 0 1q 0n qn0 1n 0n 0s = 1n 0m s 0 m n 0 1n 0n n 0 L = { 1n 0p / p > n 0 } U { 1r 0n / r > n 0 }= = { todas las sentencias con distinto número de 1 que de 0 } = = { 1n 0m / m <> n } d) S b A D c D G i A A G S G ε No crea ningún lenguaje. 20 Gramáticas y Lenguajes RELACIONES: Sea un conjunto D = { a, b, c, ..., z } y sean b y c dos elementos del conjunto D. Decimos que b está relacionado con c y lo denotamos por b R c, si se cumple una propiedad entre estos dos elementos. Otra forma de denotar que b está relacionado con c, aparte de b R c, es por medio de un par de elementos ordenados (b,c) que no es lo mismo que (c,b). Se trata de RELACIONES BINARIAS ya que se establecen entre dos elementos. A veces se define una relación como un conjunto de pares ordenados entre sí: x, y D. R = { ...,( b,c ), ... } = { ( x, y ) / x R y } Se define relación traspuesta de R y se denota por RT: RT = { (y,x) / x R y } R = { (a,b), (a,c), (b,c) } RT = { (b,a), (c,a), (c,b) } PROPIEDADES DE UNA RELACIÓN: - Reflexiva: x D x R x. - Simétrica: x, y D x R y y R x - Transitiva: x, y, z D Si x R y y R z x R z Una relación R está contenida en P si todas las parejas de R están en P: R P Si a R b a P b. PRODUCTO DE DOS RELACIONES: Dadas dos relaciones P y R: P * R = Q a P b /\ b R c ══> a Q c = a P*R c Si P = R ══> P*R = R2 21 Gramáticas y Lenguajes Ejemplo: D = { personas } R2 = a R b /\ R = "ser padre de" b R c ═══> a Q c R2 = Q = "ser abuelo de" Propiedades El producto de dos relaciones es asociativo: (P*Q)*R = P*(Q*R) = P*Q*R R*R*R = R3 R4 = R3*R = (R2)2 I = R0 Relación de identidad a R a b R b c R c (relaciona a todo elemento consigo mismo y nada más). a I a b I b c I c R1 = R SUMA DE RELACIONES (UNIÓN): P + R = Q a,b D a P b a Q b Q= P R a,b D a R b a Q b Q = P R = { (x, y) / (x, y) P (x, y) R } 22 Gramáticas y Lenguajes CIERRE TRANSITIVO: Llamamos cierre transitivo de una relación R, y lo expresamos R+, a la unión de todas las potencias de la relación R, a partir de la potencia uno: R+ = R1 + R2 + ... R R+ a,b D a R b a R+ b - Si a R+b Dem: Si /\ b R+c ═══> a R+c a R+b ═══> Existe n b R+c ═══> Existe p a Rnb b Rpc ═══> a Rn+pc = a R+c Así mismo, llamamos CIERRE TRANSITIVO REFLEXIVO de una relación R y lo denotamos R*, a la unión de todas las potencias de esa relación empezando por la potencia cero (Identidad): R* = R0 + R1 + R2 + ... R R* R* = R0 + R+ a si a R0 a a R* a 23 Gramáticas y Lenguajes IMPLEMENTACIÓN DE UNA RELACIÓN EN LA MAQUINA: El método de representación de una relación se puede realizar considerando la pareja ordenada (a,b) como índices de una matriz: a1 a2 . . . an a1 a2 ... an ┌──────────────────┐ │ │ │ │ │ │ │ R │ │ │ │ │ │ │ │ │ └──────────────────┘ n*n Esta matriz es binaria, contendrá un 1 si a R b y 0 en caso contrario. Por tanto, será una matriz booleana de n*n bits que nos definirá la relación por extensión: _ R[a,b] = 0 ◄══► a R b R[a,b] = 1 ◄══► a R b R[ai,aj] = Rij * Operación suma de dos relaciones R y P: a R b ══> a (R+P) b = a Q b a P b ══> a (R+P) b = a Q b Rij = 1 ══> Qij = 1 Pij = 1 ══> Qij = 1 R+P Rij 0 0 1 1 Pij 0 1 0 1 Qij 0 1 1 1 Suma lógica (OR) de las dos matrices. (adición binaria) 24 Gramáticas y Lenguajes * Operación producto de dos relaciones R y P: a R b ══► a R*P c = a Q c b P c Q = R*P Rij = 1 Qik = 1 /\ Para todo j Pjk = 1 Rij * Pjk = Qik n Qik = Rij P jk ══► Producto lógico (AND). (binario) Sumabinaria j=1 * Operación traspuesta: a R b ═══> b RT a Q = RT b Q a Rij = Qji * Operación identidad: a R0 a R0ii = 1 ij Rij = 0 si i j ┌────────────┐ │1 │ │ . 0 │ │ . │ │ . │ │ 0 . │ │ 1│ └────────────┘ 25 Gramáticas y Lenguajes R+ = R1 + R2 + ... + Rn Rij = Rij R2jk n 3 j=1 R* = R0 + R1 + ... + Rn Una vez calculada la relación R, podemos calcular todo lo demás. RELACIONES BINARIAS APLICADAS A LENGUAJES FORMALES: Hasta ahora hemos hablado de las relaciones en general. Muchas veces nos interesará establecer relaciones entre elementos del V = VT + VN y también entre elementos de V*. - Podemos ver las derivaciones (══>) como una relación que aplicamos a un conjunto de secuencias: α α N ß ══> ß α,ß pertenecen a V* α = α1 N α2 R ß τ /\ N pertenece a VN α1,α2,τ pertenecen a V* = α1 τ α2 α1 N α2 ═══> α1 τ α2 α ß - Esta relación la establece la gramática. Producto de Derivaciones: α ══> ß /\ ß ══> τ implica que: α ══>2 τ En general podemos tener: α ══>+ ß (derivación doble) si Existe n t.q. α ══>n ß n > 0 α ══>* ß Si n = 0 α ══>0 ß implica que: 26 si Existe n t.q. α ══>n ß n 0 α = ß Gramáticas y Lenguajes N - Nos interesa más una relación entre símbolos: Definimos la relación: N C M = N P M C = Cabeza P = Primero Si: N ══> M α α pertenece a V* M pertenece a V N pertenece a VN M ● ● ● α - Relación P+: n P = Pi + i=1 N P S1 P S2 ... Sn P S N, S1, S2, ..., Sn Є VN N ═══> S1 α1 S1 ═══> S2 α2 . . . Sn-1 ═══> Sn αn N ═══>+ S αn+1 αn αn-1 ... α2 α1 ß pertenece a V* Sn ═══> S αn+1 N P+ S ◄══► N ══>+ S ß - Relación último (U): N U M si N ══> α M N V N , M V , V * - Relación U+: n + U = U i i=1 N U+ S ◄══► N ══>+ ß S / ß pertenece a V* 27 Gramáticas y Lenguajes - Relación Dentro (D): N D M si N ══> α1 M α2 N V N , M V 1 , 2 V * - Relación D+: n + D = Di i=1 N D+ S ◄══► N ══>+ ß1 S ß2 / ß1,ß2 pertenecen a V* UD ══>* = PD ══>0 + ══>1 + ══>2 + ... N ══> α M N α M RESTRICCIONES DE UNA GRAMÁTICA: Para que una gramática tenga sentido, existen ciertas restricciones que deben cumplirse: 1) No existan reglas de la forma N N , ya que no aportan nada a la gramática y hacen los árboles ambiguos e infinitos. 2) Todo símbolo del vocabulario debe ser accesible a partir del símbolo principal de la gramática (Z): N V N Ejemplo: 3) Z A B N Z * N , V * AB 01 1B│ε 0 0 1 ───> no construye ninguna sentencia. Para todo símbolo no terminal N, desde N se pueda generar una secuencia de símbolos terminales: N V N N + x donde x V *T 28 Gramáticas y Lenguajes CHEQUEO DE LAS RESTRICCIONES DE LA GRAMÁTICA: El proceso a seguir será: aplicar las reglas 2 y 3 iterativamente y al final aplicar la regla 1. Veamos la siguiente propiedad: Prop.: Si Z ══>+ α N ß /\ N ══> α' M ß' entonces Z ══>+ α'' M ß'' Por tanto, para verificar la regla 2, compruebo los símbolos no terminales que verifican Z ══> α N ß y marco los N como accesibles, y así sucesivamente, ya que cualquier M que cumpla N α' M ß' también será accesible y marcado como tal. Una vez dada una pasada en la que no hayamos marcado ninguno, aquellos que se hayan quedado sin marcar no cumplirán esta restricción y por tanto serán eliminados. Para verificar la regla 3 veamos la siguiente propiedad: N1 ══>+ x1 . . . Nk ══>+ xk 1 M xi pertenece a VT Ni pertenece a VN y1 N1 y2 N2 ... Nk yk+1 entonces yj pertenece a VT M ══>+ z pertenece a VT* M ══>+ y1 x1 y2 x2 ... yk xk yk+1 = z pertenece a VT* M │ ┌─────────┬─────────┬─────────┼─────────┬─────────┬────────┐ y1 N1 y2 N2 . . . . Nk yk+1 ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ │ │ │ │ . . . . │ │ └───┘ └───┘ └───┘ x1 x2 xk El proceso a seguir es el siguiente: buscamos aquellos símbolos que verifican N x x pertenece a VT*, es decir, que N ══>+ x perteneciente a VT* y los marcamos (a los N), y haríamos un proceso iterativo que aplicaría la propiedad 1, donde todos los N deben estar marcados: Si M y1 N1 ... yk Nk yk+1 * yi pertenecen a VT Ni marcados para todo i entonces marco M. 29 Gramáticas y Lenguajes Tras una pasada en la que no marquemos ningún símbolo no terminal nuevo, se acaba el proceso y se eliminan los no marcados. Al final se aplica la regla 1 y así se acaba el proceso global. Veamos un ejemplo: Ejemplo: Z E F P G T Q S E E F G G T E i + T │ S + F │ T │ F P │ P │ G G │ F * i │ i │ E + T │ T │ S Los símbolos que se marcan que verifican la regla 2 son los siguientes: Z, E, T, S, F, P, G ya que, Para todo N Z ══>+ α N ß, se ha quedado sin marcar Q. Z ══> E + T ══> S + F + T Z ══>* α S ß α = ε ß = + F + T Luego la gramática resultante sería: Z E F P G T S E E F G G T i + T │ S + F │ T │ F P │ P │ G G │ F * i │ i Los símbolos que verifican la regla 3 son: S, T, E, Z, ya que: Para todo N ══>+ x perteneciente a VT* y los no marcados son F, P, G, luego al final de la primera pasada la gramática resultante sería: Z E T S E + T E │ T T * i │ i i 30 Gramáticas y Lenguajes En la segunda pasada, S no se marca debido a la regla 2, luego resulta: Z E T E + T E │ T T * i │ i Aplicando finalmente la regla 1, obtenemos la gramática final: Z E T E + T T T * i │ i NOTACIÓN BNF EXTENDIDA (EBNF): La notación para las gramáticas que hemos venido utilizando hasta ahora es la llamada BNF. En esta notación aparecían algunos metasímbolos como: , <, >, ::=, etc, de la siguiente forma: < símbolo no terminal > ::= < símbolo no terminal > begin < expresión > ::= < expresión > ± < término > │ < término > Esta notación ocasiona una especie de lenguaje que se define como el lenguaje cuyas sentencias están en BNF, y como está compuesto por metasímbolos (permiten trabajar con gramáticas que empleen otros símbolos), este lenguaje se denomina metalenguaje, ya que permite definir otro lenguaje. La notación EBNF añade otros metasímbolos como son: { }, [ ], ( ), ' '. Veamos el significado de cada uno de ellos: -{}: Indica que lo que está en su interior se puede repetir un número cualquiera de veces (0..N): N { A } N ε │ A │ A A │ A A A │ ... 31 Gramáticas y Lenguajes -[]: Indica que lo que está en su interior es opcional, por tanto se repite una o ninguna vez: <instruc.condic.> ::= if <cond.> then <instrucc.> [else <instrucc.>] < N > ::= A [ B ] C < N > ::= A B C │ A C - También puede aparecer en una regla la combinación de llaves y corchetes: A ab [c {d} e] f abf, abcef, abcdef, abcddef, ... A ab {c [ de ]} f abf, abcf, abcdef, abcdecf, abccdecdef,.. A [a │ b] c A ac │ bc │ c c, ac, bc. A { a │ b } c c, ac, bc, aac, bbc, abc, bac, ... -(): Realizan lo que en aritmética se denomina sacar factor común. Se realiza solo una vez lo que aparece dentro: abcd │ abe A ───> ab ( cd │ e ) { ( a │ b ) c } d d, acd, bcd, acacd, bcbcd, acbcd, ... 32 Gramáticas y Lenguajes -'': Sirven para distinguir un símbolo que sea igual a un metasímbolo: F ( E ) │ a F '(' E ')' │ a A las secuencias que se puedan generar con estos metasímbolos se les llama expresiones regulares y a su metalenguaje, lenguaje de expresiones regulares. DIAGRAMAS SINTÁCTICOS: Otra notación más cómoda para el usuario, pero no para el computador son los llamados diagramas sintácticos, cuyo conjunto representa a una gramática. Los símbolos terminales se representan encerrados en un círculo, mientras que los símbolos no terminales se encierran en un rectángulo. La concatenación se representa mediante flechas que unen a los símbolos: E E + T │ T E E + T T E E [ + E ] T + E T 33 Gramáticas y Lenguajes E T { + T } T E + + E T T Simplificando: El proceso de sustitución consiste en transformar el símbolo no terminal por su diagrama sintáctico correspondiente: E T F T { + T } F { * F } '(' E ')' │ a T E + E T F T + * * T F F ( E a 34 T ) F Gramáticas y Lenguajes Sustituyendo: + * E F + * ( ) E E a JERARQUÍA DE GRAMÁTICAS DE CHOMSKY: Se distinguen cuatro tipos de gramáticas, donde cada tipo de gramática es englobada por las de jerarquía superior: ┌───────────────────────────────┐ │ tipo 0 │ │ ┌───────────────────────┐ │ │ │ tipo 1 │ │ │ │ ┌───────────────┐ │ │ │ │ │ tipo 2 │ │ │ │ │ │ ┌───────┐ │ │ │ │ │ │ │tipo 3 │ │ │ │ │ │ │ └───────┘ │ │ │ │ │ │ │ │ │ │ │ └───────────────┘ │ │ │ │ │ │ │ └───────────────────────┘ │ │ │ └───────────────────────────────┘ 35 Gramáticas y Lenguajes Las gramáticas que hemos visto hasta ahora son las de tipo 2 o independientes del contexto. Cada tipo de gramática se caracteriza por la forma de sus reglas o producciones: G ( VT, VN, Z, R ) Además, se caracterizan por sus restricciones, cuantas más restricciones haya menor es el conjunto de gramáticas a construir, y también por los reconocedores que son capaces de reconocer el lenguaje. -TIPO 0 (phrase-structured grammars): Son las gramáticas más generales, denominadas gramáticas con estructura de frase. Sus reglas son de la forma: , V + V = V T V N Sentencias del tipo: a N M x nQ a b c Q a N M x x y M ══> a b c Q n Q x y M Se sustituyen por símbolos terminales y no terminales. Los autómatas que reconocen estos lenguajes son las máquinas de Turing. Esta gramática es muy potente pero tiene el inconveniente de ser muy compleja la derivación. - TIPO 1 (context-dependent grammars): Son las gramáticas dependientes del contexto, de la forma: 1 2 1 N 2 N V N 1 , 2 V * V + Ejemplo: a N M x ══> a n Q M x a = α1 M x = α2 N = N ß = n Q Sus reconocedores son los autómatas linealmente limitados (lineas-bounded autom). 36 Gramáticas y Lenguajes - TIPO 2: Son las gramáticas independientes del contexto (context-free grammars), son de la forma: N N V N V * Sus reconocedores son los autómatas de pila. Existen para ellos buenos métodos prácticos pero muy complejos para aplicarlos a compiladores, por lo que se suele utilizar un subconjunto. (PARSER). - TIPO 3: Son las más elementales, llamadas gramáticas regulares (regular grammars), de la forma: N a N M a N, M V N a V T Sus reconocedores son los autómatas finitos. Reconocedores léxicos (SCANNER). Todas las gramáticas regulares originan un conjunto de secuencias llamadas expresiones regulares. Veamos ahora como se construyen los autómatas finitos, para a partir de ellos elaborar los analizadores léxicos. 37 Gramáticas y Lenguajes REFERENCIAS BIBLIOGRÁFICAS: [Sanchis 86] Sanchis Llorca, F. J. y Galan Pascual, C. Compiladores; Teoría y construcción. Paraninfo. S. A. Madrid. [Sánchez 89] Sánchez Dueñas, G. y J. A. Valverde Andreu. Compiladores e Intérpretes; Un enfoque pragmático. (2ª Edición. Corregida y ampliada). Díaz de Santos. Madrid. [Gries 75] Gries, D. Construcción de Compiladores Paraninfo. Madrid. [Aho 72] Aho, A.V. and J.D. Ullman. The Theory of Parsing, Translation, and Compiling (Volume 1: Parsing) Prentice-Hall, Inc. Englewood Cliffs, N.J. [Alfonseca 87] Alfonseca, M., Sancho, J. y M.M. Orga. Teoría de Lenguajes, Gramáticas y Autómatas. Universidad y Cultura. Madrid. [Fortes 87] Fortes, J. Recopilación de apuntes de la asignatura Traductores e Intérpretes. Curso 86-87. 38