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