UNIDAD IV Analisis Sintactico
4.1
Introduccion Sintaxis significa “estructura del orden de las palabras en una fras e”. La tarea del analisis sintactico es revisar si los símbolos aparecen en el orden correcto ( es decir, revisar si el programa programa fuente fue disenado de acuerdo con la sintaxis del lenguaje de programación ) y combinar los símbolos del codigo fuente para formar unidades gramaticales. En general las unidades gramaticales se representan en forma de arboles sintacticos. El analisis sintactico es la fase que se encarga de verificar la secuencia de tokens que representa al texto de entrada, en base a una gramática dada. En caso de que el programa de entrada sea valido, suministra el árbol sintáctico que lo reconoce en base a una representación computacional. Ese árbol es el punto de partida de la fase posterior de la etapa de análisis: el analizador semantico. Pero esto es la teoría; en la práctica, el analizador sintáctico dirige el proceso de compilación, de manera que el resto de fases evolucionan a medida que el sintáctico va reconociendo la secuencia de entrada por lo que, a menudo, el árbol ni siquiera se genera realmente. En la práctica, el analizador sintáctico también: • Incorpora acciones semánticas en las que colocar el resto de fases del compilador (excepto el analizador léxico): desde el análisis semántico hasta la generación de código. • Informa de la naturaleza de los errores sintácticos que encuentra e intenta recuperarse de ellos para continuar la compilación. • Controla el flujo de tokens reconocidos por parte del analizador léxico.
4.2
Introduccion a las gramaticas libres de contexto y arboles de derivacion derivacion Existen aspectos dentro de los lenguajes que no se pueden describir mediante gramáticas regulares y ó expresiones regulares, como son los aspectos de bloque BEGIN-END, las expresiones aritméticas (anidadas) y las estructuras IF-THEN-ELSE, DO WHILE ETC. Para poder describir dichas estructuras estructuras se hace uso uso de las gramáticas libres de contexto o gramáticas Tipo 2. Las gramáticas tipo 2 son un conjunto de variables llamadas no terminales o variables sintácticas. sintácticas. A las reglas que relacionan los simbolos terminales a estas variables sintacticas se les llaman producciones. Formalmente, una gramatica Tipo 2 o gramática libre de contexto las producciones las producciones son de tipo α β donde: | α | <= | β | Pag. 1
además α
Vn y | α |=1
ε
El lenguaje producido es un lenguaje libre de contexto. Ejemplo: G = Vn = { E } Vt = { +, *, ( , ) , id } P = { EE+E EE*E E(E) E id } S=E
4.3
Tipos de Parser Recursivo con retroceso ( backtrack ) Parser Descendente
- Recursivo Predictivo - No Recursivo
-LR
Parser Ascendente
Desplazamiento Reduccion - Por precedencia de operadores
1.6.1 Parser Descendente ( Top – Down ) La construcción del arbol de análisis sintáctico para la entrada se comienza desde la raiz y se crean los nodos del arbol hasta llegar a las hojas. La construccion descendente de un arbol de análisis sintáctico se hace siempre empezando por la raiz etiquetada con el símbolo inicial.
Pag. 2
1.6.2 Parser Ascendente ( Bottom - Up ) Construye el arbol sintactico para una cadena de entrada empezando por las hojas y avanzando hacia la raiz. Se puede considerar este proceso como de “reducir ” una cadena W al símbolo inicial de la gramatica.
4.4
Parser de Descenso Recursivo con Retroceso
4.5
Parser Predictivo Recursivo Este método de análisis descendente utiliza el símbolo de preanalisis para determinar sin ambigüedad la producción correcta para cada símbolo No-Terminal. Consta de un conjunto de procedimiento o rutinas recursivas para procesar la entrada. A cada No-Terminal de la gramática se le asocia un procedimiento. La secuencia de llamadas a procedimientos define implícitamente un árbol de análisis sintactico de la entrada.
1) 2) 3)
La implementación del procedimiento de una producción se realiza co mo la siguiente: Cada terminal del lado derecho se “empareja” con el símbolo de preanalisis Cada no terminal de la derecha proporciona una llamada a su procedimento. El procedimiento “emparejar ” recibe un argumento t el cual si concuerda con el símbolo de preanalisis entonces avanza hacia el siguiente componente lexico de entrada.
Ejemplo: Diseñar el algoritmo de parser predicti vo recursivo de la gramatica cuya producciones son: tipo-> simple | ↑ id | array [ simple ] of tipo simple -> integer | char | num puntopunto num
calculamos : PRIMEROS ( tipo ) PRIMEROS ( simple )
= { PRIMEROS ( simple ), ↑ , array} = { integer, char, num }
Procedure tipo begin If preanalisis IN { „integer ‟, „char ‟, „num‟ } then simple Else If preanalisis = „↑ ‟ then begin emparejar ( „↑’ ); emparejar ( „id‟ ); end Else If preanalisis = „array‟ then begin emparejar ( „array’ ); emparejar ( „[‟ ); simple; emparejar ( „]’ ); Pag. 3
emparejar ( „of ‟ ); tipo; end Else error ; end; Procedure simple begin If preanalisis = „integer ‟ then emparejar ( „interger ‟ ) Else If preanalisis = „char ‟ then emparejar ( „char ‟ ) Else If preanalisis = ‟num‟ then begin emparejar ( „num‟ ); emparejar ( „ puntopunto‟ ); emparejar ( „num‟ ); end Else error; end;
Procedure emparejar ( t : complex ) begin If preanalisis = t then Preanalisis := sigcomplex Else error ; end;
4.6
Parser Predictivo No Recursivo
Pag. 4
Buffer de entrada Pila X Y Z $
a +b $
Programa para análisis Sintáctico predictivo
Salida
Tabla de análisis Fig. Modelo de un parser predictivo no recursivo
La tabla M es de la forma M[X, a] donde X= No Terminal, a= terminal X = Símbolo en la cima de la pila a = Símbolo en curso de la entrada (preanalisis) Tres casos; 1. 2. 3.
Si X = a = $; Fin, éxito del analisis. Si X = a != $; Sacar X de la pila y mover el apuntador de la entrada al siguiente símbolo. Si X es no terminal consultar M[X, a]: Si M [X,a] = {XUVM} entonces sustituir X de la pila por MVU (U hasta arriba de la pila). Si M [X,a] = error el parser invoca al manejador de errores.
Inicialmente se tiene $S en la pila, con S ( símbolo inicial ) en el tope de la pila. Ademas una cadena a analizar w a la que se le anexa $ al final.
Pag. 5
Algoritmo Parser Predictivo No Recursivo Apuntar ae al primer símbolo de w$; ( ae = apuntador de entrada ) Repeat Sea X el símbolo en el tope de la pila y a el símbolo apuntado por ae ; Si X es terminal o „$‟ entonces Si X = a entonces Saca X de la pila y avanzar ae Sino Error () Sino /* X es un no terminal */ Si M [ X, a ] = X y1 y2….yk entonces Extraer X de la pila Meter yk, yk-1, yk-2, …. y1 en la pila con y1 en la cima. Emitir la producción X y1,y2….yk Sino Error () Hasta X = „$‟ /*pila vacía*/
Ejemplo: considere la siguiente tabla gramatical M para analizar la entrada id + id * id
No terminal Id
E E‟ T T‟ F 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‟ $
E
Símbolo de entrada * ( E TE‟
+
TE‟ E‟ +TE‟
)
$
E‟ vacio E‟vacio
T FT‟
T FT‟ T‟
vacio
T‟
F id
*FT‟
T‟vacio
T‟vacio
F (E) ENTRADA
SALIDA 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 $ $ $ $
ETE ‟ TFT‟ F id T‟ε E‟+TE‟ TFT‟ Fid T‟*FT‟ Fid T‟ε
E‟ε
Ejercicio: Con la misma tabla M anterior analizar sintacticamente la entrada id * ( id + id )
Pag. 6
4.7
Parser Corrimiento - Reduccion Se pueden considerar este proceso como de “reducir ” una cadena W al símbolo inicial de la gramática. En cada paso de reducción se sustituye una subcadena determinada para que concuerde con el lado derecho de la producción por el símbolo del lado izquierdo de dicha producción. Y si en cada paso se elige correctamente la subcadena, se traza una derivación por la derecha en sentido inverso. Ejemplo: considere la gramatica
SaABe AAbc A b Bd La frase abbcde se puede reducir a S. Se examina abbcde buscando una subcadena que concuerde con el lado derecho de una pr oducción: Elegimos la b que se sitúa mas a la izquierda y se sustituye en este caso por A del lado izquierdo de la producción A b y se obtiene la cadena aAbcde y asi sucesivamente. El árbol sintáctico ascendente quedaría:
b a A
e
c A
4.8
d
b
B
Parser L - R Es un parse ascendente L significa que analiza la entrada empezando por la izquierda R significa que las derivaciones son por la derecha
Pag. 7
Entrada
a1
ai
…
…
an
$
Sm Programa de análisis Sintáctico L-R
Xm
Salida
Sm-1 Xm-1
… acción
IR-A Tabla de análisis Sintáctico
Algoritmo Parser L-R Entrada: Salida: Método:
cadena W, tabla de análisis sintáctico para la gramática G. si W esta en L(G), un análisis ascendente de W sino error. Inicialmente s0 esta en la pila y W $ en la entrada
Apuntar ae al primer símbolo de la entrada; Repetir por simpre Begin Sea s el estado en la cima de la pila y a el símbolo apuntado por ae; IF accion [ s, a ] = desplazar s THEN Begin Meter a y despues s‟ en la cima de la pila; Avanzar ae; End Else IF accion [ s, a ] = reducir Aβ THEN Begin Sacar 2* | β | simbolos de la pila; Sea s‟ el estado que esta ahora en la cima; Meter A y después ir_a [ s , A ] en la cima ; Desplegar la producción A β; End Else IF accion [ s, a ] = aceptar THEN Return Else Error() End ’
’
Pag. 8
Ejemplo: considere la siguiente gramática para expresiones numéricas con + y *
EE + T ET TT * F TF F( E ) Fid
ESTADO id
0 1 2 3 4 5 6 7 8 9 10 11
+
D5 D6 R2 R4 D5 R6 D5 D5 D6 R1 R3 R5 Simbología:
TABLA DE ANALISIS SINTACTICO ACCION * ( ) $ D4 Acepta D7 R2 R2 R4 R4 R4 D4 R6 R6 R6 D4 D4 D11 D7 R1 R1 R3 R3 R3 R5 R5 R5
E
Ir-a T
F
1
2
3
8
2
3
9
3 10
Di = Desplazar y meter en la pila el estado i . Rj = Reducir por la producción j. Celda en blanco significa error.
Analizar la entrada id * id + id Buffer De entrada: Id *
Id
+
Id
$
Salida: Fid TF Fid TT*F ET Fid TF EE+T
Pag. 9
El arbol sintactico equivalente es :
E E
+
F
T T
*
T
id
F id
F id
4.9
Manejo de errores sintacticos Libro: Capitulo: Tema:
Compiladores. Conceptos fundamentales 6 6.4 Manejo de errores en el analisis sintactico, pag. 124 - 125
Pag. 10