04.03.2015 Views

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

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!