Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Índice general
I Introducción 3
I.1 Lenguaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
I.1.1 Lenguajes particulares . . . . . . . . . . . . . . . . . . . . . . 4
I.1.2 Operadores de utilidad . . . . . . . . . . . . . . . . . . . . . . 4
I.2 Expresiones regulares . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
II Gramática 7
II.1 Gramáticas independientes del contexto . . . . . . . . . . . . . . . . . 10
IV Autómatas a pila 19
V Gramáticas de atributos 23
V.1 Análisis semántico . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
VI Analizador morfológico 34
VIIAnalizador sintáctico 36
VII.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
VII.2 Tablas de análisis ascendente . . . . . . . . . . . . . . . . . . . . . . 38
VII.2.1 Tablas LR(0) . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
VII.2.2 Tablas SLR(1) . . . . . . . . . . . . . . . . . . . . . . . . . . 44
VII.2.3 Tablas LR(1) . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
VII.2.4 Tablas LALR(1) . . . . . . . . . . . . . . . . . . . . . . . . . 51
VII.3 Análisis descendente . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
VII.3.1 Forma normal de Greigbach . . . . . . . . . . . . . . . . . . . 53
VII.3.2 ¿Cuándo nos interesa eliminar las transiciones λ? . . . . . . . . 56
VII.3.3 Análisis LL(1) usando la tabla . . . . . . . . . . . . . . . . . . 56
VII.3.4 Análisis LL(2) usando la tabla . . . . . . . . . . . . . . . . . . 59
VII.3.5 Análisis LL(*) . . . . . . . . . . . . . . . . . . . . . . . . . . 60
1 de 100
Autómatas y lenguajes - 2014/2015 - UAM Pedro Valero y Alberto Parramón
A Ejercicios 70
A.1 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
B Ejercicios 1a Hoja 73
B.1 Ejercicios sobre autómatas finitos y lenguajes regulares . . . . . . . . . 73
B.2 Ejercicios sobre autómatas a pila y gramáticas independientes del contexto 77
C Ejercicios 2a Hoja 79
C.1 Ejercicios sobre Gramáticas de Atributos . . . . . . . . . . . . . . . . 79
D Ejercicios 3a Hoja 86
D.1 Ejercicios de análisis . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
2 de 100
Autómatas y lenguajes - 2014/2015 - UAM Pedro Valero y Alberto Parramón
Capítulo I
Introducción
Máquinas/Autómata
• Autómatas finitos ⇒ Expresiones regulares
• Autómatas de pila ⇒ Lenguajes independientes del contexto
Problemas ¿Qué se puede computar?. Conjeturas que se creen ciertas pero cuya
veracidad, por ahora, no se ha demostrado.
Lenguajes/Gramática
Nuestro objetivo es ver qué relación existe entre estos tres elementos. Para ello,
primero debemos establecer algunas definiciones.
I.1. Lenguaje
P P∗
Lenguaje Definición I.6 Lenguaje universal (sobre ). Denotado por representa el
universal
P conjunto de todas las palabras que se pueden formar con los símbolos de Σ, incluido
(sobre ) λ.
Lenguaje Definición I.8 Lenguaje vacío. Lenguaje que no contiene ningún elemento: φ.
vacío
Lenguaje Definición I.9 Lenguaje {λ}. Lenguaje que sólo contiene λ. El lenguaje {λ} es
{λ} distinto del lenguaje vacío aunque λ sea la palabra vacía. En particular |{λ}| = 1 y
|φ| = 0.
Lenguajes Definición I.11 Lenguajes Regulares. Son lenguajes que pueden ser admitidos por
Regulares autómatas finitos.
En otras palabras, estos conceptos nos sirven para entender por qué Σ∗ representa todas
las palabras posibles. Para poder entender esto debemos entender la multiplicación
como una concatenación y la suma como un OR. Así el “elemento neutro del producto”
sería la cadena vacía.
Tomemos ahora el alfabeto binario Σ = {0, 1} Entonces:
1. ∅
L(∅) = ∅
2. λ
L(λ)={λ}
3. a ∈ Σ
L(a) = {a}
1. α + β (Unión de lenguajes)
L(α + β) = L(α) ∪ L(β)
3. α∗ (Cierre)
L(α∗ ) = L(α)∗
L(β ∗ ) = L(β)∗
El cierre es la repetición de cero o más veces de las expresiones regulares a las
que aplica.
1. *
2. .
3. +
Ejemplo: Encontrar los lenguajes definidos por las siguientes expresiones regulares:
1. a.(b + a).b
Cadenas de tres símbolos que empiezan por ’a’ y acaban por ’b’ y el símbolo
central es una ’a’ o una ’b’: {abb,aab}
2. (a + b)
Cadenas de un solo símbolo, que es o ’a’ o ’b’: {a,b}
3. (a + b)∗
Todas las cadenas posibles formadas por los símbolos a y b (incluso la cadena
vacía)
4. (a + b).(a + b)∗
Todas las cadenas posibles formadas por los símbolos a y b. Pero no incluye la
cadena vacía ya que por (a + b) necesariamente deben contener una ’a’ o una
’b’.
5. (aa + bb)∗
Todas las cadenas posibles formadas por ’a’ y ’b’ con la condición de que siempre
aparezcan los símbolos consecutivos un número par de veces. Es decir, cadenas
del tipo ’aaaabbaabbbbbb’, (no valdría ’aaabb’) (incluyendo la cadena vacía).
Capítulo II
Gramática
Gramática Definición II.1 Gramática. Hay varias definiciones para este término. No son muy
precisas pero nos dan una idea de su significado:
3. PREDICADO → VERBO
4. ARTÍCULO → el | un
Estas reglas constituyen una gramática que nos permite generar un lenguaje. En este
caso el lenguaje estaría por formado todas las cadenas que se pueden construir a partir
de estas reglas. Empezando siempre por el axioma (en este caso: “ORACIÓN”).
Una gramática está compuesta por una serie de elementos que definiremos a
continuación.
Símbolos Definición II.2 Símbolos terminales (T). Conjunto de símbolos que pueden aparecer
terminales en la cadena final (o sentencia). En el ejemplo anterior serían elementos terminales
(T) aquellos escritos en minúscula. Para ellos no existe ninguna regla que indique cómo se
derivan.
Reglas de Definición II.4 Reglas de producción (P). Explican cómo se transforma un símbolo
producción no terminal en un conjunto de símbolos terminales y/o no terminales.
(P)
Símbolo Definición II.5 Símbolo inicial / Axioma (S). Indica dónde empieza a construirse
inicial / la cadena. En el ejemplo anterior, el axioma sería el símbolo ORACIÓN. Una gramática
Axioma sólo puede tener un único axioma.
(S)
G = (T, N, P, S)
Una gramática permite generar cadenas para un lenguaje. Por ejemplo, para la
gramática anterior:
ORACIÓN → (derivamos ORACIÓN:)
SUJETO PREDICADO → (derivamos SUJETO:)
ARTÍCULO NOMBRE PREDICADO → (derivamos ARTÍCULO:)
el NOMBRE PREDICADO → (derivamos NOMBRE;)
el coche PREDICADO → (derivamos PREDICADO:)
el coche VERBO → (derivamos VERBO:)
el coche corre (acabamos, pues no hay más que derivar)
Este proceso se llama derivación. Cada una de las cadenas en una derivación
se denomina forma sentencial. La última de ellas es una cadena válida del lenguaje
generado por la gramática, y se denomina sentencia. Está formada únicamente por
símbolos terminales de la gramática. El lenguaje generado por una gramática, L(G),
es el conjunto de todas las sentencias posibles, es decir, el conjunto de todas las cadenas
de símbolos no terminales que pueden derivarse a partir del axioma.
Vamos a ver algunos ejemplos de gramáticas y los lenguajes que generan:
1. S → aSb
2. S → λ
T = {a, b}
N = {S}
Y su axioma es S.
El lenguaje generado por esta gramática serían todas las palabras de la forma: ai bi
con i = 0, 1, ...∞
1. S → abS
2. S → a
Gramáticas Definición II.7 Gramáticas independientes del contexto. Son aquellas cuyas
indepen- reglas tienen un único símbolo no terminal en el lado izquierdo.
dientes del
contexto
Ejemplo: Gramática dependiente de contexto
aSb → abb
cSd → cdd
A → aA
A→a
B → aA
B→a
B → Aa
B→a
A→x
Con A ∈ N , x ∈ Σ∗ con Σ = T ∪ N
Ejemplo: El lenguaje:
L = {wwR : w ∈ (a + b)∗ }
es independiente del contexto puesto que puede representarse por medio de una
gramática G independiente del contexto, que sería:
S → aSa
S → bSb
S→λ
Para demostrar que el lenguaje generado por la gramática, L(G), es el mismo que
L, habría que hacer dos cosas:
El punto 1 es fácil de ver, pues está claro que cualquier cadena generada por G es
simétrica (siempre que añadimos una a al principio añadimos otra al final, y lo mismo
para b).
Para demostrar el punto 2 vamos a probar que si w ∈ L entonces w ∈ L(G)
usando inducción:
Derivación Definición II.9 Derivación directa. Dada una gramática independiente del contexto
directa G=(N,T,S,P) y sean v, w dos formas sentenciales, decimos que w es derivación directa
de v:
v → w ≡ v = xZy ∧ w = xαy ∧ ∃ regla en P Z → α
con Z ∈ N y α ∈ Σ∗ .
Derivación Definición II.10 Derivación. Dada una gramática G=(N,T,S,P) y sean v, w dos
formas sentenciales, decimos que w es derivación de v, y lo escribimos v →+ w, si
existe una cadena de formas sentenciales a0 , a1 , a2 ,... an , tales que:
v = a0 → a1 → a2 → ... → an = w
Lenguaje Definición II.11 Lenguaje generado por G. Dada una gramática G=(N,T,S,P)
generado definimos el lenguaje generado por ella como:
por G
L(G) = {w ∈ T ∗ : S →+ w}
L = {an bn : n ≥ 0}
S→λ
S → aSb
S → aSb|bSa|λ
S → SS
Para construirla nos hemos fijado en que una palabra w puede ser de 4 formas:
aw0 b con w0 ∈ L
bw0 a con w0 ∈ L
w=
aw0 a ⇒ w = w1 w2 con w1 , w2 ∈ L
bw0 b ⇒ w = w1 w2 con w1 , w2 ∈ L
Una sentencia puede ser derivada de diferentes formas a partir de una misma
gramática. Para estos casos vamos a definir derivaciones “leftmost” y “rightmost”:
Leftmost Definición II.12 Leftmost. Consiste en derivar, en cada paso, el elemento no terminal
colocado más a la izquierda. Se deja para el lector el arduo trabajo de deducir que
significa una derivación “rightmost”.
Esto nos lleva a definir un nuevo concepto:
Ambigüedad Definición II.13 Ambigüedad. Una gramática se define como ambigua si existen dos
o más árboles de derivación distintos para la misma sentencia.
Otra forma de definirlo sería considerar ambiguas aquellas gramáticas para las que
existen dos derivaciones leftmost (o rightmost) distintas para la misma sentencia.
E → E + E|E × E|I
I → a|b|c
1. E → E + E → I + E → a + E → a + E × E → a + I × E → a + b × E →
a+b×I →a+b×c
2. E → E × E → E + E × E → I + E × E → a + E × E → a + I × E →
a+b×E →a+b×I →a+b×c
Ya vimos que dos gramáticas son equivalentes si generan el mismo lenguaje pero
vamos a recalcar que hay infinitas gramáticas que generan el mismo lenguaje.
Dada una gramática G=(T,N,S P) para obtener otra equivalente basta con hacer
otra:
G0 = (T, N ∪ {Z}, Z, P ∪ {Z → E})
Capítulo III
Q = conjunto de estados
Σ = alfabeto de entrada
δ = función de transición: δ : Q × Σ → Q
q0 = estado inicial ∈ Q
F = conjunto de estados finales, F ⊂ Q
Lenguaje Definición III.3 Lenguaje aceptado por un AFD. El lenguaje aceptado por un
aceptado autómata finito determinista, A, es el conjunto de palabras que llevan al autómata a
por un un estado final.
AFD
L(A) = {w ∈ Σ∗ : δ ∗ (q0 , w) ∈ F }
entrada: 1 0 1
q0 q1 q3 q4
entrada: 1 0 1
q0 q1 q4 q5
q2 - -
Como al menos uno de los caminos lleva a un estado final, la cadena "101" forma
parte del lenguaje del autómata (los guiones indican transición no definida, o a un
estado vacío).
La ventaja de un autómata no determinista es que podemos explorar varias ramas
en paralelo.
Transición Definición III.4 Transición λ. Transición que puede ocurrir sin consumir ningún valor
λ de entrada. Un autómata finito que tenga transiciones de este tipo se considera no
determinista.
Autómata Definición III.5 Autómata finito no determinista. AFN . Autómata con función
finito no de transición de la forma:
deter-
δ : Q × (Σ ∪ {λ}) → 2Q
minista.
AFN Es decir, dado un estado y una entrada (posiblemente vacía) salta a un conjunto de
estados.
Lenguaje Definición III.7 Lenguaje aceptado por un AFN. El lenguaje aceptado por un
aceptado autómata finito no determinista, A, es el conjunto de palabras que llevan al autómata
por un a un estado final.
AFN
L(A) = {w ∈ Σ∗ : δ ∗ (q0 , w) ∩ F 6= ∅}
El autómata queda:
Estados 1 0 1
q0 - - -
q1 q2 q4 q5
Esto significa que dado un autómata finito determinista que acepta un determinado
lenguaje, existe otro no determinista que acepta el mismo lenguaje, y viceversa. Se
utilizan los AFN por comodidad, porque las demostraciones formales son más sencillas.
4. Mediante un AFN/AFD
Capítulo IV
Autómatas a pila
Dado el lenguaje:
L = {wwR w ∈ (0 + 1)∗ }
que representa palabras capicúas sobre {0, 1} con un número par de símbolos, vamos
a intentar construir un autómata finito para él.
Esto no es posible ya que siempre necesito llegar hasta la mitad de la palabra
“almacenando” lo que hemos leído para después comprobar que lo leemos al revés.
Puesto que la palabra puede tener longitud arbitraria, necesitaremos una cantidad de
memoria arbitraria y esto no es viable (sería necesario un autómata con un número
infinito de estados).
Es aquí donde surgen los autómatas a pila. Estos autómatas se caracterizan por
que en cada salto indicamos una entrada, saca el símbolo de la cima de la pila y añade
una cadena a la pila.
Para el lenguaje dado, el autómata a pila que lo representa sería:
Acb
donde A sería la entrada leída, b el elemento que extraemos del tope de la pila y c la
cadena que insertamos en la pila. Por tanto una transición solo se puede dar si aparte
de tener la entrada correspondiente, la cima de la pila coincide con lo que vamos a
extraer de ella. Introducir az implica que la ’a’ se queda como cima de la pila, y la ’z’
detrás.
En algunos ejercicios usaremos la notación {b, A, c} con idéntico significado.
siendo:
Q: conjunto de estados
Σ: alfabeto de entrada
∗
δ: función de transición: δ : Q × (Σ ∪ {λ}) × T → 2Q×T
q0 : estado inicial ∈ Q
T : alfabeto de la pila
c. A = Contenido de la pila, A ∈ T ∗
Precedencia Definición IV.4 Precedencia entre descripciones instantáneas. Decimos que una
entre des- descripción instantánea precede a otra:
cripciones
instantá- (q, xX, aA) ` (p, X, bA)
neas
si:
(p, b) ∈ δ(q, x, a)
Siendo ’p’,’q’ nodos del autómata, ’x’ el siguiente símbolo de entrada que se va a leer,
’X’ el resto de la cadena de entrada; ’a’ el carácter que hay en la cima de la pila, ’A’ el
resto del contenido de la pila y,’b’ una cadena de símbolos que insertamos en la pila.
En este transición se lee ’x’, se saca ’a’ de la cima de la pila y se introduce ’b’.
Es decir, una descripción instantánea precede a otra si hay una transición que nos
lleva de una a otra.
Precedencia Definición IV.5 Precedencia *. Decimos que hay precedencia * entre dos
* descripciones instantáneas:
(q, X, A) `∗ (p, Y, B)
cuando hay una secuencia d0 , d1 , ..., dn de descripciones instantáneas tales que:
con p, q ∈ Q, X, Y ∈ Σ∗ y A, B ∈ T ∗ .
Basándonos en estas definiciones, podemos representar el lenguaje aceptado por
un autómata a pila como:
con p ∈ F, X ∈ T ∗
L = {an bn , n ≥ 0}
Capítulo V
Gramáticas de atributos
Por tanto, una vez obtenido el árbol de derivación, el análisis semántico recorrerá dicho
árbol utilizando el recorrido en profundidad por la izquierda y con vuelta atrás
(lo explicamos más adelante) corroborando el buen funcionamiento de estas nuevas
funciones.
El paso de información de un nodo a otro del árbol se podrá realizar mediante tres
métodos:
Vamos a ver un ejemplo con detalle, explicando sobre él algunos de los conceptos:
Como hemos dicho, la idea es que dada una gramática independiente del contexto,
podemos conseguir que esta realice funciones específicas. Lo conseguimos añadiendo
atributos y especificaciones a las reglas de derivación.
L → (I)
I → (I)
I → II
I→λ
En primer lugar vamos a derivar el axioma y obtener una sentencia, nos queda (por
ejemplo) el siguiente árbol de derivación:
I I
I I
( ( λ ) ( ( λ ) ) )
I → λ{I.prof = 0}
En las dos primeras reglas, debemos realizar una propagación hacia arriba,
aumentando en uno la profundidad. Así estas dos primeras reglas quedan de la forma:
L → (I){L.prof = I.prof + 1}
Para la tercera regla, podemos ver que la profundidad que asciende será el máximo
de las profundidades de cada uno de los símbolos en los que deriva. La tercera regla
quedaría:
I1 → I2 I3 {I1 .prof = max(I2 .prof, I3 .prof )}
Con P:
I → λ{0 : I.prof = 0}
Así, hemos conseguido una gramática de atributos que realiza una función específica
(obtener la profundidad). Lo hemos logrado a partir de una gramática independiente
del contexto añadiendo atributos y el instante en el que debo realizar cada asignación
en las reglas de derivación.
Además, una gramática de atributos contiene una información global. En este caso
no la vamos a usar por lo que la declaramos vacía (es el último símbolo que se ha
añadido a G).
También debemos saber que el árbol se recorre en profundidad por la izquierda y
con vuelta atrás. Esta técnica consiste en recorrer siempre el hijo más a la izquierda,
cuando no queden hijos a la izquierda, continuamos con el siguiente hijo más a la
izquierda. Cuando no queden hijos volvemos al nodo superior y así sucesivamente.
I1
p=2 en instante 2
I2 I3
p=1 en instante 2 p=2 en instante 2
I4 I5
p=0 en instante 0 p=1 en instante 2
I6
p=0 en instante 0
( ( λ ) ( ( λ ) ) )
Síntesis
G = {{(, )}, {L(n), I(n)}, L, P }
Herencia
G = {{(, )}, {L(n), I(antes, despues)}, L, P }
Hemos usado alguna acción que se sale de un esquema puro de herencia por ser
imposible realizarlo de otra forma.
Información global
• L → (I){0 : n = 0; 1 : n = n + 1}
• I1 → (I2 ){0 : n = n + 1}
• I1 → I2 I3
• I→λ
Este caso es bastante más sencillo, pues en cada derivación tienes acceso al
contador global y basta con incrementarlo, sin preocuparte por los sucesores.
Usando información global es realmente importante indicar los instantes en
que se realiza cada acción puesto que de lo contrario habría lugar a confusión.
(En los casos anteriores los atributos imponían un orden sin ambigüedad).
En las transparencias podéis ver estos tres ejemplos para diferenciar la herencia, la
síntesis y la información global (llamada tabla de símbolos):
AutLen () Gramáticas de atributos 7 de octubre de 2014 2 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 3 / 27
E E
E E
E E
E E
c c c
c c c
c.valor = 4 c.valor = 2 c.valor = 3
c.tipo = int c.tipo = int c.tipo = int
( 4 + 2 ) * 3
( 4 + 2 ) * 3
AutLen () Gramáticas de atributos 7 de octubre de 2014 4 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 5 / 27
E E
E E E E
E
E E.valor = 6
E.tipo = int
E E E E
E.valor = 4 E.valor = 2 E.valor = 4 E.valor = 2
E.tipo = int E.tipo = int E.tipo = int E.tipo = int
c c c c c c
c.valor = 4 c.valor = 2 c.valor = 3 c.valor = 4 c.valor = 2 c.valor = 3
c.tipo = int c.tipo = int c.tipo = int c.tipo = int c.tipo = int c.tipo = int
( 4 + 2 ) * 3 ( 4 + 2 ) * 3
AutLen () Gramáticas de atributos 7 de octubre de 2014 6 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 7 / 27
E
E E.valor = 18
E.tipo = int
E E E E
E.valor = 6 E.valor = 3 E.valor = 6 E.valor = 3
E.tipo = int E.tipo = int E.tipo = int E.tipo = int
E E
E.valor = 6 E.valor = 6
E.tipo = int E.tipo = int
E E E E
E.valor = 4 E.valor = 2 E.valor = 4 E.valor = 2
E.tipo = int E.tipo = int E.tipo = int E.tipo = int
c c c c c c
c.valor = 4 c.valor = 2 c.valor = 3 c.valor = 4 c.valor = 2 c.valor = 3
c.tipo = int c.tipo = int c.tipo = int c.tipo = int c.tipo = int c.tipo = int
( 4 + 2 ) * 3 ( 4 + 2 ) * 3
AutLen () Gramáticas de atributos 7 de octubre de 2014 8 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 9 / 27
Ejemplo 2 (herencia) Ejemplo 2 (herencia)
AutLen () Gramáticas de atributos 7 de octubre de 2014 10 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 11 / 27
T
L
T L T.tipo = int
L
L
L
L
i i i
i i i
i.nombre = x i.nombre = y i.nombre = z
i.nombre = x i.nombre = y i.nombre = z
int x , y , z
int x , y , z
AutLen () Gramáticas de atributos 7 de octubre de 2014 12 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 13 / 27
T L T L
T.tipo = int L.tipo = int T.tipo = int L.tipo = int
L L
L.tipo = int
L L
i i i i i i
i.nombre = x i.nombre = y i.nombre = z i.nombre = x i.nombre = y i.nombre = z
int x , y , z int x , y , z
AutLen () Gramáticas de atributos 7 de octubre de 2014 14 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 15 / 27
T L T L
T.tipo = int L.tipo = int T.tipo = int L.tipo = int
L L
L.tipo = int L.tipo = int
L L
L.tipo = int L.tipo = int
i i i i i i
i.nombre = x i.nombre = y i.nombre = z i.nombre = x i.nombre = y i.nombre = z
int x , y , z int x , y , z
AutLen () Gramáticas de atributos 7 de octubre de 2014 16 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 17 / 27
Ejemplo 3 (información global) Ejemplo 3 (información global)
Gramática de atributos:
Gramática independiente del contexto:
G = {{int, float, c(valor , tipo), i(nombre),00 ,00 , +, ∗, (, ), =},
G = {{int, float, c, i,00 ,00 , +, ∗, (, ), =}, {P, D, A, T , L, E }, P, R}
{P, D(tipo), A(valor , tipo), T (tipo), L(tipo), E (valor , tipo)}, P, R}
Conjunto de reglas de producción R:
Conjunto de reglas de producción R:
P ::= DA
P ::= DA
D ::= TL
D ::= TL{D.tipo = T .tipo; L.tipo = T .tipo}
T ::= int
T ::= int{T .tipo = int}
T ::= float
T ::= float{T .tipo = float}
L ::= L, i
L1 ::= L2 , i{L2 .tipo = L1.tipo; st(i.nombre, L1 .tipo)}
L ::= i
L ::= i{st(i.nombre, L.tipo)}
A ::= i = E
A ::= i = E {A.valor = E .valor ; A.tipo = E .tipo; sv (i.nombre, E .valor )}
E ::= E + E
E1 ::= E2 + E3 {E1 .valor = E2 .valor + E3 .valor ; E1 .tipo = E2 .tipo}
E ::= E ∗ E
E1 ::= E2 ∗ E3 {E1 .valor = E2 .valor ∗ E3 .valor ; E1 .tipo = E2 .tipo}
E ::= (E )
E1 ::= (E2 ){E1 .valor = E2 .valor ; E1 .tipo = E2 .tipo}
E ::= i
E ::= i{E .valor = gv (i.nombre); E .tipo = gt(i.nombre)}
E ::= c
E ::= c{E .valor = c.valor ; E .tipo = c.tipo}
AutLen () Gramáticas de atributos 7 de octubre de 2014 18 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 19 / 27
D A
D A
T L E
T
L E
T.tipo = int
L E E
L E E
c c
i i i
c.valor = 3 c.valor = 5
i.nombre = x i.nombre = y i.nombre = x c c
c.tipo = int c.tipo = int i i i
c.valor = 3 c.valor = 5
i.nombre = x i.nombre = y i.nombre = x
c.tipo = int c.tipo = int
int x , y x = 3 + 5
int x , y x = 3 + 5
TS
TS
AutLen () Gramáticas de atributos 7 de octubre de 2014 20 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 21 / 27
P P
D D
A A
D.tipo = int D.tipo = int
T L T L
E E
T.tipo = int L.tipo = int T.tipo = int L.tipo = int
L E E L
E E
L.tipo = int
c c c c
i i i i i i
c.valor = 3 c.valor = 5 c.valor = 3 c.valor = 5
i.nombre = x i.nombre = y i.nombre = x i.nombre = x i.nombre = y i.nombre = x
c.tipo = int c.tipo = int c.tipo = int c.tipo = int
int x , y x = 3 + 5 int x , y x = 3 + 5
TS TS
y(int, ?)
AutLen () Gramáticas de atributos 7 de octubre de 2014 22 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 23 / 27
P P
D D
A A
D.tipo = int D.tipo = int
T L T L
E E
T.tipo = int L.tipo = int T.tipo = int L.tipo = int
E E
L L
E E E.valor = 3 E.valor = 5
L.tipo = int L.tipo = int
E.tipo = int E.tipo = int
c c c c
i i i i i i
c.valor = 3 c.valor = 5 c.valor = 3 c.valor = 5
i.nombre = x i.nombre = y i.nombre = x i.nombre = x i.nombre = y i.nombre = x
c.tipo = int c.tipo = int c.tipo = int c.tipo = int
int x , y x = 3 + 5 int x , y x = 3 + 5
TS TS
y(int, ?) y(int, ?)
x(int, ?) x(int, ?)
AutLen () Gramáticas de atributos 7 de octubre de 2014 24 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 25 / 27
Ejemplo 3 (información global) Ejemplo 3 (información global)
E ::= E + E A ::= i = E
P P
A
D D
A A.valor = 8
D.tipo = int D.tipo = int
A.tipo = int
E E
T L T L
E.valor = 8 E.valor = 8
T.tipo = int L.tipo = int T.tipo = int L.tipo = int
E.tipo = int E.tipo = int
E E E E
L L
E.valor = 3 E.valor = 5 E.valor = 3 E.valor = 5
L.tipo = int L.tipo = int
E.tipo = int E.tipo = int E.tipo = int E.tipo = int
c c c c
i i i i i i
c.valor = 3 c.valor = 5 c.valor = 3 c.valor = 5
i.nombre = x i.nombre = y i.nombre = x i.nombre = x i.nombre = y i.nombre = x
c.tipo = int c.tipo = int c.tipo = int c.tipo = int
int x , y x = 3 + 5 int x , y x = 3 + 5
TS TS
y(int, ?) y(int, ?)
x(int, ?) x(int, 8)
AutLen () Gramáticas de atributos 7 de octubre de 2014 26 / 27 AutLen () Gramáticas de atributos 7 de octubre de 2014 27 / 27
Autómatas y lenguajes - 2014/2015 - UAM Pedro Valero y Alberto Parramón
Ejemplo: Para ver claramente las diferencia entre análisis semántico y sintáctico
nos podemos fijar en lo siguiente, según el ejemplo 1, el código:
int _x,_y
_x=7
int _x,_y
_z=7
Ejemplo: Vamos a tomar un caso sencillo con dos reglas sacadas del último ejemplo
mostrado en las transparencias. La semántica es:
L → i{st(i.nombre, L.tipo}
Capítulo VI
Analizador morfológico
Análisis morfológico
Análisis sintáctico
Análisis semántico
Tras ser analizado, se genera un árbol de derivación como los vistos hasta ahora.
Nos centramos ahora en el analizador morfológico (también llamado léxico o
scanner). Este realiza principalmente la siguiente función:
Obtención de unidades sintácticas. Son los llamados tokens. Estos pueden ser
identificadores, constantes, palabras reservadas (if , them, f or,...) u otros símbolos
(simples: +, =,... o dobles: :=,...).
begin
int A;
A := 100;
print A;
end
<"begin",TOK_BEGIN>
<"int",TOK_INT>
<"A",TOK_ID, valor=’A’>
.
.
.
<"100",TOK_CONST, valor=100>
.
.
.
Capítulo VII
Analizador sintáctico
VII.1. Introducción
Para llevar a cabo el análisis sintáctico de una entrada se emplean tablas de análisis.
Estas permiten analizar una sentencia, con el fin de saber si se trata de una sentencia
válida para una gramática dada o no.
Existen dos tipos de análisis: ascendente y descendente
Veamos un ejemplo:
1) E → E + E
2) E → E x E
3) E → -E
4) E → (E)
5) E → id
(id+id)xid
Para ello vamos a contar con la ayuda de una pila y nos basaremos en dos reglas
básicas:
Puesto que en la pila sólo queda el axioma, concluimos que la sentencia es válida para
este lenguaje.
Tras este ejemplo podemos definir formalmente el algoritmo de análisis ascendente.
Análisis Definición VII.1 Análisis ascendente. Este algoritmo consiste de dos pasos:
ascenden-
te
Mientras queden elementos en la entrada:
desplazamos
mientras podemos reducir:
reducimos
Análisis Definición VII.2 Análisis descendente. Algoritmo para determinar si una entrada es
descen- válida o no para una gramática dada mediante derivaciones (partiendo del axioma)
dente
Es decir, tomamos el axioma y aplicamos derivaciones sucesivas intentando llegar
a la sentencia que queremos analizar.
Si logramos generar la sentencia que estamos analizando, esta será válida. (En caso
contrario no)
Vamos a trabajar con gramáticas sencillas en las que sólo haya una derivación
posible en cada paso. En caso de no ser así deberíamos avanzar todo lo posible para
después hacer backtracking, comprobando que no dejamos caminos sin explorar.
Veámoslo con un ejemplo:
E → TB
B → +TB | λ
T → FX
X → *FX | λ
F → i | (E)
i*i
Para hacerlo apoyándonos en una pila, como en el ejemplo anterior, los pasos a seguir
son los siguientes:
Instante Pila Acción
1 E Derivamos
2 B|T Derivamos
3 B|X|F Derivamos
4 B|X|i Extraemos, pues i está en la sentencia dada
5 B|X Derivamos
6 B | X | F | * Extraemos, pues * está en la sentencia dada
7 B|X|F Derivamos
8 B|X|i Extraemos, pues i está en la sentencia dada
9 B|X Derivación λ
10 B Derivación λ
Si al finalizar nos queda la pila vacía concluimos que la sentencia estudiada es
correcta.
A lo largo de esta sección profundizaremos sobre el análisis ascendente y el análisis
descendente.
Tabla Definición VII.3 Tabla LR(n). Tabla empleada para el procesamiento de entrada
LR(n) desde la izquierda (Left) mediante derivaciones Right-most con n símbolos de entrada.
Veamos un ejemplo de como funciona esta tabla de análisis
E → T | E+T
T → i | (E)
E’ → E$
E’ → E $
E→T
E → E+T
T→i
T → (E)
Ahora lo que hacemos es añadir un ’.’ delante del símbolo que estemos analizando
en cada paso.
Para realizar el análisis por este método vamos a construir un autómata finito
determinista, que procesa una cadena de símbolos, empezando por el estado S0:
Situamos un ’.’ delante del símbolo que analizamos, en este caso empezamos
por el símbolo E. Ya que la regla de derivación del axioma es E 0 → E$. Por
tanto nos queda E 0 → .E$
Ahora tenemos que cerrar el símbolo que esta inmediatamente después del
punto. Si es un terminal ya estaría cerrado. Si es un no terminal lo cerramos
escribiendo las reglas de derivación del mismo, poniendo de nuevo un ’.’
delante del primer símbolo de cada una de las reglas y cerrando el símbolo
inmediatamente posterior al ’.’. Así terminamos el estado S0
después del ’.’, entonces se irá a un nuevo estado del autómata en el que ahora el
’.’ se encontrará en la siguiente posición dentro de la regla de derivación. Si llega
un símbolo que no está inmediatamente después del ’.’, se saltará a un estado
de error.
A partir de este autómata se puede crear una tabla, denominada tabla de análisis
LR(0) que resume el funcionamiento del autómata:
En la cual vemos que se indica la acción a realizar según el estado en el que nos
encontremos y el símbolo de entrada que leamos.
Así, para realizar el análisis de una entrada nos basta con utilizar esta tabla y una
pila en la que vayamos guardando las acciones que vamos realizando.
A la hora de analizar una entrada realizamos los siguientes 5 tipos de acciones:
Ejemplo: Veamos un ejemplo del análisis de una expresión que termina en error:
Veamos un ejemplo
E → T E0
E 0 → +T E 0
E0 → λ
T → FT0
T 0 → ∗F T 0
T0 → λ
F → (E)
F →i
P∗ Para calcularlo formalmente, dada una regla : X 7−→ αA{β1 , β2 , ...}, con α, βi ∈
(0) B’ → B $
(1) B → bD;Ef
(2) D → d
(3) D → D;d
(4) E → e
(5) E → e;E
En el cual podemos observar que en el estado final S7 tenemos dos posibles acciones
si entra un ’;’, la de reducir (por ser estado final y encontrarse el ’.’ a la derecha de la
regla) o la de desplazar al estado S10
Por tanto nos quedaría la siguiente tabla de análisis LR(0):
Concluimos que no es por tanto un autómata LR(0) ya que tenemos conflictos que
debemos solucionar. Para ello usaremos SLR(1).
Tabla Definición VII.6 Tabla SLR(1). Tabla que mejora la tabla de análisis LR(0)
SLR(1) modificando las transiciones de los estados finales del autómata.
En el caso de LR(0) realizaban una reducción siempre, mientras que en SLR(1) se
específica cuándo hay que realizar una reducción, cuándo un desplazamiento, y cuándo
vamos a un estado de error.
Por tanto el autómata quedará igual a simple vista (sólo que ahora habrá más
transiciones a estados de error aunque estas no aparezcan dibujadas). Los cambios los
mostraremos en la tabla de análisis.
La idea principal del análisis SLR(1) es que sólo aplicaremos las reducciones de
reglas de la forma X → algo, delante del Siguiente(X).
Vamos a calcular los elementos siguientes de los no terminales B, D y E.
Como podemos observar, en el estado S7, se reduce siguiendo la regla (4) (ver
las reglas de la gramática definidas al principio del ejemplo), pero sólo si el siguiente
elemento de la entrada es una f, ya que siguiente(E)=f.
3. Modificar las filas de la tabla que correspondan a estados finales. Poniendo huecos
en blanco en todas las casillas salvo en aquellas en las que haya desplazamiento
y aquellas en las que realmente reduzcamos, es decir, en las que el siguiente
elemento del que vayamos a reducir coincida con el de la entrada.
(0) E’ → E $
(1) E → E+E
(2) E → E*E
(3) E → i
(0) S’ → S $
(1) S → xb
(2) S → A
(3) A → aAb
(4) A → x
En el cual vuelve a ocurrir algo parecido a lo del ejemplo anterior. En este caso
tenemos que:
siguiente(S)={$}
siguiente(A)={b, $}
1. Ahora la gramática extendida no va a tener una regla que sea S 0 → S$ sino que
esta regla será S 0 → S{$}.
2. Vamos a formar cada estado como en LR(0), poniendo un ’.’ delante del
símbolo que estamos evaluando y cerrando ese símbolo como ya explicamos
anteriormente.
3. A cada regla que aparezca en cada estado del autómata se deberá añadir entre
corchetes lo que llamaremos el símbolo de adelanto.
Este símbolo es el siguiente(X) si tenemos X → ABC..., es decir, el siguiente
del símbolo no terminal situado a la izquierda de la regla.
Esto es algo más complicado de lo que parece.
El procedimiento a aplicar, consiste en partir únicamente de la regla que está
generando el autómata (En el estado inicial esta regla será la derivación del
axioma y en otros estados la regla que acabamos de derivar).
Para esta regla ya conocemos el símbolo de adelanto: si es un estado intermedio
conserva el símbolo de adelanto del estado anterior y si es el estado inicial su
símbolo de adelanto es $.
Una vez tenemos la regla inicial, calculamos su cierre en pequeños pasos.
Es decir, primero añadimos las reglas que se derivan del no terminal situado
inmediatamente después del punto (hasta aquí un paso), luego aplicamos
calculamos el cierre de cada una de estas nuevas reglas (por cada regla un
paso).
¿Por qué realizamos esta distinción entre pasos que antes no hacíamos? Por que
ahora será necesario realizar un pequeño trabajo entre estos pasos.
En cada paso tomamos únicamente la regla que estamos cerrando y las reglas que
acabamos de añadir y, restringiéndonos a ese subconjunto de reglas, calculamos
los símbolos de adelanto de las mismas.
S → aSb
S → ab
Para empezar derivamos el axioma con la primera regla (en realidad daría igual
cual coger).
Obtenemos por tanto S->aSb y vemos que es compatible con la cadena buscada.
Nos hemos quedado sin reglas por aplicar, de modo que debemos deshacer una
acción más. Volvemos al estado S->aSb y tratamos de aplicar la segunda regla:
Llegamos a S->aSb->aabb y vemos que coincide con la cadena buscada.
Compatibilidad Definición VII.7 Compatibilidad. Para comprobar si la cadena que tenemos ahora
mismo es compatible con la cadena que estamos buscando simplemente vemos si los
primeros símbolos terminales (hasta el primer no terminal) coinciden.
Tal y como lo hemos explicado ,el algoritmo de análisis descendente presenta dos
problemas graves:
1. Es extremadamente ineficiente
2. Recursividad por la izquierda.
Si nos encontramos con una gramática del tipo
S→b
S → Sb
y buscamos la cadena abb entraríamos en un problema de recursión infinita pues
aplicar la primera regla no nos da la solución final en ningún caso y con la segunda
regla tendremos siempre al inicio de la cadena un símbolo que no es terminal.
Para clasificar las gramáticas según puedan causarnos o no este problema vamos a
definir un nuevo concepto
Gramática Definición VII.8 Gramática LL(1). Gramática en la que todas las reglas presentan
LL(1) en la parte derecha 1 símbolo no terminal seguido de un símbolo cualquiera (terminal
o no terminal).
Además, dos reglas con la misma parte izquierda deben un terminal distinto al
inicio de su parte derecha.
Estas gramática son muy interesantes ya que presentan un claro determinismo, que
nos evita de hacer backtracking con lo que hacen la búsqueda muy eficiente.
Veremos dos métodos para el análisis de gramáticas de este tipo pero antes debemos
definir un nuevo concepto muy importante de cara al análisis descendente: Forma
normal de Greigbach
Forma Definición VII.9 Forma normal de Greigbach. Decimos que una gramática está en
normal de forma normal de Greigbach si todas las reglas son de la forma:
Greigbach
A → aβ donde a ∈ T, β ∈ N ∗
A → Aβ
A→α
la convertimos en otra
A → αX
X → βX|λ
a) A → aZ
b) Ai → Aj α con Ai precediendo a Aj
c) Ai → Aj α con Aj precediendo a Ai
4. Eliminar reglas λ
5. Eliminar indeterminismo
Dadas reglas de la forma
a) A → aZ
b) A → aB
a) A → aW
b) W → B
c) W → Z
Tras este paso vemos si aparecen reglas recursivas. En caso afirmativo, las
eliminamos antes de seguir.
E →E+T
E→T
T →T ∗T
T →F
F →i
Primero eliminamos las reglas recursivas por la izquierda y nos quedamos en:
E → T X (tipo 2)
X → +T X|λ (tipo 1)
T → F Y (tipo 2)
Y → ∗T Y |λ (tipo 1)
F → i (tipo 1)
donde hemos indicado el tipo de cada regla, preparándonos así para el paso siguiente.
Ahora tenemos que eliminar los símbolos no terminales del principio de la parte
derecha de las reglas. Para ello aplicamos las siguientes transformaciones
T → FY =⇒ T → iY
E → T X =⇒ E → F Y X =⇒ F → iY X
E → iY X
X → +T X
X→λ
T → iY
Y → ∗T Y
Y →λ
F →i
Pero a esta gramática aún le falta algo para ser de Greibach, tenemos que eliminar
las transiciones vacías, obteniendo:
E → iY X
E → iY
E → iX
E→i
X → +T X
X → +T
T → iY
T →i
Y → ∗T Y
Y → ∗T
F →i
a) pila=entrada=$ FIN
b) pila contiene x∈ T
1) x = entrada =⇒ desplazamos entrada y pop
2) x 6= entrada =⇒ ERROR
c) pila contiene x ∈ N =⇒ saco x de la pila y meto β.
S → E$
E → T E0
E 0 → +T E 0
E0 → λ
T → FT0
T 0 → ∗F T 0
T0 → λ
F →i
F → (E)
i + i ∗ i$
La tabla queda:
Símbolo + * i ( ) $
E E →TE’ E → T E0
E’ E 0 → +T E 0 E0 → λ E0 → λ
T T → FT0 T → FT0
T’ T0 → λ T 0 → ∗F T 0 T0 → λ T0 → λ
F F →i F → (E)
y el análisis resulta:
P → iEtP P 0 $
P →a
P 0 → eP
P0 → λ
E→b
Símbolo a t e b i $
P P →a P → iEtP P 0
P’ P 0 → EP P0 → λ
P0 → λ
E E→b
Ejemplo: La gramática
S → aSb
S → ab
B→b
S → aW
W → aW b
W →b
S → aSb
S → ab
Símbolo aa ab
S S → ab S → aSb
Pero aún quedan casos en los que no podemos resolver los conflictos ni usando
LL(2).
Por ejemplo, en la gramática
ARGS -> λ
ARG -> ID
En este caso no hay problemas pues es bastante sencilla la tabla mostrada. No obstante,
en un caso más general sería necesario cuidar que no se solapen las expresiones regulares
empleadas en el análisis.
Capítulo VIII
B F
G C
A-B -> X B-E -> X E-F -> X F-G -> X G-H -> X
A-E -> V B-F -> X E-G -> V F-H -> X
A-F -> X B-G -> X E-H -> H
A-G -> V B-H -> V
A-H -> X
Ejemplo:
y nos queda:
Como |xy| ≤ m podemos escoger un xy que sean todo a’s, de manera que xy i z
tendría mas a’s que b’s y por tanto no pertenecería a L.
Hemos encontrado una palabra w que no cumple las condiciones que debería
cumplir toda palabra si el lenguaje fuese regular. Concluimos que el lenguaje no
es regular.
El truco esta en coger una palabra que no cumpla la implicación, con la cual si
tenemos un A ⇒ B y B no se cumple, se deduce que A tampoco. ¬B ⇒ ¬A
Veamos otro ejemplo:
Como |xy| ≤ m podemos escoger un xy que sean todo a’s de la parte izquierda,
de manera que xy i z no sería simétrica.
Hemos encontrado una palabra w que no cumple las condiciones que debería
cumplir toda palabra si el lenguaje fuese regular. Concluimos que el lenguaje no
es regular.
3. Tenemos: abab
| {z . . . ab} ab |aa {z
. . . a}
2m m
2m
z }| {
m m
z }| { z }| {
abab
| {z . . . ab} . . . ab ab aa . . . a
xy
Como |xyz| ≤ m tenemos que en xyz o bien no hay a’s o bien no hay c’s, y por
tanto ux0 yz 0 v ∈
/ L.
Hemos encontrado una palabra w que no cumple las condiciones que debería
cumplir toda palabra si el lenguaje fuese independiente del contexto. Concluimos
que el lenguaje no es independiente del contexto.
2. Elegimos una palabra w ∈ L con |w| ≥ m. Cogemos w = am−1 bam−1 b que tiene
|w| = 2m ≥ m
Vemos que si escogemos xyz = a, a, ..., b, a, a, ..., a, con esta división la palabra
ux0 yz 0 v ∈ L, y por tanto no nos vale como contraejemplo.
Se deja como ejercicio para e lector comprobar que la elección correcta es coger
un w = am bm am bm . Con esta palabra conseguiremos demostrar que el lenguaje
no es independiente del contexto.
n n m
Ejemplo: Tomemos el lenguaje L1 = a b c |n, m ≥ 1 generado por la
gramática:
• S → AB
• A → aAb| ab
• B → cB| c
• S → AB
• A → aA| a
• B → bBc| bc
L1 ∩ LR es I.C.
L1 ∪ L2 = L1 ∩ L2 = L1 ∩ L2
Pero sin embargo acabamos de ver que L1 ∩ L2 no tiene por qué ser I.C.
L1 − L2 no es necesariamente I.C.
Apéndice A
Ejercicios
A.1. Ejercicios
S → abB
A → aaBb
B → bbAa
A→λ
S → BaB
B → Bb
B→λ
El autómata sería:
S → XaX
X → XZ|λ
Z → a|b
El autómata sería:
El autómata sería:
1. L = {a2n bn+1 }
2. L = {an bm n > m ≥ 0}
3. L = {an bm ck k = n + m}
1. Gramática
S → aaSb|b
Autómata
2. Gramática
S → aSb|aS|a
Autómata
3. Gramática
S → aSc|aAc|λ
A → bAc|λ
Autómata
Apéndice B
Ejercicios 1a Hoja
Apartado a)
(aa) ∗ .(a + b).(bb)∗
Apartado b)
(1 + 0) ∗ .1010.(1 + 0)∗
Apartado c)
@.(a + b + ... + z).(0 + 1 + ... + 9 + a + b + ... + z)∗
Apartado b)
Las transiciones no indicadas sobreentendemos que van a un nodo residuo.
Aunque nos pida el lenguaje nos vale con poner la expresión regular.
Ejercicio 1.5: Para el autómata siguiente encuentra δ ∗ (q0 , 1011) y δ ∗ (q1 , 01)
Explicación: Nos piden la salida del autómata dada un estado inicial y una palabra.
δ ∗ (q0 , 1011) = q2
Estados 1 0 1 1
q0 q1 q0 q1 q2
q2 - -
q2 - - - -
δ ∗ (q1 , 01) = q1
Estados 0 1
q1 q0 q1
q2 -
En cada regla, si aparecen dos ’X’ estas tienen que acabar en el mismo símbolo
terminal. La otra opción era poner muchas reglas más tipo X0 , ..., X9 .
S −→ XZX
Z −→ XZX|X|λ
X −→ 0|1|2|3|4|5|6|7|8|9
Ejercicio 2.2: Diseña una gramática independiente del contexto que genere
el lenguaje de los números formados con el alfabeto Σ = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 que
tengan el mismo número de dígitos pares e impares. Puede suponer por simplicidad
que los números pueden tener ceros a la izquierda.
Explicación: Cuando pongo ’x’ o ’y’ quiero decir un símbolo del conjunto
{0,1,2,3,4,5,6,7,8,9}. Cuando pongo ’x’ e ’y’ en la misma transición, x 6= y.
Apéndice C
Ejercicios 2a Hoja
genera frases que consisten en una secuencia de películas con sus respectivas
valoraciones realizadas por los usuarios.Al principio de las frases generadas por la
gramática siempre aparece el nombre de un usuario. A continuación se muestran tres
ejemplos:
jaime Star_Wars(jaime:10)(ana:10) Spiderman(ana:10)(pepe:1)
ana Kapax(pepe:100)(jaime:1) Avatar(ana:40) Pi(pepe:100)(ana:1)
mike Kapax(pepe:100)(jaime:1) Avatar(ana:40) Pi(pepe:100)(ana:1)
Se desa añadir a esta gramática un sistema de atributos que haga lo siguiente:
Por ejemplo, para las tres cadenas anteriores se mostrarían respectivamente los
mensajes siguientes:
Se han valorado 2 películas. La mejor valorada por jaime es Star_Wars, con una
valoración de 10.
Se han valorado 3 películas. La mejor valorada por ana es Avatar, con una valoración
de 40.
INSTATE ACCIÓN
axioma ::= USUARIO peliculas
1 peliculas.usuario_actual = USUARIO.nombre
2 print("Se han valorado " + peliculas.num + " películas")
print("la mejor valorada por " + USUARIO.nombre + " es " + peliculas.titulo
+ " con una valoración de " + peliculas.nota + ".")
peliculas_1 ::= peliculas_2 pelicula
0 peliculas_2.usuario_actual = peliculas_1.usuario_actual
pelicula.usuario_actual = peliculas_1.usuario_actual
2 if(peliculas_2.nota>pelicula.nota){
peliculas_1.nota=peliculas_2.nota
peliculas_1.titulo=peliculas_2.titulo}
else{peliculas_1.nota=pelicula.nota
peliculas_1.titulo=pelicula.titulo}
peliculas_1.num = peliculas_2.num+1
peliculas ::= pelicula
0 pelicula.usuario_actual = peliculas.usuario_actual
1 peliculas.titulo = pelicula.titulo
peliculas.nota = pelicula.nota
peliculas.num=1
pelicula ::= TITULO valoraciones
0 valoraciones.usuario_actual = pelicula.usuario_actual
1 pelicula.titulo = TITULO.titulo
2 pelicula.nota=valoraciones.notamax
valoraciones_1 ::= valoraciones_2 valoracion
0 valoraciones_2.usuario_actual = valoraciones_1.usuario_actual
2 if(valoraciones_1.usuario_actual==valoracion.usuario AND valoraciones_2.notamax
6= 0){
print("ERROR")
}else if(valoraciones_1.usuario_actual==valoracion.usuario)}
valoraciones_1.notamax=valoracion.nota
}else if(valoraciones_2.notamax 6=0){
valoracion_1.notamax=valoraciones_2.notamax
}else{valoraciones_1.notamax=0}
valoraciones ::= valoracion
0 valoraciones.notamax=0
1 if(valoraciones.usuario_actual==valoracion.usuario){
valoraciones.notamax=valoracion.nota}
valoracion ::= (USUARIO:NUMERO)
2 valoracion.nota = NUMERO.valor
valoracion.usuario=USUARIO.nombre
Esta gramática genera sentencias entre las que se encuentran los números romanos
hasta el 8.
Se pide añadir a la gramática un sistema de atributos que compruebe si la
sentencia corresponde a un número romano correcto y, en caso afirmativo, imprima
su valor numérico.
No está permitido el uso de información global
romano ::= I V
{romano.esValido = true}
IList ::= λ
{IList.esValido = true}
{IList.items = 0}
Esta gramática genera sentencias formadas por dos cadenas separadas por el signo
’=’. La primera cadena es igual que las generadas por la gramática del ejercicio 5.
La segunda cadena es una lista de símbolos I.
Se pide añadir a la gramática un sistema de atributos que compruebe si, en el
caso de que la primera cadena sea un número romano correcto, el valor del mismo
coincide con el número de símbolos I en la segunda cadena.
No está permitido el uso de información global
romano ::= I V
{Síntesis; romano.esValido = true}
{Síntesis; romano.value = 4}
IList ::= λ
{IList.esValido = true}
{IList.items = 0}
Apéndice D
Ejercicios 3a Hoja
S ::= A
S ::= B
A ::= cA+b
A ::= a
B ::= cB+a
B :== b
Primeros:
Primero(A) ={c, a}
Primero(B) ={c, b}
Primero(S) ={a, c, b}
Sigueintes
siguiente(A) ={$, +}
siguiente(B) ={$, +}
siguiente(S) ={$}
E ::= T
E ::= E + T
T ::= i
T ::= (E)
E’ ::= .ES
E ::= .T
E ::= .E + T
T ::= .i
T ::=.(E)
E ::= (L)
E ::= i
L ::= L,E
L ::= E
a)
E ::= (.L)
L ::= .L,E
L ::= .E
E ::= .(L)
E ::= .i
b)
E ::= (L.)
D ::= iPSn
P ::= :n
S ::= λ
S ::= n
Para trabajar con esta gramática primero añadimos la regla: D’ ::= D$, con lo que
nos queda el conjunto de reglas:
(3) S ::= .λ
(4) S ::= .n
a)
Estado i n : $ D P S
S0 d1 2
S1 d3 F3
S2 dacc F5
SF3 r3 r3/df4 r3 r3 4
b)
S3 dF2
SF4 r4 r4 r4 r4
S4 dF5
SF2 r2 r2 r2 r2
SF5 r1 r1 r1 r1
c) No se trata de una gramática LR(0) ya que hay ocasiones en las que
observamos un conflico desplazamiento-reducción. Por ejemplo, en el estado inicial
podemos reducir la S o desplazar según la entrada dada.
Para ver si se trata de una gramática SLR(1) vamos a ver si somos capaces de
solucionar los conflictos sabiendo cuales son los elementos siguientes:
Estado i n : $ D P S
S0 d1 2
S1 d3 F3
S2 dacc F5
SF3 r3/df4 4
S3 dF2
SF4 r4
S4 dF5
SF2 r2
SF5 r1
S ::= bLd
L ::= E;L
L ::= λ
E ::= i=c
E ::= b
(0) S’ ::= S $
(3) L ::= λ
(5) E ::= b
Estado i = c ; b d $ L E S
S0 dF0 1
S1 dacc
SF0 r3/d7 r3 r3 r3 r3/dF3 r3 r3 3 4
S3 dF1
SF1 r1 r1 r1 r1 r1 r1 r1
b) S4 dF4
SF4 r3 r3 r3 r3 r3 r3 r3 F5 4
SF5 r2 r2 r2 r2 r2 r2 r2
SF3 r5 r5 r5 r5 r5 r5 r5
S7 d8
S8 dF2
SF2 r4 r4 r4 r4 r4 r4 r4
c) No se trata de una gramática LR(0) ya que hay ocasiones en las que
observamos un conflicto desplazamiento-reducción.
Para ver si se trata de una gramática SLR(1) vamos a ver si somos capaces de
solucionar los conflictos sabiendo cuales son los elementos siguientes:
Se corrigen los dos conflictos que hay ya que en el estado SF0 solo reduciremos
si llega una ’d’, por tanto en el caso de que llegue una ’b’ o una ’i’ desplazaremos.
Quedando la tabla así:
Estado i = c ; b d $ L E S
S0 dF0 1
S1 dacc
SF0 d7 dF3 r3 3 4
S3 dF1
SF1 r1
S4 dF4
SF4 r3 F5 4
SF5 r2
SF3 r5
S7 d8
S8 dF2
SF2 r4
Ejercicio 1.6: Calcula los conjuntos primero y siguiente de todos los símbolos
no terminales de las gramáticas siguientes
a)
X ::= Ye
X ::= eYZf
Y ::= g
Y ::= Yg
Z ::= h
b)
Q ::= fXY
X ::= cQ
X ::= λ
Y ::= iQ
Y ::= λ
c)
A ::= BXB
X ::= ,
X ::= .
X ::= e
B ::= 0B
B ::= 1B
B ::= λ
Apartado a)
primero(X)={e,g}
primero(Y)={g}
primero(Z)={h}
siguiente(X)={$}
siguiente(Y)={$,e,h}
siguiente(Z)={$,f}
Apartado b)
primero(Q)={f}
primero(X)={c,λ}
primero(Y)={i,λ}
siguiente(Y)=siguiente(Q) = {$, i}
Apartado c)
primero(X)={",",.,e}
primero(A)={0,1,",",.,e}
primero(B)={0,1,",",.,e}
siguiente(X)={$,0,1}
siguiente(A)={$,}
siguiente(B)={$,",",.,e}
Ejercicio 1.7: Cacula los símbolos de adelanto para el cierre de las siguientes
reglas y gramáticas:
a) Cierre de E’ ::= .E {$} para la siguiente gramática
E’ ::= E
E ::= T
E ::= E+T
T ::= i
T ::= (E)
S’ ::= S
S ::= L=R
S ::= R
L ::= *R
L ::= i
R ::= L
E ::= (L)
E ::= a
L ::= L,E
L ::= E
E’ ::= .E {$}
E ::= .T {$}
T ::= .i {+, $}
b)
S’ ::= .S {$}
S ::= .R {$}
L ::= .i {=, $}
R ::= .L {$}
c)
L ::= .E {”, ”, )}
E ::= .a {”, ”, )}
S ::= aSb
S ::= ab
a)
Estado S a b $
S0 S2 S1
S1 S3 S4 SF4
S2 ACC
S3 SF2
b) S4 S5 S4 SF1
S5 SF3
SF1 r3
SF2 r2
SF3 r2
SF4 r3
c) La secuencia de acciones sería la siguiente:
d) Cuando pasemos de LR(1) a LALR(1) vamos a agrupar los nodos SF4 y SF1
en uno solo así como SF2 y SF3, manteniendo las mismas reglas en cada caso y
estableciendo como símbolos de adelanto la unión de los símbolos de adelanto de las
reglas de los estados a unir.
S ::= XX
X ::= aX
X ::= b
(0) S’ ::= S
(1) S ::= XX
(2) X ::= aX
(3) X ::= b
Estado a b X S
S0 d1 dF0 acc 2
SF0 r3 r3
S1 d1 dF3 F4
SF3 r3 r3
b) SF4 r2 r2
S2 d3 dF2 F1
SF1 r1 r1
S3 d3 dF2 F5
SF5 r2 r2
SF2 r3 r3
D ::= iPSn
P ::= :n
S ::= λ
S ::= n
(0) S’ ::= S
(1) S ::= XX
(2) X ::= aX
(3) X ::= b
Estado i n : $ D P S
S0 d1 2
S1 d3 F3
S2 dacc F5
SF3 r3 r3/df4 r3 r3 4
b)
S3 dF2
SF4 r4 r4 r4 r4
S4 dF5
SF2 r2 r2 r2 r2
SF5 r1 r1 r1 r1