Está en la página 1de 31

Análisis Sintáctico

Manejo de errores sintácticos y su


recuperación
• Si los traductores tuvieran que procesar
programas correctas el proceso de
implantación se simplificaría mucho.

• ¿Cómo debe de responder un compilador de


pascal a un código Fortran?

• Ningún método de recuperación de errores


resuelve todos los problemas
Tipos de Errores
• Léxicos: como escribir mal un identificador,
palabra clave u operador.

• Sintácticos: como una expresión aritmética con


paréntesis no equilibrados.

• Semánticos: como un operador aplicado a un


operando incompatible.

• Lógicos: como una llamada infinitamente


recursiva.
Tipos de Errores
• La mayoría de los errores se centra en la fase
de análisis sintáctico.

• El manejador de errores debe:

• Informar la presencia de errores con claridad y


exactitud.

• Brindar una posible solución al problema.


Administrador de Errores
• Recuperar de cada error con la suficiente
rapidez como para detectar errores posibles.

• No debe retrasar de manera significativa el


procesamiento de programas correctos.

• Debe indicar la línea del error y algún mensaje


informativo
Estrategia de Recuperación de
Errores

• Modo Pánico

• Nivel de Frase

• Producciones de error

• Corrección global
Recuperación en Modo Pánico
• Es el más sencillo de implantar.

• El analizador sintáctico desecha componentes


léxicos hasta encontrar un carácter de
sincronización. Estos caracteres son el punto y
como (;) entre otros.

• En C/Java es muy común este tipo de errores.


Recuperación en Modo Pánico
int a.b,c;
struct c
{
….
}

main() {
int a;
}
Recuperación a nivel de frase
• Esta técnica utiliza una corrección de
caracteres adyacentes, ya sea por inserción,
eliminación o intercambio.

• Esta técnica permite sustituir “,” por “;”, etc. Son


traductores que corrigen errores.

• Desafortunadamente para muchos casos no


aplican por lo que no se utilizan demasiados.
Producción de Errores
• Se pueden generar gramáticas para generar
producciones de error y así de esta forma
seguir con el proceso.

• La dificultad radica en el sentido de encontrar


esas reglas gramaticales para generar error. En
algunos casos sería inclusiva más extensa que
la gramática del propio lenguaje.

• for(i<3, a<10; i++)


Corrección Global
• Idealmente, sería recomendable que un
traductor hiciera el mínimo de cambios para
procesar una entrada inválida. Este algoritmo
genera menores costos globales para realizar
cambios.

• El problema radica en que el implementar estas


estrategias son muy costosas en tiempo y
espacio.
Generadores de Analizadores
Sintácticos: YACC & Bison

• YACC (YET ANOTHER COMPILER-


COMPILER): es una herramienta que nos
permite validar lenguajes a través de la
especificación de reglas gramaticales.

• Esta fuertemente relacionado con Lex para la


identificación de caracteres extraños.
YACC
• La forma de trabajar con yacc es la siguiente:

• Analizador.y (#include“lex.yy.c”)  bison 


analizador.c (y.tab.c)  gcc analizador

• $gcc analizador.c –o analizador –lfl

• Se necesita modificar el valor de retorno en el


analizador léxico para trabajar de manera
conjunta.
Estructura de un programa en
YACC/BISON
%{
Declaraciones globales C
}%
Declaraciones bison

%%
Gramáticas Nombre:prod1|prod2|…|prodn;

%%
Código auxiliar C
Consejos
• Todo lexema debe ser un entero:
• #define VAR 200 (256)
• return (VAR);

• Gramática vacía: prod1| prod2| ;

• Es sumamente sensible a los separadores.


Consejos
• Yacc no es una herramienta que se caracterice
por optimizar gramáticas. Por lo tanto, se
pueden presentar algunos problemas de
ambigüedad:

• Reduce/Reduceambigüedad infinita
• Shift/Reduce

• A continuación se muestran algunos ejemplos


de Yacc.
Analizador.lex
%{
#include“ytab.h”
}%
sp [\n\r\t]
if [i][f]
%%
{if} {return(IF);}
“(” {return(PI); }
. return(ERROR);
%%
ytab.h
• /*Se deben colocar todos los tokens*/
• #define IF 1
• #define
Analizador.y
• %{
• #include“lex.yy.c”
• }%
• %token IF PI PD LLI LLD
• %token ID NUM OPREL OPLOG
• %%
• programa: linea programa | ;
• Linea: iflinea | ;
• if: ifPI condicionPD LLI campo LLD ;
Analizador.y
• .: {printf(“Error sintáctico”);}

• %%
• main(intargc, char*argv[]) {
• FILE *f = fopen(argv[1], “r”);
• yyin= f;
• while(yyparse());
• fclose(f); }
Compilación con Yacc
• $flexanalizador.lex

• $bisonanalizador.y

• $gccanalizador.c –o analizador –lfl

• yytextcomponente léxico
• yyinflujo de entrada
• yylinenolínea de error
Manejo de errores con Yacc
• %% yyerror() {
• printf(“Error sintáctico en %dlinea”, yylineno);
• }

• En general, el manejo de errores se realiza de


forma trivial. De lo contrario tendría que ser
más específico.
CUP
• Es el generador de analizadores sintácticos
más populares para Java.

• Al igual que con lex, los archivos de JLEX


deben de modificarse para poder trabajar en
conjunto.

• Se deben devolver valores de la clase sym,


además de incluir la biblioteca de cup. A
continuación se muestra un ejemplo de un
analizador sintáctico de expresiones.
CUP
import java_cup.runtime.SymbolFactory;
%%
%cup
%class Scanner
%{
public Scanner(java.io.InputStream r,
SymbolFactory sf){
this(r);
this.sf=sf;
}
CUP
private SymbolFactory sf;
%}
%eofval{
return sf.newSymbol("EOF",sym.EOF);
%eofval}
%%
";" { return
sf.newSymbol("Semicolon",sym.SEMI); }
"+" { return sf.newSymbol("Plus",sym.PLUS); }
"*" { return
CUP
sf.newSymbol("Times",sym.TIMES); }
"(" { return sf.newSymbol("Left
Bracket",sym.LPAREN); }
")" { return sf.newSymbol("Right
Bracket",sym.RPAREN); }
[0-9]+ { return sf.newSymbol("Integral
Number",sym.NUMBER, new Integer(yytext()));
}
[ \t\r\n\f] { /* ignore white space. */ }
. { System.err.println("Illegal character:
"+yytext()); }
CUP
• En cup se definen las gramáticas en una
sintaxis muy similar a BNF.

• El archivo define algunas secciones para


código auxiliar y definición de terminales y no
terminales.

• Para compilar se debe de incluir en el path la


ruta de la biblioteca de cup. El archivo
generado por cup se denomina parser.java y
sym.java que se compilan con el lexer.java
CUP
import java_cup.runtime.*;
parser code {:
public static void main(String args[]) throws
Exception {
SymbolFactory sf = new
DefaultSymbolFactory();
if (args.length==0) new parser(new
Scanner(System.in,sf),sf).parse();
else new parser(new Scanner(new
java.io.FileInputStream(args[0]),sf),sf).parse();
CUP
• }
• :}

• terminal SEMI, PLUS, TIMES, LPAREN,


RPAREN;
• terminal Integer NUMBER;
• non terminal expr_list, expr_part;
• non terminal Integer expr;
• precedence left PLUS;
• precedence left TIMES;
CUP
expr_list ::= expr_list expr_part | expr_part;
expr_part ::= expr:e {: System.out.println(" =
"+e+";"); :} SEMI;
expr ::= NUMBER:n
{: RESULT=n; :}
| expr:l PLUS expr:r
{: RESULT=new Integer(l.intValue() +
r.intValue()); :}
| expr:l TIMES expr:r
{: RESULT=new Integer(l.intValue()
CUP
* r.intValue()); :}
| LPAREN expr:e RPAREN
{: RESULT=e; :}
;

También podría gustarte