Está en la página 1de 5

Analizadores descendentes deterministas:

En éste analizador las entradas son de izquierda a derecha, y construcciones de


derivaciones por la izquierda de una sentencia o enunciado. El análisis sintáctico
descendente es una técnica de análisis sintáctico que intenta comprobar si una
cadena x pertenece al lenguaje definido por una gramática L (G) aplicando los
siguientes criterios.
 Partir del axioma de la gramática.
 Escoger reglas gramaticales estratégicamente.
 Hacer derivaciones por la izquierda (Left Most Derivation).
 Procesar la entrada de izquierda a derecha.
 Obtener el árbol de análisis sintáctico o error.

Características
 El análisis sintáctico descendente (ASD)intenta encontrar entre las
producciones de la gramática la derivación por la izquierda del símbolo
inicial para una cadena de entrada.
 Parte del axioma de la gramática.
 Procesa la entrada de izquierda a derecha.
 Escoge reglas gramaticales.

Bueno primeramente para trabajar el análisis sintáctico descendente se debe


realizar primeramente algunas operaciones para que la gramática sea LL1 las
cuales son:

Eliminar Ambigüedad: Para eliminar la ambigüedad se debe reescribir la


gramática.

Eliminar Recursividad por la Izquierda: Una gramática es recursiva por la


izquierda si tiene un nodo Terminal a tal que existe una derivación A->Aα para
alguna cadena. Es decir, por simple observación podemos identificar.

Para eliminar la recursividad por la izquierda se utiliza la siguiente formula.


Factorizar: Se trata de rescribir las producciones de la gramática con igual
comienzo para retrasar la decisión hasta haber visto lo suficiente de la entrada como
para elegir la opción correcta.

primeros y siguientes.

Ejemplo:

Análisis sintáctico descendente con retroceso:


El método parte del axioma inicial y aplica todas las posibles reglas al no terminal más a la
izquierda.
 Se usa el retroceso para resolver la incertidumbre.
 sencillo de implementar.
 Muy eficiente.

Ejemplo:

Análisis sintáctico descendente predictivo (ASDP):


El analizador debe realizar la previsión de la regla a aplicar sólo con ver el primer
símbolo que produce para que el algoritmo tenga una complejidad lineal.
Las gramáticas que son susceptibles de ser analizadas sintácticamente de forma
descendente mediante un análisis predictivo y consultando un únicamente
un símbolo de entrada pertenecen al grupo LL (1).
A partir de gramáticas LL (1) se pueden construir analizadores sintácticos
descendentes predictivos (ASDP), que son ASD sin retroceso.

ANÁLISIS SINTÁCTICO ASCENDENTE


El objetivo de un análisis ascendente consiste en construir el árbol sintáctico desde
abajo hacia arriba, esto es, desde los tokens hacia el axioma inicial, lo cual
disminuye el número de reglas mal aplicadas con respecto al caso descendente (si
hablamos del caso con retroceso) o amplia el número de gramáticas susceptibles
de ser analizadas (si hablamos del caso LL (1)).

Análisis ascendente con retroceso


Al igual que ocurría con el caso descendente, este tipo de análisis intenta probar
todas las posibles operaciones (reducciones y desplazamientos) mediante un
método de fuerza bruta, hasta llegar al árbol sintáctico, o bien agotar todas las
opciones, en cuyo caso la cadena se rechaza.
En el análisis con retroceso no se permiten las reglas ԑ, puesto que estas se podrán
aplicar de forma indefinida.

Análisis Ascendente sin Retroceso


 El análisis ascendente sin retroceso busca una derivación derecha de la
cadena de entrada de forma determinista.
 Este se sustenta en su aplicación a las gramáticas LR(K).
 La L viene de la lectura de la cadena de entrada de izquierda a derecha.
 La R de producir un árbol de derivación derecho.
 La k indica el número de símbolos que es necesario leer a la entrada para
tomar la decisión de qué producción emplear.
 Un parser del tipo shift-reduce puede verse como un autómata de pila
determinista extendido que realiza el análisis de abajo hacia arriba.
 Dada una cadena de entrada w, simula una derivación más a la derecha.

Funcionamiento de yacc
Igual que sucedía con lex, yacc no es directamente un analizador sino un generador
de analizadores. A partir de un fichero fuente en yacc, se genera un fichero fuente
en C que contiene el analizador sintáctico. Sin embargo, un analizador sintáctico de
yacc no puede funcionar por sí solo, sino que necesita un analizador léxico externo
para funcionar. Dicho de otra manera, el fuente en C que genera yacc contiene
llamadas a una función yylex() que debe estar definida y debe devolver el tipo de
lexema encontrado. Además, es necesario incorporar también una función yyerror(),
que será invocada cuando el analizador sintáctico encuentre un símbolo que no
encaja en la gramática.

Esquema del lenguaje yacc:


Un programa fuente de Yacc se parece bastante a uno de lex. La diferencia principal
está en la sección de reglas, que en vez de expresiones regulares contiene las
reglas de la gramática:

Código en c en un programa lex:


Igual que en lex, muchas veces es útil incluir código en C dentro de un programa en
yacc. Es normal utilizar esta posibilidad para incluir las funciones main() e yyerror()
en el mismo fichero. La función yylex(), sin embargo, suele proporcionarse en un
módulo aparte, generado por lex, que se enlaza en la fase final de la compilación.
Normalmente, el código C se introduce en la sección de declaraciones, o bien en la
de rutinas:
 En la sección de declaraciones, entre una línea %{ y una línea %} (nótese
que no es }%). Este código será externo y se situará antes de la función
yyparse() en el fichero y.tab.c.
 En la sección de rutinas todo lo que haya debe ser código C, que será externo
y posterior a la función yyparse().

Ejemplo:
%token H,O,L,A hola: H letra_o L A
%{ {printf("La expresión
#define H 257 introducida es parte del
#define O 258 lenguaje reconocido\n");}
#define L 259 letra_o: O |
#define A 260 letra_o O ;
int yylex() { %%
char carac=getchar(); int main() {
switch(carac) { yyparse();
case 'H': return 0;
case 'h': }
return H;
case 'O':
case 'o':
return O;
case 'L':
case 'l':
return L;
case 'A':
case 'a':
return A;
}
return -1;
}
int yyerror() {
printf("La expresión de la
entrada NO forma parte del
lenguaje reconocido\n");
return 0;
}
%}
%%

También podría gustarte