Análisis Sintáctico. Procesadores de Lenguaje I - GIAA
Análisis Sintáctico. Procesadores de Lenguaje I - GIAA
Análisis Sintáctico. Procesadores de Lenguaje I - GIAA
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Análisis</strong> <strong>Sintáctico</strong><br />
Ca<strong>de</strong>na <strong>de</strong><br />
tokens<br />
Analizador<br />
<strong>Sintáctico</strong><br />
Árbol<br />
<strong>Sintáctico</strong><br />
En realidad...<br />
Analizador<br />
Léxico<br />
Componente léxico<br />
Obtén otro<br />
componente léxico<br />
Analizador<br />
<strong>Sintáctico</strong><br />
Árbol<br />
sintáctico<br />
Tabla <strong>de</strong><br />
Símbolos
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong><br />
Funciones<br />
• Comprobar que la secuencia <strong>de</strong> componentes<br />
léxicos cumple las reglas <strong>de</strong> la gramática<br />
• Generar el árbol sintáctico<br />
Ventajas <strong>de</strong> utilizar gramáticas<br />
• Son especificaciones sintácticas y precisas <strong>de</strong><br />
lenguajes<br />
• Se pue<strong>de</strong> generar automáticamente un analizador<br />
• El proceso <strong>de</strong> construcción pue<strong>de</strong> llevar a<br />
<strong>de</strong>scubrir ambigüeda<strong>de</strong>s<br />
• Imparte estructura al lenguaje <strong>de</strong> programación,<br />
siendo más fácil generar código y <strong>de</strong>tectar errores<br />
• Es más fácil ampliar y modificar el lenguaje<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Analizador <strong>Sintáctico</strong>, Tipos<br />
Tres tipos generales <strong>de</strong> analizadores sintácticos:<br />
• Métodos Universales: Cocke-Younger-Kasami y Earley<br />
• Sirven para cualquier gramática<br />
• Muy ineficientes<br />
• Descen<strong>de</strong>ntes (top-down)<br />
• Construyen el árbol <strong>de</strong> análisis sintáctico <strong>de</strong>s<strong>de</strong> arriba (raíz,<br />
axioma) hasta abajo (hojas, terminales)<br />
• Analizadores Descen<strong>de</strong>ntes Recursivos<br />
• Analizadores LL(1) con tabla<br />
• Ascen<strong>de</strong>ntes (bottom-up)<br />
• Construyen el árbol <strong>de</strong> análisis sintáctico <strong>de</strong>s<strong>de</strong> abajo hacia<br />
arriba<br />
• Analizadores <strong>de</strong> Prece<strong>de</strong>ncia <strong>de</strong> Operador<br />
• Analizadores LR(1)
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Analizador <strong>Sintáctico</strong><br />
Tanto para el análisis <strong>de</strong>scen<strong>de</strong>nte como para el<br />
ascen<strong>de</strong>nte:<br />
• La entrada se examina <strong>de</strong> izquierda a <strong>de</strong>recha, un símbolo<br />
cada vez<br />
• Trabajan con subclases <strong>de</strong> gramáticas<br />
En general las gramáticas serán LL y LR<br />
• LR(k) ⊃ LL(k)<br />
• En la práctica solo se utilizan LR(1) y LL(1)<br />
Muchos compiladores se llaman “parser-driven”<br />
<strong>de</strong>bido a que el analizador sintáctico es el que llama<br />
al léxico<br />
Existen herramientas para generar automáticamente<br />
analizadores sintácticos (YACC, Bison)<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Analizador <strong>Sintáctico</strong><br />
Árbol sintáctico<br />
• Ejemplo: Id.*.Id.+.Id<br />
Expresión<br />
Gramática:<br />
Expresión::=<br />
Expresión.*.Término<br />
| Expresión.+.Término<br />
| Término<br />
Término ::= Id<br />
| Número<br />
Expresión<br />
+<br />
Término<br />
Expresión<br />
*<br />
Término<br />
Id<br />
Término<br />
Id<br />
Id
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Descen<strong>de</strong>nte<br />
Algoritmo<br />
1. Poner el axioma como raíz <strong>de</strong>l árbol <strong>de</strong> <strong>de</strong>rivación<br />
2. Hasta que solo haya símbolos terminales, <strong>de</strong>rivar más a la<br />
izquierda<br />
Ejemplo<br />
• Entrada: Id.*.Id.+.Id<br />
• Gramática:<br />
Expresión::=Expresión.*.Término | Expresión.+.Término |<br />
Término<br />
Término ::= Id | Número<br />
• Derivación:<br />
Expresión → Expresión.+.Término →<br />
Expresión.*.Término.+.Término →<br />
Término.*.Término.+.Término →<br />
Id.*.Término.+.Término →<br />
Id.*.Id.+.Término → Id.*.Id.+.Id<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Ascen<strong>de</strong>nte<br />
Definición: Pivote<br />
• Secuencia más larga <strong>de</strong> símbolos (Σ T y Σ N ) en la parte más<br />
izquierda <strong>de</strong> la entrada que se pue<strong>de</strong> encontrar en la parte<br />
<strong>de</strong>recha <strong>de</strong> una producción y tal que todos los símbolos a su<br />
<strong>de</strong>recha son terminales<br />
• Ejemplo:<br />
• Si entrada es: Expresión.*.Término.+.Id<br />
• el pivote es: Expresión.*.Término<br />
Algoritmo<br />
1. Empezar con la ca<strong>de</strong>na <strong>de</strong> entrada<br />
2. Intentar llegar hasta el axioma, encontrando el pivote y<br />
reduciéndolo con la producción correspondiente<br />
Ejemplo<br />
Id.*.Id.+.Id → Término.*.Id.+.Id → Expresión.*.Id.+.Id →<br />
Expresión.*.Término.+.Id → Expresión.+.Id →<br />
Expresión.+.Término → Expresión
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Analizadores <strong>Sintáctico</strong>s,<br />
Problemas<br />
Descen<strong>de</strong>ntes<br />
• Mas <strong>de</strong> una opción: A::= α | β<br />
• Retroceso<br />
• Analizar los siguientes elementos <strong>de</strong> la entrada<br />
• Recursividad izquierda<br />
• Eliminación <strong>de</strong> la recursividad<br />
• Ambigüedad<br />
• Factorización por la izquierda<br />
Ascen<strong>de</strong>ntes<br />
• Más <strong>de</strong> una opción: A::= α y α es el pivote<br />
Otros<br />
• Problemas semánticos<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo<br />
No necesita realizar retroceso para analizar bien las<br />
sentencias <strong>de</strong>l lenguaje<br />
Sólo con ver el siguiente carácter <strong>de</strong> la entrada<br />
pue<strong>de</strong> <strong>de</strong>cidir cuál va a ser la siguiente producción a<br />
emplear<br />
Condiciones<br />
• Diseñar bien la gramática<br />
• Eliminar la recursividad izquierda<br />
• Factorizar por la izquierda<br />
No está asegurado el tener una gramática predictiva<br />
Las gramáticas son difíciles <strong>de</strong> leer<br />
Para las partes <strong>de</strong> las gramáticas que no son<br />
predictivas se pue<strong>de</strong>n utilizar otros analizadores
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo:<br />
Descen<strong>de</strong>nte Recursivo<br />
Se ejecuta un conjunto <strong>de</strong> procedimientos recursivos para<br />
procesar la entrada<br />
A cada NO Terminal <strong>de</strong> una gramática se le asocia un<br />
procedimiento<br />
• Deci<strong>de</strong> la producción que utilizará analizando el símbolo <strong>de</strong><br />
preanálisis,<br />
• si está en PRIMERO(α) entonces se usa la producción con lado <strong>de</strong>recho α<br />
• si no está en ningún PRIMERO entonces se usa una producción λ<br />
• Usa una producción imitando al lado <strong>de</strong>recho<br />
• no terminal da como resultado una llamada a otro procedimiento<br />
• terminal (que coinci<strong>de</strong> con el símbolo <strong>de</strong> preanálisis) produce otra lectura<br />
<strong>de</strong> otro token. Si el token no coinci<strong>de</strong> entonces Error<br />
La secuencia <strong>de</strong> procedimientos llamados para procesar la<br />
entrada <strong>de</strong>fine implícitamente un árbol <strong>de</strong> análisis sintáctico<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo:<br />
Descen<strong>de</strong>nte Recursivo<br />
Ejemplo:<br />
S → if B then S | write B | i := B<br />
B → i = i | i i | true | false<br />
Procedure S()<br />
{<br />
if (car== if)<br />
{ scan();<br />
B();<br />
if (car== then) {scan();} else error();<br />
S();<br />
}<br />
else if (car==write)<br />
{scan();<br />
B();<br />
}<br />
else if (car== i)<br />
{ scan();<br />
if (car == asig) {scan();} else error();<br />
B();<br />
}<br />
else error()<br />
}<br />
Procedure B()<br />
{<br />
if (car= i)<br />
{ scan();<br />
if (car in [igual, noigual]) scan(); else error();<br />
if (car == i) then scan else error;<br />
}<br />
elseif (car in [true, false])<br />
scan();<br />
else<br />
error();<br />
}
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo,<br />
DEFINICIONES: PRIMERO<br />
Si α es una ca<strong>de</strong>na <strong>de</strong> símbolos gramaticales,<br />
PRIMERO(α) es el conjunto <strong>de</strong> terminales que inician las<br />
ca<strong>de</strong>nas <strong>de</strong>rivadas <strong>de</strong> α.<br />
• PRIMERO(α)={x | (α → * xβ), (x ∈ Σ T ∪ {λ}), (α, β ∈Σ * )}<br />
Conjunto PRIMERO(X) para todos los símbolos<br />
gramaticales X<br />
1. Repetir hasta que no se puedan añadir más terminales o λ a<br />
ningún conjunto PRIMERO<br />
2. Si X ∈ Σ T ⇒ PRIMERO(X) es { X }<br />
3. Si X → λ⇒añadir λ a PRIMERO(X)<br />
4. Si X ∈ Σ N y X →Y 1 Y 2 ...Y K Y ⇒ a ∈ PRIMERO(X) si a ∈ PRIMERO(Y i )<br />
y λ ∈PRIMERO(Y 1 ), PRIMERO(Y 2 ),..., PRIMERO(Y i-1 )<br />
• Si Y 1<br />
<strong>de</strong>riva a λ ⇒se aña<strong>de</strong> PRIMERO(Y 2<br />
)<br />
• Si Y 1<br />
no <strong>de</strong>riva a λ ⇒no se aña<strong>de</strong> más a PRIMERO(X)<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo,<br />
DEFINICIONES: PRIMERO<br />
PRIMERO(α), Ejemplo:<br />
E ::= T.E’<br />
E’ ::= +.T.E’ | λ<br />
T ::= F.T’<br />
T’ ::= *.F.T’ | λ<br />
F ::= (.E.) | Id<br />
• PRIMERO(E) = { (, Id } PRIMERO(T.*.Id) = { (, Id }<br />
• PRIMERO(T) = { (, Id } PRIMERO(Id.+.Id) = { Id }<br />
• PRIMERO(F) = { (, Id } PRIMERO(Id) = { Id }<br />
• PRIMERO(E’) = { +, λ } PRIMERO(T’) = { *, λ }
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo,<br />
DEFINICIONES: SIGUIENTE<br />
Conjunto SIGUIENTE(A)<br />
• SIGUIENTE(A)={x|(S→ * α·A·β), (A∈Σ N ), (α∈Σ * ), (β∈Σ + ),<br />
(x∈PRIMERO(β)-{λ})}<br />
• Conjunto <strong>de</strong> terminales que pue<strong>de</strong>n aparecer<br />
inmediatamente a la <strong>de</strong>recha <strong>de</strong> A en alguna forma<br />
sentencial, si A es el último símbolo entonces se incluye el<br />
separador $<br />
Algoritmo<br />
1. SIGUIENTE(S)={$}<br />
2. La regla A→αBβ ⇒<br />
SIGUIENTE(B) = (PRIMERO(β)-{λ}) ∪<br />
SIGUIENTE(B)<br />
3. La regla A→αBβ | β=λ, β→ * λ (λ ∈PRIMERO(β)) ⇒<br />
SIGUIENTE(B) = SIGUIENTE(A) ∪ SIGUIENTE(B)<br />
4. Repetir hasta que no cambie ningún conjunto SIGUIENTE<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo,<br />
DEFINICIONES: SIGUIENTE<br />
SIGUIENTE(A), Ejemplo:<br />
E ::= T.E’<br />
E’ ::= +.T.E’ | λ<br />
T ::= F.T’<br />
T’ ::= *.F.T’ | λ<br />
F ::= (.E.) | Id<br />
Σ N<br />
SIGUIENTE<br />
E $, )<br />
E’ $, )<br />
F $, *, ), +<br />
T $, +, )<br />
T’ $, +, )
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo:<br />
Condiciones<br />
Pregunta:<br />
• ¿Que <strong>de</strong>be cumplir una gramática para que pueda ser<br />
reconocida sin retroceso, con solo mirar el siguiente elemento<br />
<strong>de</strong> la entrada, <strong>de</strong> forma <strong>de</strong>scen<strong>de</strong>nte?<br />
Respuesta:<br />
• Si A::= α | β ⇒<br />
• PRIMERO(α) ∩ PRIMERO(β) = ∅. para ningún terminal a<br />
tanto α y β <strong>de</strong>rivan a la vez ca<strong>de</strong>nas que comiencen con a<br />
• No pue<strong>de</strong> ocurrir que α → * λ y β → * λ<br />
• Si β → * λ, entonces α no <strong>de</strong>riva ninguna ca<strong>de</strong>na que<br />
comience con un terminal en SIGUIENTE(A)<br />
• Condición LL(1)<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo:<br />
Condiciones<br />
Condición LL(1)<br />
• No pue<strong>de</strong> haber conflictos PRIMERO/PRIMERO<br />
• ∀N∈Σ N<br />
, el conjunto PRIMERO <strong>de</strong> todas sus alternativas <strong>de</strong>be<br />
ser disjunto<br />
• No pue<strong>de</strong> haber múltiples alternativas nulas<br />
• ∀N∈Σ N<br />
, solo pue<strong>de</strong>n tener una producción N→*λ<br />
• No pue<strong>de</strong> haber conflictos PRIMERO/SIGUIENTE<br />
• ∀N∈Σ N<br />
, con una alternativa nula, SIGUIENTE(N) <strong>de</strong>be ser<br />
disjunto <strong>de</strong> los conjuntos PRIMERO <strong>de</strong> todas sus alternativas<br />
• No pue<strong>de</strong> haber entradas con <strong>de</strong>finiciones múltiples en la<br />
tabla <strong>de</strong> análisis
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo:<br />
Tabla <strong>de</strong> <strong>Análisis</strong> <strong>Sintáctico</strong><br />
Funcionamiento<br />
• Sea A→α con a∈Σ T | a∈PRIMERO(α). El analizador sintáctico<br />
expandirá A por α cuando el símbolo actual <strong>de</strong> la entrada sea a<br />
Algoritmo<br />
ForAll (A::= α) ∈ Ρdo<br />
ForAll a ∈ PRIMERO(α) do<br />
tabla(A,a)= α<br />
Si λ ∈PRIMERO(α)<br />
Entonces ForAll b ∈ SIGUIENTE(A) do<br />
tabla(A,b)= α<br />
ForAll A∈Σ N y c∈Σ T do<br />
If tabla(A,c)= ∅<br />
Then tabla(A,c)= error<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo:<br />
Tabla <strong>de</strong> <strong>Análisis</strong> <strong>Sintáctico</strong><br />
Ejemplo<br />
E ::= T.E’<br />
E’ ::= +.T.E’ | λ<br />
T ::= F.T’<br />
T’ ::= *.F.T’ | λ<br />
F ::= (.E.) | Id<br />
Id + * ( ) $<br />
E T.E’ T.E’<br />
E’ +.T.E’ λ λ<br />
T F.T’ F.T’<br />
T’ λ *.F.T’ λ λ<br />
F Id (.E.)
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo<br />
No Recursivo; LL(1)<br />
Mo<strong>de</strong>lo <strong>de</strong> analizador sintáctico predictivo no<br />
recursivo<br />
ENTRADA<br />
a + b $<br />
PILA<br />
X<br />
Y<br />
Z<br />
$<br />
Programa <strong>de</strong><br />
<strong>Análisis</strong> <strong>Sintáctico</strong><br />
Predictivo<br />
Tabla <strong>de</strong> <strong>Análisis</strong><br />
<strong>Sintáctico</strong> M<br />
SALIDA<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Predictivo<br />
No Recursivo; LL(1)<br />
Los símbolos <strong>de</strong> la entrada actual “a” y cima <strong>de</strong> la<br />
pila “X” <strong>de</strong>terminan la acción <strong>de</strong>l analizador<br />
Hay tres posibilida<strong>de</strong>s:<br />
• X=a=$, el analizador se <strong>de</strong>tiene y anuncia el éxito <strong>de</strong>l<br />
análisis<br />
• X=a≠$, el analizador saca X <strong>de</strong> la pila y mueve el apuntador<br />
<strong>de</strong> la entrada al siguiente símbolo <strong>de</strong> entrada<br />
• X∈Σ N , el programa consulta la entrada M[X,a]<br />
• Si M[X,a]=UVW, se sustituye la X <strong>de</strong> la pila por WVU (U queda<br />
como cima <strong>de</strong> la pila)<br />
• Si M[X,a]= error, se llama a la rutina <strong>de</strong> recuperación <strong>de</strong> error
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> LL(1)<br />
Algoritmo:<br />
pila =$;<br />
meter$ al final <strong>de</strong> la entrada;<br />
a:= GetToken;<br />
Push S;<br />
Repeat<br />
If X ∈Σ T<br />
or X=$ then<br />
If X=a then<br />
Pop;<br />
a:= GetToken;<br />
Else<br />
error;<br />
Else<br />
If M[X,a]=X→Y 1<br />
Y 2<br />
..Y k<br />
then<br />
Pop;<br />
Push Y k<br />
,Y k-1<br />
,...,Y 1<br />
Emitir la producción X<br />
else<br />
error();<br />
until X=$<br />
If X=$ and a=$ then<br />
Aceptar;<br />
else<br />
error();<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> LL(1)<br />
Ejemplo:<br />
Pila Entrada Producción<br />
$ ⋅ E Id ⋅ * ⋅ Id ⋅ + ⋅ Id ⋅ $ E::= T ⋅ E’<br />
$ ⋅ E’ ⋅ T Id ⋅ * ⋅ Id ⋅ + ⋅ Id ⋅ $ T::= F ⋅ T’<br />
$ ⋅ E’ ⋅ T’ ⋅ F Id ⋅ * ⋅ Id ⋅ + ⋅ Id ⋅ $ F::= Id<br />
$ ⋅ E’ ⋅ T’ ⋅ Id Id ⋅ * ⋅ Id ⋅ + ⋅ Id ⋅ $<br />
$ ⋅ E’ ⋅ T’ * ⋅ Id ⋅ + ⋅ Id ⋅ $ T’::= * ⋅ F ⋅ T’<br />
$ ⋅ E’ ⋅ T’ ⋅ F ⋅ * * ⋅ Id ⋅ + ⋅ Id ⋅ $<br />
$ ⋅ E’ ⋅ T’ ⋅ F Id ⋅ + ⋅ Id ⋅ $ F::= Id<br />
$ ⋅ E’ ⋅ T’ ⋅ Id Id ⋅ + ⋅ Id ⋅ $<br />
$ ⋅ E’ ⋅ T’ + ⋅ Id ⋅ $ T’::= λ<br />
$ ⋅ E’ + ⋅ Id ⋅ $ E’::= + ⋅ T ⋅ E’<br />
$ ⋅ E’ ⋅ T ⋅ + + ⋅ Id ⋅ $<br />
$ ⋅ E’ ⋅ T Id ⋅ $ T::= F ⋅ T’<br />
$ ⋅ E’ ⋅ T’ ⋅ F Id ⋅ $ F::= Id<br />
$ ⋅ E’ ⋅ T’ ⋅ Id Id ⋅ $<br />
$ ⋅ E’ ⋅ T’ $ T’::= λ<br />
$ ⋅ E’ $ E’::= λ<br />
$ $
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Ascen<strong>de</strong>nte<br />
<strong>Análisis</strong> por <strong>de</strong>splazamiento y reducción<br />
• Por prece<strong>de</strong>ncia <strong>de</strong> operadores<br />
• LR<br />
Construir un árbol <strong>de</strong> análisis sintáctico para una<br />
ca<strong>de</strong>na <strong>de</strong> entrada que comienza por las hojas y<br />
avanza hacia la raíz.<br />
Reducir una ca<strong>de</strong>na <strong>de</strong> entrada w al símbolo inicial<br />
<strong>de</strong> la gramática (axioma)<br />
En cada paso <strong>de</strong> reducción se sustituye una<br />
subca<strong>de</strong>na que concuer<strong>de</strong> con el lado <strong>de</strong>recho <strong>de</strong><br />
una producción por el símbolo <strong>de</strong>l lado izquierdo, se<br />
traza una <strong>de</strong>rivación por la <strong>de</strong>recha en sentido<br />
inverso<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Ascen<strong>de</strong>nte:<br />
Gramática <strong>de</strong> Operadores<br />
Para una pequeña clase <strong>de</strong> gramáticas se pue<strong>de</strong> construir<br />
con facilidad, a mano, eficientes analizadores sintácticos<br />
por <strong>de</strong>splazamiento y reducción<br />
Gramática <strong>de</strong> operadores<br />
• No tiene reglas <strong>de</strong> producción <strong>de</strong>l tipo A::=λ<br />
• No tiene dos no terminales adyacentes A::=α·B·C·β | A,B,C ∈Σ N<br />
Ejemplo<br />
No es G. <strong>de</strong> operadores<br />
Si es G. <strong>de</strong> operadores<br />
E→EAE | (E) | -E | id<br />
A→+ | - | * | /<br />
E→E+E | E-E | E*E | E/E | (E) | -E | id
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador:<br />
Relaciones <strong>de</strong> Prece<strong>de</strong>ncia<br />
Se <strong>de</strong>finen tres relaciones <strong>de</strong> prece<strong>de</strong>ncia<br />
disjuntas<br />
• ab si a tiene más prece<strong>de</strong>ncia que b<br />
Algoritmo<br />
Sustituir todos los símbolos no terminales por un único símbolo<br />
Insertar $ al principio y al final <strong>de</strong> la ca<strong>de</strong>na <strong>de</strong> entrada<br />
Insertar las relaciones <strong>de</strong> prece<strong>de</strong>ncia en la ca<strong>de</strong>na <strong>de</strong> entrada<br />
Mientras entrada≠$S$ hacer<br />
Recorrer entrada <strong>de</strong>s<strong>de</strong> la izquierda hasta encontrar •><br />
Buscar a la izquierda, a partir <strong>de</strong> ese punto, el primer •> •> •><br />
Id •> •> •> •><br />
* •> •><br />
+ <br />
(
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador:<br />
Evaluador <strong>de</strong> Expresiones<br />
El análisis recorre la entrada <strong>de</strong> izquierda a <strong>de</strong>recha y<br />
se encuentra en dos posibles estados:<br />
• Esperando un operando (variables o constantes)<br />
• Esperando un operador (resto <strong>de</strong> terminales)<br />
El análisis mantiene dos pilas<br />
• Pila <strong>de</strong> Operadores<br />
• Pila <strong>de</strong> Operandos<br />
Cuando un operador en la cima <strong>de</strong> su pila es <strong>de</strong> más<br />
prece<strong>de</strong>ncia que el siguiente leído, entonces arranca<br />
la reducción <strong>de</strong>l pivote, hasta encontrar la relación <strong>de</strong><br />
prece<strong>de</strong>ncia mayor. Cada operador extraído se aplica<br />
a los operandos más arriba <strong>de</strong> la pila <strong>de</strong> operandos<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Evaluación <strong>de</strong> Expresiones<br />
Algoritmo <strong>de</strong> evaluación <strong>de</strong> expresiones:<br />
pilaOperadores = $;<br />
poner $ al final <strong>de</strong> la entrada;<br />
a:= GetToken;<br />
repeat<br />
if a=$ y cimaOperadores=$ then return<br />
if a es Operando then PushOperando (a); a:=GetToken;<br />
else<br />
if (cimaOperandos
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Ascen<strong>de</strong>nte:<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador<br />
Entrada:<br />
• Id·+·Id·*·Id<br />
Gramática<br />
• E:=E·+·E | E·*·E | (·E·) | Id<br />
La gramática es ambigua pero este tipo <strong>de</strong> análisis<br />
proporciona una única <strong>de</strong>rivación<br />
Entrada Pila Operadores Pila Operandos<br />
Id a·+·Id b·*·Id c<br />
$ $ ∅<br />
+·Id b·*·Id c<br />
$ $ Id a<br />
Id b·*·Id c<br />
$ $ + Id a<br />
*·Id c<br />
$ $ + Id a<br />
, Id b<br />
Id c<br />
$ $ + * Id a<br />
,Id b<br />
$ $ + * Id a<br />
,Id b<br />
,Id c<br />
$ $ + Id a<br />
, Id b<br />
*Id c<br />
$ $ Id a<br />
+Id b<br />
*Id d<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Ascen<strong>de</strong>nte:<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador<br />
Entrada: Id*(Id+Id*Id)<br />
Entrada Pila Operadores Pila Operandos<br />
Id a<br />
.*.(Id b·+·Id c<br />
.*. Id d<br />
)$ $ ∅<br />
.*.(Id b·+·Id c<br />
.*.Id d<br />
)$ $ Id a<br />
(Id b·+·Id c<br />
.*.Id d<br />
)$ $ * Id a<br />
Id b·+·Id c<br />
.*.Id d<br />
)$ $ * ( Id a<br />
·+·Id c<br />
.*.Id d<br />
)$ $ * ( Id a<br />
, Id b<br />
Id c<br />
.*.Id d<br />
)$ $ * ( + Id a<br />
,Id b<br />
.*.Id d<br />
)$ $ * ( + Id a<br />
,Id b<br />
,Id c<br />
Id d<br />
)$ $ * ( + * Id a<br />
,Id b<br />
,Id c<br />
)$ $ * ( + * Id a<br />
,Id b<br />
,Id c<br />
, Id d<br />
)$ $ * ( + Id a<br />
,Id b<br />
,Id c<br />
*Id d<br />
)$ $ * ( Id a<br />
,Id b<br />
+Id c<br />
*Id d<br />
$ $ * ( ) Id a<br />
,Id b<br />
+Id c<br />
*Id d<br />
$ $ Id a<br />
*(Id b<br />
+Id c<br />
*Id d<br />
)
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Ascen<strong>de</strong>nte:<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador<br />
Entrada: Id*(Id+Id)+Id<br />
Entrada Pila Operadores Pila Operandos<br />
Id a<br />
.*.(Id b·+·Id c<br />
).+. Id d<br />
$ $ Id a<br />
.*.(Id b·+·Id c<br />
).+. Id d<br />
$ $ Id a<br />
(Id b·+·Id c<br />
).+. Id d<br />
$ $ * Id a<br />
Id b·+·Id c<br />
).+. Id d<br />
$ $ * ( Id a<br />
.+·Id c<br />
).+. Id d<br />
$ $ * ( Id a<br />
Id b<br />
Id c<br />
).+. Id d<br />
$ $ * ( + Id a<br />
Id b<br />
).+. Id d<br />
$ $ * ( + Id a<br />
Id b<br />
Id c<br />
).+. Id d<br />
$ $ * ( Id a<br />
Id b<br />
+Id c<br />
.+. Id d<br />
$ $ * ( ) Id a<br />
Id b<br />
+Id c<br />
.+. Id d<br />
$ $ * Id a<br />
Id b<br />
+Id c<br />
.+. Id d<br />
$ $ Id a<br />
*(id b<br />
+Id c<br />
)<br />
Id d<br />
$ $ + Id a<br />
*(id b<br />
+Id c<br />
)<br />
$ $ + Id a<br />
*(id b<br />
+Id c<br />
) Id d<br />
$ $ Id a<br />
*(id b<br />
+Id c<br />
)+Id d<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador:<br />
Construir la Tabla <strong>de</strong> Prece<strong>de</strong>ncia<br />
Si el operador θ 1 tiene mayor prece<strong>de</strong>ncia que θ 2<br />
entonces hacer θ 1 •>θ 2 y θ 2 θ 2 y θ 2 •> θ 1 si son asociativos por la izquierda<br />
• θ 1
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador:<br />
Operadores Unarios (¬)<br />
Manejo <strong>de</strong> Operadores Unarios (¬)<br />
• Operador Unario que no es a<strong>de</strong>más Binario<br />
• θ θ ∀ θ si ¬ tiene mayor prece<strong>de</strong>ncia que θ<br />
• ¬
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador:<br />
Calcular la Tabla <strong>de</strong> Prece<strong>de</strong>ncia<br />
Definiciones:<br />
• Cabecera(A) = { x | (A→ * α·x·β)<br />
∧ (x ∈Σ T ) ∧ (A ∈Σ N ) ∧ (α ∈Σ N* ) ∧ (β ∈Σ * )}<br />
• Último(A) = { x | (A→ * α·x·β)<br />
∧ (x ∈Σ T ) ∧ (A ∈Σ N ) ∧ (α ∈Σ * ) ∧ (β ∈Σ N* )}<br />
Ejemplo:<br />
E::=E·+·T | T<br />
Cabecera(E)={+, *, (, Id}<br />
T::=T·*·F | F<br />
Último(E)={+, *, ), Id}<br />
F::=(·E·) | Id<br />
Propiedad:<br />
• ∀(A::= α·B·a·C·β) ∈ P, a ∈Σ T , A, B, C ∈Σ N , α, β∈Σ * , a siempre<br />
aparece en un nivel superior a los símbolos terminales <strong>de</strong><br />
Cabecera(C) y Último(B) en el árbol <strong>de</strong> <strong>de</strong>rivación<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador:<br />
Calcular la Tabla <strong>de</strong> Prece<strong>de</strong>ncia<br />
Reglas:<br />
(A::= α·B·a·C·β) ∈ P, a ∈ Σ T , A, B, C ∈ Σ N , α, β ∈Σ *<br />
1. ∀c ∈ Cabecera(C), a a<br />
3. ∀ (A::= α·a·β·b·γ) ∈ P, a, b ∈Σ T , a=b , β∈Σ *<br />
Si existe más <strong>de</strong> una relación <strong>de</strong> prece<strong>de</strong>ncia entre dos<br />
símbolos terminales, no es una gramática <strong>de</strong><br />
prece<strong>de</strong>ncia<br />
Algoritmo<br />
ForAll (A::= α·B·a·C·β) ∈ P do<br />
Calcular Cabecera(C)<br />
Calcular Último(B)<br />
Calcular las prece<strong>de</strong>ncias usando las reglas 1, 2 y 3<br />
ForAll a ∈ Cabecera(S) do $ $
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Ejemplo Calculo <strong>de</strong> Tabla <strong>de</strong><br />
Prece<strong>de</strong>ncia<br />
Gramática<br />
E::=E·+·T | T<br />
T::=T·*·F | F<br />
F::=(·E·) | Id<br />
Cabecera y Último<br />
Σ N Cabecera Último<br />
E +, *, (, Id +, *, ), Id<br />
T *, (, Id *, ), Id<br />
F (, Id ), Id<br />
Tabla<br />
Regla Prece<strong>de</strong>ncias(R 2 ) Prece<strong>de</strong>ncias (R 1 )<br />
E::=E+T +, *, ), Id •> + + * * g(b)<br />
Para encontrar la relación <strong>de</strong> prece<strong>de</strong>ncia entre a y b<br />
se realiza una comparación entre f(a) y g(b)<br />
No todas las relaciones <strong>de</strong> prece<strong>de</strong>ncia tienen<br />
funciones <strong>de</strong> prece<strong>de</strong>ncia
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador:<br />
Funciones <strong>de</strong> Prece<strong>de</strong>ncia<br />
Construcción <strong>de</strong> las Funciones <strong>de</strong> Prece<strong>de</strong>ncia<br />
1. Crear los símbolos f a y g a ∀ a∈Σ T ∪ {$}<br />
2. Se divi<strong>de</strong>n los f a y g a en tantos grupos como sea posible:<br />
• Si a=b entonces f a<br />
y g b<br />
están en el mismo grupo<br />
3. Crear un grafo dirigido cuyos nodos son los grupos<br />
encontrados en el paso 2, los arcos se etiquetan:<br />
• si ab, a<br />
f → g b<br />
4. Ciclos en el grafo:<br />
• Respuesta SI, entonces no existen funciones <strong>de</strong> prece<strong>de</strong>ncia<br />
• Respuesta NO, entonces f(a) y g(a) son los caminos más<br />
largos que comienzan en a<br />
f y g a<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador:<br />
Funciones <strong>de</strong> Prece<strong>de</strong>ncia<br />
Ejemplo<br />
Id + * $<br />
Id •> •> •><br />
+ <br />
* •> •><br />
$
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador:<br />
Funciones <strong>de</strong> Prece<strong>de</strong>ncia<br />
No hay ciclos, entonces existen las funciones <strong>de</strong><br />
prece<strong>de</strong>ncia.<br />
Como las funciones <strong>de</strong> $ no tienen arcos<br />
entonces f($)=g($)=0<br />
El camino más largo <strong>de</strong>s<strong>de</strong> g + tiene longitud 1,<br />
entonces g(+)=1<br />
El camino más largo <strong>de</strong>s<strong>de</strong> g Id a f * a g * a f + a f $<br />
por tanto g(id)=5<br />
Id + * $<br />
f 4 2 4 0<br />
g 5 1 3 0<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> <strong>Sintáctico</strong> Ascen<strong>de</strong>nte:<br />
Prece<strong>de</strong>ncia <strong>de</strong> Operador<br />
Inconvenientes<br />
• Es difícil <strong>de</strong> manejar componentes léxicos con dos<br />
prece<strong>de</strong>ncias distintas, como el signo menos (unario y<br />
binario)<br />
• No se pue<strong>de</strong> tener la seguridad <strong>de</strong> que el analizador acepta<br />
exactamente el lenguaje <strong>de</strong>seado<br />
• Sólo una pequeña clase <strong>de</strong> gramáticas pue<strong>de</strong> analizarse<br />
Ventajas<br />
• Sencillez<br />
• Se pue<strong>de</strong>n establecer relaciones <strong>de</strong> prece<strong>de</strong>ncia (* prece<strong>de</strong><br />
a +)<br />
Se aplican con otros analizadores para la parte que<br />
no son <strong>de</strong> operador
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
<strong>Análisis</strong> Ascen<strong>de</strong>nte LR<br />
LR(k): Left-to-right, rightmost <strong>de</strong>rivation, k símbolos<br />
<strong>de</strong> entrada son necesarios para tomar las <strong>de</strong>cisiones<br />
<strong>de</strong> análisis sintáctico<br />
• Ventajas<br />
• Es el método <strong>de</strong> análisis por <strong>de</strong>splazamiento y reducción sin<br />
retroceso más general, a pesar <strong>de</strong> esto es igual <strong>de</strong> eficiente<br />
• La clase <strong>de</strong> gramáticas que pue<strong>de</strong>n analizarse es un<br />
supraconjunto <strong>de</strong> la clase <strong>de</strong> gramáticas que pue<strong>de</strong>n analizarse<br />
con analizadores sintácticos predictivos<br />
• Detectan los errores sintácticos tan pronto como es posible en<br />
un examen <strong>de</strong> izquierda a <strong>de</strong>recha <strong>de</strong> la entrada<br />
• Se pue<strong>de</strong>n reconocer prácticamente todas las construcciones<br />
<strong>de</strong> los lenguajes <strong>de</strong> programación <strong>de</strong>scritos por una gramática<br />
G2<br />
• Inconvenientes<br />
• La construcción “a mano” requiere mucho trabajo<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Tipos <strong>de</strong> Análizadores LR<br />
LR simple (SLR)<br />
• Fácil <strong>de</strong> implementar<br />
• Menos po<strong>de</strong>roso, hay algunas gramáticas que los<br />
otros métodos pue<strong>de</strong>n analizar y este no pue<strong>de</strong><br />
LR canónico<br />
• Es muy costoso <strong>de</strong> implementar<br />
• El más potente<br />
LALR (LR con símbolo <strong>de</strong> preanálisis)<br />
• Intermedio entre los dos métodos anteriores
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Mo<strong>de</strong>lo <strong>de</strong> un Analizador LR<br />
ENTRADA<br />
a 1<br />
... a 1<br />
... a n<br />
$<br />
Pila<br />
s m<br />
X m<br />
s m-1<br />
Programa <strong>de</strong><br />
<strong>Análisis</strong> <strong>Sintáctico</strong><br />
LR<br />
SALIDA<br />
X m-1<br />
...<br />
s 0<br />
Acción Ir_a<br />
Tabla <strong>de</strong> <strong>Análisis</strong><br />
<strong>Sintáctico</strong> LR<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Mo<strong>de</strong>lo <strong>de</strong> Analizador LR<br />
El programa es el mismo para todos los analizadores<br />
LR<br />
X i es un símbolo gramatical y cada s i es un símbolo<br />
llamado estado<br />
Se utiliza el símbolo <strong>de</strong> estado y el símbolo <strong>de</strong> la<br />
entrada para in<strong>de</strong>xar la tabla y <strong>de</strong>terminar la acción<br />
siguiente<br />
La tabla <strong>de</strong> análisis sintácticos tiene dos partes:<br />
• Acción[s m , a ]= i<br />
• Error:<br />
• Aceptar:<br />
• Desplazar:<br />
• Reducción:<br />
• Ir_a[s m , X i ]= s k<br />
error <strong>de</strong> sintaxis<br />
acepta la entrada, el análisis sintáctico finaliza<br />
introduce en la pila el símbolo a i y el estado s m<br />
extrae símbolos <strong>de</strong> la pila, ejecuta la acción<br />
semántica correspondiente a una producción
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Mo<strong>de</strong>lo <strong>de</strong> Analizador LR<br />
Configuración <strong>de</strong> un analizador sintáctico LR<br />
• Tupla con el contenido <strong>de</strong> la pila y la entrada que<br />
resta por procesar<br />
(s 0 X 1 s 1 X 2 s 2 ... X m s m , a i a i+1 ... a n $)<br />
Acción[s m , a ] i = <strong>de</strong>splazar s<br />
(s 0 X 1 s 1 X 2 s 2 ... X m s m a i s, a i+1 ... a n $)<br />
Acción[s m , a ] i = reducir A →β<br />
(s 0 X 1 s 1 X 2 s 2 ... X m-r s m-r A s, a i a i+1 ... a n $)<br />
don<strong>de</strong> s=Ir_a[s m-r , A] y r=|β| (se extraen r<br />
símbolos no terminales y r símbolos <strong>de</strong> estados<br />
<strong>de</strong> la pila)<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Algoritmo <strong>de</strong> <strong>Análisis</strong> LR<br />
apuntar ae al primer símbolo <strong>de</strong> w$ (s está en la cima y ae apunta al símbolo a)<br />
repetir<br />
case Acción[s, a]<br />
Desplazar s’<br />
push a<br />
push s’<br />
leer en la entrada<br />
Reducir A → β<br />
pop 2*|β| símbolos<br />
s’ símbolo en la cima <strong>de</strong> la pila<br />
s= Ir_a[s’, A]<br />
push A<br />
push s<br />
Aceptar<br />
Error<br />
fincaso<br />
hasta Aceptar o Error
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Ejemplo <strong>de</strong> <strong>Análisis</strong> LR<br />
Gramática<br />
1. E::= E·+·T<br />
2. E::= T<br />
3. T::= T·*·F<br />
4. T::= F<br />
5. F::= (·E·)<br />
6. F::= Id<br />
Tabla <strong>de</strong> análisis sintáctico<br />
Acción<br />
Ir_a<br />
Estado Id + * ( ) $ E T F<br />
0 d5 d4 1 2 3<br />
1 d6 ACP<br />
2 r2 d7 r2 r2<br />
3 r4 r4 r4 r4<br />
4 d5 d4 8 2 3<br />
5 r6 r6 r6 r6<br />
6 d5 d4 9 3<br />
7 d5 d4 10<br />
8 d6 d11<br />
9 r1 d7 r1 r1<br />
10 r3 r3 r3 r3<br />
11 r5 r5 r5 r5<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Ejemplo <strong>de</strong> <strong>Análisis</strong> LR<br />
Pila Entrada Acción<br />
0 Id·*·Id·+·Id·$ d5<br />
0 Id 5 *·Id·+·Id·$ r6<br />
0 F 3 *·Id·+·Id·$ r4<br />
0 T 2 *·Id·+·Id·$ d7<br />
0 T 2 * 7 Id·+·Id·$ d5<br />
0 T 2 * 7 Id 5 +·Id·$ r6<br />
0 T 2 * 7 F 10 +·Id·$ r3<br />
0 T 2 +·Id·$ r2<br />
0 E 1 +·Id·$ d6<br />
0 E 1 + 6 Id·$ d5<br />
0 E 1 + 6 Id 5 $ r6<br />
0 E 1 + 6 F 3 $ r4<br />
0 E 1 + 6 T 9 $ r1<br />
0 E 1 $ ACP
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construcción <strong>de</strong> Tabla <strong>de</strong> <strong>Análisis</strong><br />
SLR<br />
Definiciones:<br />
• Elemento <strong>de</strong>l análisis sintáctico LR(0) <strong>de</strong> una<br />
gramática G (elemento, ítem)<br />
• Producción <strong>de</strong> G con un “punto” en alguna posición <strong>de</strong>l lado<br />
<strong>de</strong>recho<br />
• El punto indica hasta don<strong>de</strong> se ha visto la producción en un<br />
momento <strong>de</strong>l análisis<br />
Ejemplo: La producción A→XYZ tiene cuatro elementos:<br />
A→•XYZ<br />
A→X•YZ<br />
Pregunta:<br />
¿Qué elemento genera la<br />
producción A→λ?<br />
A→XY•Z<br />
A→XYZ•<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construcción <strong>de</strong> Tabla <strong>de</strong> <strong>Análisis</strong><br />
SLR<br />
Definiciones:<br />
• Prefijo viable<br />
• Item válido para prefijo viable:<br />
A→β 1<br />
•β 2<br />
es item válido <strong>de</strong> αβ 1<br />
sii:<br />
S →* αAw→*αβ 1<br />
β 2<br />
w (A∈Σ N,<br />
, α,β 1<br />
,β 2<br />
∈Σ * , w∈Σ * T )<br />
rm rm<br />
• Estado<br />
• Conjunto <strong>de</strong> ítems<br />
• Dan lugar a los estados <strong>de</strong>l analizador sintáctico SLR<br />
• El conjunto <strong>de</strong> estados: colección canónica LR(0)<br />
Los ítems son los estados <strong>de</strong> un AF que reconoce los<br />
prefijos viables<br />
Los estados son las agrupaciones <strong>de</strong> estados, (¡La<br />
minimización <strong>de</strong>l AF!)
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Algoritmo: crear conjunto<br />
canónico LR(0)<br />
Entrada:<br />
• Gramática ampliada G’<br />
• Función cierre(I) (clausura o cerradura), I≡ítem +<br />
• Función goto(I, X) (ir_a), X∈(Σ T ∪Σ N )<br />
Salida<br />
• Conjunto canónico LR(0)<br />
Gramática ampliada G’ <strong>de</strong> G<br />
• Añadir S’, Σ N = (Σ N ∪ S’ ’) | S’ es el axioma<br />
• Añadir S’→ S, P= (P ∪ S’→ S)<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir el conjunto canónico<br />
LR(0)<br />
Función cierre(I)<br />
function cierre(I);<br />
begin<br />
J:=I;<br />
repeat<br />
for ∀ J i (A →α•Bβ) ∈ J , ∀ p (B →γ) ∈ P | (B → • γ) ∉ J<br />
do J := J ∪ (B → • γ) ;<br />
until no pue<strong>de</strong>n añadirse ítems a J ;<br />
return J<br />
end<br />
• Ejemplo:<br />
A→ B<br />
B → id | Cnum| ( D )<br />
C → + D<br />
D → id | num<br />
¿ cierre(A→ • B) ?<br />
A→ • B<br />
B → • id | • Cnum| •( D )<br />
C → •+ D
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir el conjunto canónico<br />
LR(0)<br />
Función goto(I, X)<br />
• Si I son items válidos <strong>de</strong> γ, goto(I, X) son los<br />
items válidos <strong>de</strong> γX<br />
function goto(I, X);<br />
begin<br />
J:=∅;<br />
∀ I i | (B →α•X β) ∈ I, J := J ∪ cierre(B →αX • β) ;<br />
return J<br />
end<br />
• Ejemplo:<br />
A→ B<br />
B → id | Cnum| ( D )<br />
C → + D<br />
D → id | num<br />
I = {B→ • id, B→ •( D )}<br />
¿ goto {I, ( }?<br />
B → (•D )<br />
D → • id<br />
D → • num<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Algoritmo: crear conjunto<br />
canónico LR(0)<br />
La función elementos proporciona la<br />
colección canónica <strong>de</strong> conjuntos <strong>de</strong><br />
elementos <strong>de</strong> LR(0)<br />
function elementos(G’);<br />
begin<br />
C:=cierre(S’ → • S);<br />
repeat<br />
for ∀ I ∈ C , ∀ X | goto(I, X) ≠∅, goto(I, X) ∉ C<br />
do C := C ∪ goto(I, X);<br />
until no pue<strong>de</strong>n añadirse más conjuntos <strong>de</strong> ítems a C;<br />
return C<br />
end
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir el conjunto canónico<br />
LR(0)<br />
Ejemplo:<br />
• G<br />
1. S → A B end<br />
2. A → tipo<br />
3. A → id A<br />
4. B → begin C<br />
5. C → código<br />
• G’<br />
1. S’ → S<br />
2. S → A B end<br />
3. A → tipo<br />
4. A → id A<br />
5. B → begin C<br />
6. C → código<br />
items LR(0):<br />
I 0 :<br />
I 1 :<br />
I 2 :<br />
I 3 :<br />
S’ → •S<br />
S → •A B end<br />
A → •tipo<br />
A → •id A<br />
S’ → S•<br />
S → A•B end<br />
B → •begin C<br />
A → tipo•<br />
I 4 : A → id•A<br />
A → •tipo<br />
A → •id A<br />
I 5 : S → A B•end<br />
I 6 : B → begin•C<br />
I 7 :<br />
C → •código<br />
A → id A•<br />
I 8 : S → A B end•<br />
I 9 : B → begin C•<br />
I 10 : C → código•<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir el conjunto canónico<br />
LR(0)<br />
El conjunto canónico <strong>de</strong>fine un AFD que reconoce los prefijos<br />
viables <strong>de</strong> G, con I 0 estado inicial e I j ∀j ≠ 0 estados finales<br />
S<br />
I 0 I 1<br />
A<br />
tipo<br />
id<br />
I 2<br />
I 3<br />
B<br />
end<br />
I 5 I 8<br />
begin<br />
C<br />
I 6 I 9<br />
tipo<br />
código<br />
A<br />
I 4 I 7<br />
id<br />
I 10<br />
Para cada prefijo alcanzado, I i <strong>de</strong>fine sus prefijos viables!
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir la tabla SLR (por fin)<br />
Entrada:<br />
• Gramática aumentada G’<br />
Salida<br />
• Tabla SLR, funciones <strong>de</strong> acción e ir_a<br />
Algoritmo<br />
1. Construir C={I 0 , I 1 , ..., I n } LR(0) <strong>de</strong> G’<br />
2. El estado i se construye a partir <strong>de</strong> I , i poner las<br />
operaciones a<strong>de</strong>cuadas <strong>de</strong>l analizador sintáctico<br />
3. Las entradas no <strong>de</strong>finidas son ERROR<br />
4. El estado inicial es el <strong>de</strong>l conjunto con [S’→•S]<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir la tabla SLR<br />
Operaciones asociadas a los ítems<br />
• Desplazar<br />
• Si [A→α•aβ] ∈ I i , a ∈Σ T , goto(I , i a) = I j ⇒ acción[i, a] =<br />
<strong>de</strong>splazar j<br />
• Reducir<br />
• Si [A→α•] ∈ I i , A ≠ S’ ⇒∀a ∈ SIGUIENTE(A),<br />
acción[i, a] = reducir A→α<br />
• Aceptar<br />
• Si [S’→S•] ∈ I i ⇒ acción[i,$] = aceptar<br />
• Ir_a<br />
• Si goto(I i , A) = I j , A ∈ Σ N ⇒ ir_a[i, A] = j
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir la tabla SLR<br />
ccLR(0)<br />
I 0 :<br />
S’ →•S ir_a[0,S]=1<br />
S → •A B end ir_a[0,A]=2<br />
A → •tipo acción[0,tipo]=d3<br />
A → •id A acción[0,id]=d4<br />
I 1 :<br />
S’ → S• acción[1,$]=aceptar<br />
I 2 :<br />
S → A•B end ir_a[2,B]=5<br />
B → •begin C acción[2,begin]=d6<br />
I 3 :<br />
A → tipo• acción[3,begin]=r(A → tipo)<br />
I 4 :<br />
A → id•A ir_a[4,A]=7<br />
A → •tipo acción[4,tipo]=d3<br />
A → •id A acción[4,id]=d4<br />
I 5 :<br />
S → A B•end acción[5,end]=d8<br />
I 6 :<br />
B → begin•C ir_a[6,C]=9<br />
C → •código acción[6,código]=d10<br />
I 7 :<br />
A → id A• acción[7,begin]=r(A → id)<br />
I 8 :<br />
S → A B end• acción[8,$]=r(S → A B end)<br />
I 9 :<br />
B → begin C• acción[9,end]=r(B → begin C)<br />
I 10 :<br />
C → código• acción[10,end]=r(C → código)<br />
Σ N Siguiente<br />
S $<br />
A begin<br />
B end<br />
C end<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Tabla SLR Resultante<br />
acción<br />
ir_a<br />
tipo id begin código $ end S A B C<br />
0 d3 d4 1 2<br />
1 ACP<br />
2 d6 5<br />
3 r(A → tipo)<br />
4 d3 d4 7<br />
5 d8<br />
6 d10 9<br />
7 r(A → id)<br />
8 r(S →AB end)<br />
9 r(B →begin C)<br />
10 r(C →código)
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Resumen<br />
El análisis sintáctico LR<br />
• El análisis ascen<strong>de</strong>nte sin retroceso más general<br />
• Utiliza una pila y una tabla <strong>de</strong> análisis<br />
• Desplazamiento/Reducción<br />
• La tabla SLR se obtiene haciendo el conjunto<br />
canónico LR(0)<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Analizador canónico LR<br />
Motivación<br />
• Tabla SLR tiene info insuficiente y pue<strong>de</strong>n aparecer<br />
conflictos <strong>de</strong>splazamiento/reducción<br />
• Si el estado I i contiene [A->β•] No es a<strong>de</strong>cuada<br />
siempre la reducción A->a para todos los terminales en<br />
Siguiente(A)<br />
• Dado prefijo viable αβ con items válidos en I i pue<strong>de</strong> ser que no<br />
existan formas sentenciales αAa, con a∈Siguiente(A)<br />
Ejemplo:<br />
S → L=R<br />
S → R<br />
L → *R<br />
L → id<br />
R → L
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Conjunto LR(0)<br />
Ejemplo:<br />
• G<br />
1. S → L=R<br />
2. S → R<br />
3. L → *R<br />
4. L → id<br />
5. R → L<br />
• G’<br />
1. S → L=R<br />
2. S → R<br />
3. L → *R<br />
4. L → id<br />
5. R → L<br />
6. S’ → S<br />
items LR(0):<br />
I 0 :<br />
I 1 :<br />
S’→ •S<br />
S → •L=R<br />
S → •R<br />
R → •L<br />
L →•*R<br />
L →•id<br />
S’ → S•<br />
I 2 : S → L • =R<br />
I 3 :<br />
R → L •<br />
S → R•<br />
I 4 : L → * • R<br />
R → •L<br />
L →•*R<br />
L →•id<br />
I 5 : L → id •<br />
I 6 : S → L = •R<br />
R → •L<br />
L →•*R<br />
L →•id<br />
I 7 : L → * R •<br />
I 8 : R → L•<br />
I 9 : S → L = R•<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Tabla <strong>de</strong> análisis LR(0)<br />
S<br />
I 0 I 1<br />
L<br />
R<br />
*<br />
id<br />
I 2<br />
=<br />
I 3<br />
I 6<br />
I 7<br />
I 9<br />
* R<br />
id<br />
L<br />
R<br />
I 5
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Conflicto en la tabla SLR!<br />
ccLR(0)<br />
acción<br />
....<br />
I 2<br />
: S → L • =R<br />
acción[2,=]=d6<br />
R → L • acción[2,=]=r5<br />
...<br />
Σ N Siguiente<br />
S $<br />
L $, =<br />
R $, =<br />
$ está en<br />
Siguiente(R) pero no<br />
hay ninguna<br />
<strong>de</strong>rivación don<strong>de</strong><br />
reducir L por R<br />
seguido <strong>de</strong> $<br />
Esta información <strong>de</strong><br />
contexto no se usa en<br />
el analizador SLR<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Items en LR(1)<br />
Ítems: estados <strong>de</strong> AF que reconoce los<br />
prefijos viables junto a símbolos posibles tras<br />
pivote<br />
• Elementos con más información:<br />
[A→β 1 •β 2 , a] con A→β 1 •β 2 ∈P, a∈Σ T<br />
• Definición:<br />
[A→β 1 •β 2 , a] es item válido <strong>de</strong> γ=αβ 1 sii:<br />
-S →* αAw→αβ 1 β 2 w<br />
rm<br />
rm<br />
-<br />
a es el primer símbolo <strong>de</strong> w (o si w es λ, a es $)<br />
• Estado:<br />
• Conjunto <strong>de</strong> estados: colección canónica LR(1)<br />
• Se aumentan los estados LR(0)
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Items en LR(1)<br />
Construcción: varía la función cierre(I)<br />
• [A→α•Bβ, a]∈I<br />
[A→α•Bβ, a] es item válido <strong>de</strong> γ=δα:<br />
S →* δAax→δαΒβax=γΒβax<br />
rm<br />
• Para cada item B→η:<br />
S →* γηby, ∀b|b∈Primero(βa)<br />
rm<br />
[B→ • η, b] ∈ cierre(I)<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir el conjunto canónico<br />
LR(1)<br />
Ejemplo:<br />
Función cierre(I)<br />
function cierre(I);<br />
begin<br />
J:=I;<br />
repeat<br />
for ∀ J i [A →α•Bβ,a] ∈ J , ∀ p (B →γ) ∈ P , ∀ b∈Primero(βa) |<br />
[B → • γ, b] ∉ J<br />
do J := J ∪ [B → • γ, b] ;<br />
until no pue<strong>de</strong>n añadirse ítems a J ;<br />
return J<br />
end<br />
S’→ S<br />
S → CC<br />
C → cC | d<br />
¿ cierre([S’→ •S,$])?<br />
[S’→ •S,$]<br />
[S→ •CC,$]<br />
[C→ •cC,c/d]<br />
[C→ •d,c/d]<br />
Primero<br />
$ $<br />
C$ c, d
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir el conjunto canónico<br />
LR(1)<br />
Función goto(I, X)<br />
• Si I son items válidos <strong>de</strong> γ, goto(I, X) son los items<br />
válidos <strong>de</strong> γX<br />
function goto(I, X);<br />
begin<br />
J:=∅;<br />
∀ I i | [B →α•X β, a] ∈ I, J := J ∪ cierre([B →αX • β, a]) ;<br />
return J<br />
end<br />
Ejemplo:<br />
S’→ S<br />
S → CC<br />
C → cC | d<br />
¿ goto([C→ •cC,c/d],c)?<br />
[C→ c•C,c/d]<br />
[C→ •cC,c/d]<br />
[C→ •d,c/d]<br />
(λ) c<br />
(λ) d<br />
Primero<br />
c<br />
d<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Algoritmo: crear conjunto<br />
canónico LR(1)<br />
La función elementos proporciona la<br />
colección canónica <strong>de</strong> conjuntos <strong>de</strong><br />
elementos <strong>de</strong> LR(1)<br />
function elementos(G’);<br />
begin<br />
C:=cierre([S’ → • S, $]);<br />
repeat<br />
for ∀ I ∈ C , ∀ X | goto(I, X) ≠∅, goto(I, X) ∉ C<br />
do C := C ∪ goto(I, X);<br />
until no pue<strong>de</strong>n añadirse más conjuntos <strong>de</strong> ítems a C;<br />
return C<br />
end
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Conj. LR(1)<br />
• G’<br />
1. S → L=R<br />
2. S → R<br />
3. L → *R<br />
4. L → id<br />
5. R → L<br />
6. S’ → S<br />
items LR(1):<br />
I 0 :<br />
[S’→•S,$]<br />
[S →•L=R,$]<br />
[S →•R,$]<br />
[L →•*R,=|$]<br />
[L →•id,=|$]<br />
[R →•L,$]<br />
I 1 : [S’ → S•,$]<br />
I 2 : [S → L• =R,$]<br />
[R → L•,$]<br />
I 3 : [S → R•,$]<br />
I 4 : [L → * • R,=|$]<br />
[R →•L,=|$]<br />
[L →•*R,=|$]<br />
[L →•id, =|$]<br />
I 5 : [L → id•,=|$]<br />
I 6 : [S →L=•R,$]<br />
[R →•L,$]<br />
[L →•*R,$]<br />
[L →•id, $]<br />
I 7 : [L → *R•,=|$]<br />
I 8 : [R → L•,=|$]<br />
I 9 : [S → L = R•,$]<br />
I 10 : [R → L•,$]<br />
I 11 : [L → id•,$]<br />
I 12 : [L → * • R,$]<br />
[R →•L,$]<br />
[L →•*R, $]<br />
[L →•id, $]<br />
I 13 : [L → *R•,$]<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Estados <strong>de</strong> analizador canónico LR(1)<br />
S<br />
I 0 I 1<br />
L<br />
R<br />
*<br />
id<br />
I 4 I 8 I 13<br />
L<br />
R<br />
I 9<br />
I 2<br />
=<br />
I 6<br />
R<br />
L<br />
I 10<br />
id<br />
L<br />
I 3 R<br />
I 7 I 11<br />
*<br />
*<br />
id<br />
I 5<br />
I 12
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir la tabla canónica LR<br />
Entrada:<br />
• Gramática aumentada G’<br />
Salida<br />
• Tabla LR, funciones <strong>de</strong> acción e ir_a<br />
Algoritmo<br />
1. Construir C={I 0 , I 1 , ..., I n } LR(1) <strong>de</strong> G’<br />
2. El estado i se construye a partir <strong>de</strong> I , i poner las<br />
operaciones a<strong>de</strong>cuadas <strong>de</strong>l analizador sintáctico<br />
3. Las entradas no <strong>de</strong>finidas son ERROR<br />
4. El estado inicial es el <strong>de</strong>l conjunto con [S’→•S, $]<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir la tabla canónica LR<br />
accLR(1)<br />
I 0 : [S’→•S,$] ir_a(0,S)=1<br />
[S →•L=R,$] ir_a(0,L)=2<br />
[S →•R,$] ir_a(0,R)=3<br />
[L →•*R,=] acc(0,*) =d4<br />
[L →•id,=] acc(0,id)=d5<br />
[R →•L,$]<br />
I 1 : [S’ → S•,$] acc(1,$)=ACP<br />
I 2 : [S → L• =R,$] acc(2,=)=d6<br />
[R → L•,$] acc(2,$)=r(R→L)<br />
I 3 : [S → R•,$] acc(3,$)=r(S→R)<br />
I 4 : [L → * • R,=] ir_a(4, R)=7<br />
[R →•L,=] ir_a(4, L)=8<br />
[L →•*R,=] acc(4,*)=d4<br />
[L →•id, =] acc(4,id)=d5<br />
I 5 : [L → id•,=] acc(5,=)=r(L→id)<br />
I 6 : [S →L=•R,$] ir_a(6,R)=9<br />
[R →•L,$] ir_a(6,L)=10<br />
[L →•*R,$] acc(6,*)= d12<br />
[L →•id, $] acc(6,id)=d11<br />
I 7 : [L →*R•,=] acc(7,=)=r(L →*R)<br />
I 8 : [R → L•,=] acc(8,=)=r(R →L)<br />
I 9 : [S → L = R•,$] acc(9,$)=r(S→L=R)<br />
I 10 : [R →L •,$] acc(10,$)=r(R→L)<br />
I 11 : [L → id•,$] acc(11,$)=r(L→id)<br />
I 12 : [L → * • R,$] ir_a(12,R)=13<br />
[R → •L,$] ir_a(12,L)=10<br />
[L →•*R, $] acc(12,*)=d12<br />
[L →•id, $] acc(12,id)=d11<br />
I 13 : [L → *R•,$] acc(13,$)=r(L →*R)
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Analizador LALR<br />
Motivación<br />
• Utilizado en la práctica al reducir el número <strong>de</strong> estados<br />
<strong>de</strong>l analizador canónico LR (mismo número que SLR)<br />
Forma estados a partir <strong>de</strong> la unión <strong>de</strong> estados <strong>de</strong><br />
LR(1) con el mismo núcleo<br />
• Si estado I i contiene [A->α • β, α], estado I j contiene<br />
[A->α • β, b] forma estado unión I ij con [A->α • β, a/b]<br />
Las gramáticas LALR(1) son un subconjunto <strong>de</strong><br />
LR(1).<br />
• Pue<strong>de</strong>n inducirse conflictos reducción/reducción pero<br />
nunca <strong>de</strong>splazamiento/reducción<br />
• Algunos errores se manifiestan más tar<strong>de</strong><br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Analizador LALR<br />
Dos principios <strong>de</strong>l analizador LALR(1)<br />
• El núcleo <strong>de</strong> cualquier estado <strong>de</strong>l AFD LR(1) es un<br />
estado <strong>de</strong>l AFD LR(0)<br />
• Si dos estados <strong>de</strong> LR(1), (s1, s2) tienen el mismo<br />
núcleo<br />
• Si goto(x1, X)=t1 ⇒∃t2,| goto(x2,X)=t2 y (t1,t2) mismo<br />
núcleo<br />
Corolario: el número <strong>de</strong> estados <strong>de</strong>l AFD <strong>de</strong>l<br />
analizador LALR(1) coinci<strong>de</strong> con el AFD LR(0)
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir la tabla LALR<br />
Algoritmo<br />
1. Construir C={I 0 , I 1 , ..., I n } LR(1) <strong>de</strong> G’<br />
2. Para cada núcleo en el conjunto <strong>de</strong> items LR(1),<br />
buscar todos los conjuntos con ese núcleo y<br />
reemplazarlos por su estado unión<br />
3. C’={J 0 , J 1 , ..., J m } pasan a ser los nuevos estados.<br />
Hacer transiciones. Las acciones se generan igual<br />
que en el analizador LR. Si hay conflictos, la<br />
gramática no es LALR(1)<br />
4. La tabla ir_a se forma sobre los conjuntos<br />
resultantes <strong>de</strong> efectuar las uniones <strong>de</strong> elementos<br />
LR(1) con el mismo núcleo<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Ejemplo<br />
Unir estados:<br />
‣ 4,12<br />
‣ 8,10<br />
‣ 5,11<br />
‣ 7,13<br />
estados LALR(1):<br />
I 0 : [S’→•S,$]<br />
[S →•L=R,$]<br />
[S →•R,$]<br />
[L →•*R,=]<br />
[L →•id,=]<br />
[R →•L,$]<br />
I 1 : [S’ → S•,$]<br />
I 2 : [S → L• =R,$]<br />
[R → L•,$]<br />
I 3 : [S → R•,$]<br />
I 4_12 :<br />
[L → * • R,=/$]<br />
[R →•L,=/$]<br />
[L →•*R,=/$]<br />
[L →•id, =/$]<br />
I 5_11 :<br />
[L → id•,=/$]<br />
I 6 : [S →L=•R,$]<br />
[R →•L,$]<br />
[L →•*R,$]<br />
[L →•id, $]<br />
I 7_13 :<br />
[L → *R•,=/$]<br />
I 8_10 :<br />
[R → L•,=/$]<br />
I 9 : [S → L = R•,$]
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Estados <strong>de</strong> analizador LALR(1)<br />
S<br />
I 0 I 1<br />
L<br />
R<br />
*<br />
id<br />
I 4 I 8<br />
L<br />
I 9<br />
I 2<br />
=<br />
I 6<br />
R<br />
L<br />
id<br />
I 3 R<br />
I 7 a I 5<br />
*<br />
*<br />
id<br />
I 5<br />
10 estados, igual que SLR(1)<br />
a I 8<br />
a I 4<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Construir la tabla LALR<br />
accLR(1)<br />
I 0 : [S’→•S,$] ir_a(0,S)=1<br />
[S →•L=R,$] ir_a(0,L)=2<br />
[S →•R,$] ir_a(0,R)=3<br />
[L →•*R,=] acc(0,*) =d4<br />
[L →•id,=] acc(0,id)=d5<br />
[R →•L,$]<br />
I 1 : [S’ → S•,$] acc(1,$)=ACP<br />
I 2 : [S → L• =R,$] acc(2,=)=d6<br />
[R → L•,$] acc(2,$)=r(R→L)<br />
I 3 : [S → R•,$] acc(3,$)=r(S→R)<br />
I 4 : [L → * • R,=/$] ir_a(4, R)=7<br />
[R →•L,=/$] ir_a(4, L)=8<br />
[L →•*R,=/$] acc(4,*)=d4<br />
[L →•id, =/$] acc(4,id)=d5<br />
I 5 : [L → id•,=/$] acc(5,=)=r(L→id)<br />
acc(5,$)=r(L→id)<br />
I 6 : [S →L=•R,$] ir_a(6,R)=9<br />
[R →•L,$] ir_a(6,L)=10<br />
[L →•*R,$] acc(6,*)= d12<br />
[L →•id, $] acc(6,id)=d11<br />
I 7 : [L →*R•,=/$] acc(7,=)=r(L →R)<br />
acc(7,$)=r(L →R)<br />
I 8 : [R → L•,=/$] acc(8,=)=r(R →L)<br />
acc(8,$)=r(R→L)<br />
I 9 : [S → L = R•,$] acc(9,$)=r(S→L=R)
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Uso <strong>de</strong> gramáticas ambiguas<br />
Una gramática ambigua nunca pue<strong>de</strong> ser LR<br />
A veces es útil emplear una gramática ambigua:<br />
• Construcciones más naturales y concisas<br />
• Aislar casos particulares que pue<strong>de</strong> ser útil tenerlos<br />
separados<br />
Una gramática ambigua pue<strong>de</strong> generar lenguaje<br />
con reglas para “<strong>de</strong>shacer la ambigüedad”<br />
• I<strong>de</strong>a similar a las reglas <strong>de</strong> prioridad en gramáticas <strong>de</strong><br />
operador<br />
• Las gramáticas ambiguas sólo <strong>de</strong>ben usarse <strong>de</strong> forma<br />
escasa y controlada, para asegurar qué lenguaje se<br />
reconoce<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Ejemplo 1ª gramática ambigua<br />
Sintaxis <strong>de</strong> condicional:<br />
• S→ if E then S else S<br />
• S→ if E then S<br />
• S→ other<br />
Gramática ambigua. Versión no Ambigua:<br />
• S→ S_emparejada | S_no_emparejada<br />
• S_emparejada→ if E then S_emparejada else S_emparejada<br />
• S_emparejada→ other<br />
• S_no_emparejada→ if E then S<br />
• S_no_emparejada→ if E then S_emparejada else<br />
S_no_emparejada
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Conj. LR(0)<br />
• G’<br />
1. S → iSeS<br />
2. S → iS<br />
3. S → a<br />
4. S’ → S<br />
items LR(0):<br />
I 0 : [S’ →•S]<br />
[S →•iSeS]<br />
[S →•iS]<br />
[S →•a]<br />
I 1 : [S’ → S•]<br />
I 2 : [S → i •SeS]<br />
[S → i •S]<br />
[S →•iSeS]<br />
[S →•iS]<br />
[S →•a]<br />
I 4 : [S → iS•eS]<br />
[S → i S•]<br />
I 5 : [S → iSe•S]<br />
[S →•iSeS]<br />
[S →•iS]<br />
[S →•a]<br />
I 6 : [S → iSeS •]<br />
I 3 : [S → a •]<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Acciones analizador SLR(1)<br />
Items LR(0)-acciones SLR (1):<br />
I 0 : [S’ →•S]<br />
[S →•iSeS] acc(0,i)=d2<br />
[S →•iS]<br />
[S →•a] acc(0,a)=d3<br />
I 1 : [S’ → S•]<br />
I 2 : [S → i •SeS]<br />
acc(1,$)=ACP<br />
[S → i •S]<br />
[S →•iSeS] acc(2,i)=d2<br />
[S →•iS]<br />
[S →•a] acc(2,a)=d3<br />
I 3 : [S → a •]<br />
acc(3,$)=r3<br />
acc(3,e)=r3<br />
I 4 : [S → iS•eS]<br />
acc(4,e)=d5<br />
[S → i S•] acc(4,e)=r2<br />
acc(4,$)=r2<br />
I 5 : [S → iSe•S]<br />
[S →•iSeS] acc(5,i)=d2<br />
[S →•iS]<br />
[S →•a] acc(5,i)=d3<br />
I 6 : [S → iSeS •]<br />
Σ N<br />
S<br />
Siguiente<br />
$,e<br />
acc(6,e)=r1<br />
acc(6,$)=r1
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Tabla SLR sin conflictos<br />
Resolución conflicto: en estado 4, <strong>de</strong>splazamiento<br />
sobre “else” (prioridad para if más anidado)<br />
acción<br />
ir_a<br />
i e a $ S<br />
0 d2 d3 1<br />
1 ACP<br />
2 d2 d3 4<br />
3 r3 r3<br />
4 d5 r2<br />
5 d2 d3<br />
6 r1 r1 6<br />
G:<br />
1. S → iSeS<br />
2. S → iS<br />
3. S → a<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Ejemplo 2ª gramática ambigua<br />
Gramática <strong>de</strong> expresiones con sumas y productos:<br />
E::=E·+·T | T<br />
T::=T·*·F | F<br />
F::=(·E·) | Id<br />
Versión ambigua:<br />
E:=E·+·E | E·*·E | (·E·) | Id<br />
Dos ventajas:<br />
• Más intuitiva<br />
• Analizador más rápido al evitar reducciones F→Id, T→F<br />
Deshacer la ambigüedad con LR equivale aquí a fijar<br />
externamente la tabla <strong>de</strong> prece<strong>de</strong>ncia con analizador <strong>de</strong><br />
prece<strong>de</strong>ncia
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Conj. LR(0)<br />
• G’<br />
1. E→ E+E<br />
2. E→E * E<br />
3. E→(E)<br />
4. E →Id<br />
5. E’→E<br />
I 0 : [E’→•E]<br />
[E→•E+ E]<br />
[E→•E * E]<br />
[E→• (E)]<br />
[E →•Id]<br />
I 1 : [E’→E•]<br />
[E→E•+ E]<br />
[E→E•* E]<br />
I 2 : [E→(•E)]<br />
[E→•E+ E]<br />
[E→•E * E]<br />
[E→• (E)]<br />
[E →•Id]<br />
I 3 : [E→Id•]<br />
I 4 : [E→E+•E]<br />
[E→•E+ E]<br />
[E→•E * E]<br />
[E→•(E)]<br />
[E→•Id]<br />
I 5 : [E→E *•E]<br />
[E→•E+ E]<br />
[E→•E * E]<br />
[E→•(E)]<br />
[E→•Id]<br />
I 6 : [E→(E •)]<br />
[E→E•+ E]<br />
[E→E• * E]<br />
I 7 : [E→E+E•]<br />
[E→E•+ E]<br />
[E→E• * E]<br />
I 8 : [E→E *E •]<br />
[E→E•+ E]<br />
[E→E•* E]<br />
I 9 : [E→(E) •]<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Conflictos en analizador SLR<br />
Σ N<br />
• G’<br />
1. E→ E+E<br />
2. E→E * E<br />
3. E→(E)<br />
4. E →Id<br />
5. E’→E<br />
Siguiente<br />
S $,+,*,)<br />
I 7 : [E→E+E•]<br />
[E→E•+ E]<br />
[E→E• * E]<br />
I 8 : [E→E*E•]<br />
[E→E•+ E]<br />
[E→E• * E]<br />
acc(7,$)=r1<br />
acc(7,+)=r1<br />
acc(7,*)=r1<br />
acc(7,))=r1<br />
acc(7,+)=d4<br />
acc(7,*)=d5<br />
acc(8,$)=r2<br />
acc(8,+)=r2<br />
acc(8,*)=r2<br />
acc(8,))=r2<br />
acc(8,+)=d4<br />
acc(8,*)=d5
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Tabla SLR sin conflictos<br />
Resolución conflictos (<strong>de</strong>splaz/reducción) sobre<br />
+,*<br />
{+,*} asociativos por la izquierda<br />
“*” más prioridad que “+”<br />
• estado I 7 :<br />
• acc(7,+)=r1 (“+” es asociativo por izda)<br />
• acc(7,*)=d5 (“*” mayor prioridad que “+”)<br />
• estado I 8 :<br />
• acc(8,+)=r2 (“*” mayor prioridad que “+”)<br />
• acc(8,*)=r2 (“*” es asociativo por izda)<br />
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Tabla SLR sin conflictos<br />
acción<br />
ir_a<br />
id + * ( ) $ E<br />
0 d3 d2 1<br />
1 d4 d5 ACP<br />
2 d3 d2 6<br />
3 r4 r4 r4 r4<br />
4 d3 d2 7<br />
5 d3 d2 8<br />
6 d4 d5 d9<br />
7 r1 d5 r1 r1<br />
8 r2 r2 r2 r2<br />
9 r3 r3 r3 r3<br />
G:<br />
1. E→ E+E<br />
2. E→E * E<br />
3. E→(E)<br />
4. E →Id
<strong>Análisis</strong> <strong>Sintáctico</strong>. <strong>Procesadores</strong> <strong>de</strong> <strong>Lenguaje</strong> I<br />
Ejemplo 3ª gramática ambigua<br />
Gramática <strong>de</strong> EQN, editor gráfico <strong>de</strong> ecuaciones:<br />
E::=E·sub·E ·sup·E<br />
E::=E·sub·E<br />
E::=E·sup·E<br />
E::={·E ·}<br />
E::=c<br />
Gramática intencionadamente ambigua por doble motivo:<br />
• “sub” y “sup” tendrán conflictos <strong>de</strong>sp/reducción: se resuelve con<br />
asociatividad (a <strong>de</strong>recha)<br />
• Justificado por simplicidad en la gramática y eficiencia en el análisis<br />
• La primera producción entra en conflicto <strong>de</strong>sp/reducción con la<br />
segunda<br />
• Justificación <strong>de</strong> producción “extra” porque tiene sentido<br />
semántico:<br />
E sub a sup b representa E b , en lugar <strong>de</strong> E<br />
b<br />
a<br />
a