Capítulo 9. Tratamiento de errores
Hay dos conceptos fundamentales:
- Corrección de errores: exige que el programa pueda ejecutarse. Suele
utilizarse en sistemas que generán .EXE directamente, pues ahorra tiempo
(permite encontrar errores de ejecución a la vez que los de compilación).
- Recuperación de errores: sólo trata de evitar que el número de mensajes de
error sea demasiado grande y que el compilador/intérprete pueda seguir
ejecutándose correctamente en instrucciones sucesivas.
Corrección ortográfica
Errores ortográficos típicos:
- Un carácter por otro.
- Un carácter perdido.
- Un carácter añadido.
- Dos caracteres intercambiados.
Pueden comprobarse sólo los errores anteriores, lo que acelera el proceso.
Correcciones posibles:
- Análisis sintáctico
- Si se espera una palabra reservada y aparece un identificador, buscar la
palabra reservada más parecida al identificador.
- Deshacer errores de concatenación. Por ejemplo, convertir 'begina' en
'begin a'.
- Análisis semántico
- Si un identificador se utiliza en un contexto incompatible con su tipo,
tratar de sustituirlo por otro de nombre parecido y tipo compatible con el
contexto.
- Si un identificador no ha sido referenciado o asignado, es candidato para
corrección ortográfica. Sólo en compiladores de dos pasos. En la tabla de
símbolos se puede añadir como valor un par de contadores de uso y asignación.
Todas las correcciones efectuadas deben ser cuidadosamente documentadas,
para evitar que el programador se pierda al probar el programa.
Corrección de errores sintácticos
Si se detecta al analizar la cadena
xUy
donde x,y en A* y U en A es el próximo símbolo a analizar, podemos intentar lo
siguiente:
- Borrar U e intentarlo de nuevo.
- Insertar una cadena de terminales z entre x, U y empezar a analizar a
partir de z.
- Insertar una cadena de terminales z entre x, U y empezar a analizar a
partir de U, poniendo z en la pila (si es análisis bottom-up).
- Borrar símbolos del final de x e intentar de nuevo.
No hacer nunca los dos últimos. Deshace la información semántica asociada.
Ejemplo: tenemos
if (...) { x=0; else ...
El error se detecta en "else". Solución posible: añadir "}" delante de
"else", analizando
if (...) { x=0; } else ...
Recuperación de errores de compilación
Conviene tener una sola rutina de recuperación de errores separada del
resto del compilador.
- Evitar que un solo error produzca varios mensajes.
Ejemplo: A[i1,i2,...,i3], donde A no es un "array". Al abrir el corchete
nos dará un error: "A no es un array". Al cerrar el corchete podría dar otro:
"El número de índices no coincide con el rango de A". Si se ha dado el
primero, el segundo es innecesario. Una solución: detectado el primer error,
se sustituye la referencia a A por una referencia a un identificador
"fantasma". La rutina de recuperación de errores podría ignorar los mensajes
que se refieren al identificador fantasma.
- Evitar que un error idéntico repetido produzca varios mensajes. Ejemplo:
{ ...
{ int i;
...
/* { */ ...
}
for (i=0; i<j; i++) { a=j-i+1; b=2*a+i; }
}
}
Se nos olvida poner la tercera llave. La llave siguiente cierra el segundo
bloque. "i" está indefinida en el primer bloque. El bucle "for" nos daría
cinco veces el mensaje "variable i indefinida".
Solución: crear un identificador llamado "i" en la tabla de símbolos con
los atributos correctos. Esto elimina los mensajes subsiguientes. Atención:
esto podría hacer que no se detecte un error real que nos interesaría atrapar.
Otra alternativa sería imprimir un solo mensaje diciendo que el identificador
"i" ha sido utilizado sin declaración previa en las líneas número a,b,c...
Recuperación de errores en un intérprete
Hay que señalar el error y detener la ejecución, permitiendo al programador
- revisar las variables
- revisar el código
- modificar el código
- reanudar la ejecución
- saltarse líneas
- abandonar la ejecución del último programa
- abandonar totalmente la ejecución
y asegurarse de que todo sigue correctamente. En lenguaje simbólico se
puede manipular la pila de ejecución, salir automáticamente de rutinas
pendientes, sin continuar la ejecución, etc.