Teoría de lenguajes y compiladores Unidad II
Analizador Sintáctico
Semana 8
Análisis Sintáctico Descendente Predictivo
Objetivo General El alumno al finalizar el curso desarrollará aplicaciones que le permitan determinar si una sentencia corresponde a la estructura gramatical de un lenguaje de programación. Así mismo estará capacitado para proponer nuevas formas estructurales en la definición de lenguajes de programación.
Objetivo General El alumno al finalizar el curso desarrollará aplicaciones que le permitan determinar si una sentencia corresponde a la estructura gramatical de un lenguaje de programación. Así mismo estará capacitado para proponer nuevas formas estructurales en la definición de lenguajes de programación.
Objetivo Específico
Desarrollar un analizador sintáctico
Objetivo Instruccional Analizar gramáticas tipo LL(1) para implementar analizadores descendentes predictivos
s o d i n e t n o C
Generalidades Gramáticas LL Análisis Sintáctico Predictivo
ANALIZADOR SINTÁCTICO Sentencias
s Sentencia ; e d a Asignación d i l a r e Variable := Expresión n e + x Variable Expresión G b
Variable c
*
Sentencias
Sentencia Asignación Variable
Expresión Variable
y
:=
Expresión Variable e
ANALISIS SINTACTICO Función: •
Comprobar que la secuencia de tokens cumple con las reglas de la gramática Generar el árbol sintáctico
s • e d Ventajas de utilizar gramáticas: a • Las gramáticas son especificaciones sintácticas y precisas d i l de lenguajes de programación a r • A partir de una gramática se puede generar e un analizador n • automáticamente El proceso de construcción puede llevar a descubrir e G ambigüedades •
•
Una gramática imparte estructura a un lenguaje de programación, siendo mas fácil generar código y detectar errores Es mas fácil de ampliar/modificar el lenguaje si esta descrito con una gramática
TIPOS DE ANALIZADORES SINTACTICOS Descendentes (Top-Down): Parten del axioma y s aplican las reglas de la gramática hasta llegar a e secuencia de símbolos terminales (tokens): d a d • Analizadores LL(1) i l • Analizadores recursivos a r e n Ascendentes (Bottom-Up): Parten de las hojas e G (conjunto de tokens) para llegar a la raíz (axioma de la gramática): • •
Analizadores de Precedencia de Operador Analizadores LR(1)
ANALISIS SINTÁCTICO DESCENDENTE s e d a d i l a r e n e G
• Se basa en gramáticas
LL, que construyen árboles de análisis sintáctico de arriba (raíz) hacia abajo (hojas).
• La
primera “L” significa que la entrada será leída de izquierda a derecha y la segunda “L” indica derivaciones por la izquierda.
ANALISIS SINTÁCTICO DESCENDENTE Algoritmo: el axioma como raíz del árbol de derivación s •• Poner Hasta que solo haya símbolos terminales, derivar mas a la e izquierda d a d i l Ejemplo: a r Entrada: Id * Id + id e Gramática: Expresion::= Expresion * Termino | n Expresion + Termino | e Termino G Termino ::= id | Numero Derivación: Expresion Expresion + Termino Expresion
* Termino + Termino Termino * Termino + Termino Id * Termino + Termino Id * Id + Termino Id * Id + id
PROBLEMAS DE LOS ANALIZADORES SINTÁCTICO DESCENDENTE s e d a d i l a r e n e G
•
Mas de una opción: A ::= a|β
•
Recursividad izquierda
•
Retroceso Analizar los siguientes elementos de entrada
Eliminación de la recursividad
Ambigüedad
Factorización por la izquierda
Para cada producción de la forma: A
α1 | α2 | α3 | … | αn
Siempre debemos ser capaces de elegir la L alternativa correcta para la generación de un árbol L de análisis sintáctico.
s a c Para cumplir esta regla necesitamos información adicional, a i t saber: á m • El conjunto de todos los símbolos terminales que pueden a r aparecer al principio de una frase que puede derivarse de una secuencia arbitraria de símbolos (CONJUNTO G PRIMERO).
•
El conjunto de todos los símbolos terminales que pueden aparecer después de uno no terminal (CONJUNTO SIGUIENTE).
CONJUNTO PRIMERO(1/3) Sea G(N,T,P,S) una gramática y decir α Є (NUT)*, entonces;
α
Primero(α) = { t / t Є TЄ ^ α
secuencia arbitraria de símbolos, es t α„ } , donde T Є = T U { Є }
L Para calcular Primero(X) para todos los símbolos gramaticales X, L aplíquense las reglas siguientes hasta que no se puedan añadir mas s terminales o Є a ningún conjunto Primero. a 1. Si X es terminal, entonces primero(X) es {X} c 2. Si X Є es una producción, entonces añádase Є a Primero(X) i t á 3. a. Si X es no terminal y X Y1 Y2 … Yk , es una producción, entonces póngase “a” en Primero(X) si para alguna i, “a” esta en Primero(Yi) m y Є esta en todos los Primero(Y1)…Primero(Y i-1) ; es decir Y1..Yi-1 Є a r G b. Si Є esta en primero(Yi) para toda i = 1,2,…,k, entonces añádase Є a primero(X).
Por ejemplo, todo lo que esta en Primero(Y 1) sin duda esta en
Primero(X). Si Y1 no deriva a Є, entonces no se añade nada más a Primero(X). Pero si Y1 Є, entonces se le añade Primero(Y2), y así sucesivamente.
CONJUNTO PRIMERO(2/3) Ahora se puede calcular el conjunto Primero para cualquier cadena X1X2…Xn de la siguiente forma: L L s a c i t á m a r G
añádase a Primero(X1X2…Xn) todos los símbolos distintos de Є de Primero(X1). Si Є esta en Primero(X1), añádase también los símbolos distintos de Є de Primero(X2); si Є esta tanto en Primero(X1) y Primero(X2) añádanse también los símbolos distintos de Є de Primero(X3) y así sucesivamente. Por ultimo añádase Є a Primero (X1X2…Xn) si para
todo i=1..n, Primero(Xi) contiene al Є.
CONJUNTO PRIMERO(3/3) Ejemplo: L L s a c i t á m a r G
Considérese la gramática siguiente: E
F
(
TE’ E’ +TE’ | Є T F T’ T’ *F T’ | Є
E ) | id
Entonces :
Primero(E) = { ( , id } Primero(E’) = { + , Є } Primero(T) = { ( , id } Primero(T’) = { * , Є } Primero(F) = { ( , id }
CONJUNTO SIGUIENTE(1/2) Sea G(N,T,P,S) una gramática y secuencia arbitraria de símbolos, es decir Є (NUT)*, entonces; Siguiente(X) = { t / t Є TЄ ^ S
α X t β}
L L Para calcular Siguiente(A) para todos los no terminales A, s aplíquense las reglas siguientes hasta que no se pueda añadir a nada mas a ningún conjunto siguiente: c i t á 1. Póngase $ en Siguiente(S) , donde S es el símbolo inicial y $ es m el delimitador derecho de la entrada. a r G 2. Si hay una producción A α B β, entonces todo lo que este en Primero(β) excepto Є se pone en Siguiente(B).
3. Si hay una producción A α B o una producción A α B β donde Primero(β) contenga Є ( es decir β Є), entonces todo lo que este en Siguiente(A) se pone en Siguiente(B).
CONJUNTO SIGUIENTE(2/2) Ejemplo:
Considerando la gramática anterior: E TE’ Se determinó que: E’ +TE’ | Є Primero(E) = { ( , id } T F T’ Primero(E’) = { + , Є } L T’ *F T’ | Є Primero(T) = { ( , id } L s F ( E ) | id Primero(T’) = { * , Є } a Primero(F) = { ( , id } c
i t Entonces: á Siguiente(E) = { $ , ) } m a r Siguiente(E‟) = { ) , $ } G
Regla 1 Regla 2 aplicada a F
(E)
Regla 3 aplicada a E
T E‟
Siguiente(T) = { + , ) , $ }
Regla 2 aplicada a E Regla 3 aplicada a E‟
TE‟ +TE‟
Siguiente(T‟) = { + , ) , $ }
Regla 3 aplicada a T
F T‟
Siguiente(F) = { * , + , ) , $ } Regla 2 aplicada a T
FT‟
GRAMÁTICAS LL(1) Una gramática independiente del contexto G(N,T,P,S) se denomina gramática LL(1) si tiene las siguientes características:
C1) Para las producciones de la forma: A α1 | α2 | α3 | … | αn L se requiere: Primero(αi) ∩ Primero(α j) = Ø Para todo i <> j L
s a C2) si puede derivarse la cadena vacía (Є) de un símbolo no c i terminal X, se requiere que: Primero(X) ∩ Siguiente(X) = Ø t á m“Una gramática cuya tabla de análisis sintáctico no tiene a r entradas con definiciones múltiples se define como LL(1)”. G
Queda la cuestión de lo que se debe hacer cuando la tabla de análisis sintáctico tiene entradas con múltiples definiciones. Un recurso es transformar la gramática eliminando la recursión por la izquierda y factorizando por la izquierda siempre que sea posible, con la esperanza de producir una gramática para la cual la tabla de análisis sintáctico no tenga entradas con múltiples
Ejemplo:
GRAMÁTICAS LL(1)
Considerar una gramática que permita la generación de frases como: program declaracion; declaracion; begin proposicion; p = programa proposicion; d = declaracion b = begin proposicion; s = proposicion end. e = end
L L s a c i t á m a r G La gramática G viene dada por: T={b,d,e,p,s,;,.} N={A,X,Y} P = { A pX X d ; X | bsYe Y ; sY |Є
GRAMÁTICAS LL(1) Solución:
Primero(A) = { p } Primero(X) = { d , b }
Siguiente(A) = { $ } Siguiente(X) = { $ }
Primero(Y) = { Є , ; } Siguiente(Y) = { e , $ } Luego: Por C1) Primero(d;X) ∩ Primero(bsYe) = { d } ∩ { b } = Ø Primero(Є) ∩ Primero(;sY) = { Є } ∩ { ; } = Ø
L L s a c Por C2) Primero(Y) ∩ Siguiente(Y) = { Є , ; } ∩ { Є } = Ø i t á mEntonces a partir de la definición de LL(1) se concluye que esta a r gramática es no ambigua y nunca puede ser recursiva izquierda. G
Esto es obvio ya que una gramática G es ambigua si hay una palabra en L(G) que posea 2 derivaciones por la izquierda (a partir del símbolo inicial). EN CONCLUSION:
Las gramáticas LL(1) se usan preferentemente para el análisis
CONSTRUCCIÓN DE TABLAS LL(1) r a Sea G una gramática ; supóngase que A α , es una producción con l u “a” en Primero(α). Entonces, el analizador sintáctico expandirá A por α b cuando el símbolo actual de entrada sea “a”. a T Algoritmo: Construcción de una tabla de análisis sintáctico predictivo o c Entrada: Una gramática G i t c Salida: La tabla de análisis sintáctico M á t Método: n i S 1. Para cada producción A ϒ de la gramática dense los pasos 2 y 3. s 2. Para cada terminal “a” de primero(ϒ ) , añádase A ϒ a M[A,a] i s 3. a. Si Є esta en Primero(ϒ), añádase A ϒ a M[A,b] para cada i l á terminal b de Siguiente(A). n b. Si Є esta en Primero(ϒ ) y $ esta en Siguiente(A), añádase A ϒ A a M[A,$] 4. Hágase que cada entrada no definida de M sea error.
CONSTRUCCIÓN DE TABLAS LL(1) r a l u Del ejemplo anterior, para: E b a T No o Terminal id + c i t c E T E’ E á t n i E’ S s i s i T l á n T’ A F
TE‟ Símbolo de entrada *
( E
T E’
)
$
CONSTRUCCIÓN DE TABLAS LL(1) r a l u Del ejemplo anterior, para: E‟ b a T No o Terminal id + c i t c E T E’ E á t n i E’ +TE’ E’ S s i s i T l á n T’ A F
+TE‟ Símbolo de entrada *
( E T E’
)
$
CONSTRUCCIÓN DE TABLAS LL(1) r a l u Del ejemplo anterior, para: E‟ b a T No o Terminal id + c i t c E T E’ E á t n i E’ +TE’ E’ S s i s i T l á n T’ A F
Є Símbolo de entrada *
(
)
$
E T E’ E’
Є
E’
Є
CONSTRUCCIÓN DE TABLAS LL(1) r a l u Del ejemplo anterior, para: T b a T No o Terminal id + c i t c E T E’ E á t n i E’ +TE’ E’ S s i s F T’ T i T l á n T’ A F
F T‟ Símbolo de entrada *
(
)
$
E T E’ E’ Є T
F T’
E’ Є
CONSTRUCCIÓN DE TABLAS LL(1) r a l *F T‟ u Del ejemplo anterior, para: T‟ b a Símbolo de entrada T No o Terminal id + * ( ) c i t c E T E’ E T E’ E á t n i E’ +TE’ E’ E’ Є S s i s T F T’ T F T’ i T l á n T’ *FT’ T’ A F
$
E’ Є
CONSTRUCCIÓN DE TABLAS LL(1) r a l Є u Del ejemplo anterior, para: T‟ b a Símbolo de entrada T No o Terminal id + * ( ) c i t c E T E’ E T E’ E á t n i E’ +TE’ E’ E’ Є S s i s T F T’ T F T’ i T l á n T’ *FT’ T’ T’ Є T’ Є A F
$
E’ Є
T’
Є
CONSTRUCCIÓN DE TABLAS LL(1) r a l (E) u Del ejemplo anterior, para: F b a Símbolo de entrada T No o Terminal id + * ( ) c i t c E T E’ E T E’ E á t n i E’ +TE’ E’ E’ Є S s i s T F T’ T F T’ i T l á n T’ *FT’ T’ T’ Є T’ Є A F
F
(E)
$
E’ Є
T’ Є
CONSTRUCCIÓN DE TABLAS LL(1) r a l id u Del ejemplo anterior, para: F b a Símbolo de entrada T No o Terminal id + * ( ) c i t c E T E’ E T E’ E á t n i E’ +TE’ E’ E’ Є S s i s T F T’ T F T’ i T l á n T’ *FT’ T’ T’ Є T’ Є A F
F
id
F ( E )
$
E’ Є
T’ Є
CONSTRUCCIÓN DE TABLAS LL(1) r a l u b a T o c i t c á t n i S s i s i l á n A
TABLA FINAL Símbolo de entrada No Terminal
id
+
*
(
)
$
E
E T E’
Error
Error
E T E’
Error
Error
E’
Error
E’ +TE’
Error
Error
E’ Є
E’ Є
T
T F T’
Error
Error
T F T’
Error
Error
T’
Error
T’ Є
T’ *FT’
Error
T’ Є
T’ Є
F
F id
Error
Error
F ( E )
Error
Error
ALGORITMO RECURSIVO GUIADO POR TABLA (1/2)
r Algoritmo: a Entrada: Una cadena W y una tabla de análisis sintáctico M para la gramática G l u Salida: Si W esta en L(G) , una derivación por la izquierda de W; de lo contrario una indicación de error. b a T Al principio, el analizador sintáctico esta en una configuración en la que tiene a o $S en la pila S, el símbolo inicial de G en el tope y W$ en el buffer de entrada. c i t 1. Apuntar ptr al primer símbolo de W$ c 2. Repetir Sea X el símbolo de la cima de la pila y a el símbolo apuntado por ptr á t Si X es un terminal o $ entonces n i Si X = a entonces S Extraer X de la pila y avanzar ptr s Caso contrario i s “Error” i l Caso contrario á Si M[X,a] = X Y1Y2…Yk entonces n Extraer X de la pila A Meter Yk ,Yk-1,…,Y1 en la pila con Y1 en la cima Emitir la producción X Caso contrario
Y1Y2…Yk
“Error “
Hasta X = $ /* la pila esta vacía */
r a l u b a T o c i t c á t n i S s i s i l á n A
ALGORITMO RECURSIVO GUIADO POR TABLA (2/2) Ejemplo: Analizar si: id + id * id es valida para la gramática anteriormente presentada. PILA
$E $E’T $E’T’F $E’T’id $E’T’ $E’ $E’T+ $E’T $E’T’F $E’T’id $E’T’ $E’T’F* $E’T’F $E’T’id $E’T’ $E’
$
ENTRADA
id + id * id $ id + id * id $ id + id * id $ id + id * id $ + id * id $ + id * id $ + id * id $ id * id $ id * id $ id * id $ * id $ * id $ id $ id $ $ $ $
SALIDA
E TE’ T FT’ F id T’ Є E’ +TE’
T FT’ F id T’ *FT’
F id T’ Є