3.1.1 Manejo de los Errores Sintácticos

Si un compilador tuviera que procesar sólo programas correctos, su diseño e implantación se simplificarían mucho. Pero los programadores a menudo escriben programas incorrectos, y un buen compilador debería ayudar al programador a identificar y localizar errores. Es sorprendente que aunque los errores sean tan frecuentes, pocos lenguajes han sido diseñados teniendo en cuenta el manejo de errores.

Esta civilización sería completamente distinta si los lenguajes hablados exigieran tanta exactitud sintáctica como los lenguajes de programación. La mayoría de las especificaciones de los lenguajes de programación no describen cómo debe responder un compilador a los errores; la respuesta se deja al diseñador del compilador. Considerar desde el principio el manejo de errores puede simplificar la estructura de un compilador y mejorar su respuesta a los errores. Se sabe que los programas pueden contener errores de muy diverso tipo. Por ejemplo, los errores pueden ser:

  • 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

A menudo, gran parte de la detección y recuperación de errores en un compilador se centra en la fase de análisis sintáctico. Una razón es que muchos errores son de naturaleza sintáctica o se manifiestan cuando la cadena de componentes léxicos que proviene del analizador léxico desobedece las reglas gramaticales que definen al lenguaje de programación.

Otra razón es la precisión de los métodos modernos de análisis sintácticos, que pueden detectar la presencia de errores dentro de los programas de una forma muy eficiente. La detección exacta de la presencia de errores semánticos y lógicos en el momento de la compilación es mucho más dificil. En esta sección se presentan algunas técnicas básicas para recuperarse de errores sintácticos; en este capítulo se estudia su implantación junto con los métodos de análisis sintáctico.

El manejador de errores en un analizador sintáctico tiene objetivos fáciles de establecer:

  • Debe informar de la presencia de errores con claridad y exactitud.
  • Se debe recuperar de cada error con la suficiente rapidez como para detectar errores posteriores.
  • No debe retrasar de manera significativa el procesamiento de programas correctos.

La realización efectiva de estos objetivos plantea desafíos importantes. Afortunadamente. los errores más comunes son simples y a menudo basta con un mecanismo sencillo de manejo de errores. Sin embargo, en algunos casos un error pudo haber ocurrido mucho antes de la posición en que se detectó su presencia, y puede ser muy difícil deducir la naturaleza precisa del error. En los casos difíciles, el manejador de errores quizá tenga que adivinar qué tenía en mente el programador cuando escribió el programa.

¿Cómo debe informar un manejador de errores de la presencia de un error? Al menos debe informar del lugar en el programa fuente donde se detecta el error. Porque es muy probable que el error real se haya producido en alguno de los componentes léxicos anteriores. Una estrategia común empleada por muchos compiladores es imprimir la línea errónea con un apuntador a la posición donde se detecta el error. Si hay una posibilidad razonable de saber cuál es realmente el error. También se incluye un mensaje de diagnóstico informativo y comprensible: por ejemplo. "falta punto y coma en esta posición"

Una vez  detectado el error, ¿cómo se debe recuperar el analizador sintáctico? Como se verá, existen varias estrategias generales, pero ningún método es claramente superior. En la mayoría de los casos, no es adecuado que el analizador sintáctico abandone después de detectar el primer error, porque el posterior procesamiento de la entrada podría revelar más errores. Normalmente, hay alguna forma de recuperación del error donde el analizador sintáctico intenta volver él mismo a un estado en el que el procesamiento de la entrada pueda continuar con una esperanza razonable de que se hará el análisis de la entrada correcta o de que será manejada correctamente por el compilador.

Una estrategia conservadora para un compilador es inhibir los mensajes de error que provengan de errores descubiertos demasiado cerca unos de otros en la cadena de entrada Después de descubrir un error sintáctico, el compilador podría exigir que varios componentes léxicos se analizarán sintácticamente con éxito antes de permitir otro mensaje de error. En algunos casos, puede haber demasiados errores como para que el compilador continúe un procesamiento razonable. (Por ejemplo, ¿cómo debe responder un compilador de Pascal a un programa en FORTRAN como entrada?)

Parece que una estrategia de recuperación de errores tiene que ser un compromiso cuidadosamente considerado, teniendo en cuenta las clases de errores que se pueden presentar y que sean de procesamiento razonable.

 Como ya se ha mencionado, algunos compiladores intentan reparar el error, proceso en el cual el compilador intenta, adivinar lo que pretendía escribir el programador. El compilador de PL/C (Conway y Wilcox [ 1973]) es un ejemplo de este tipo de compilador. Excepto tal vez en un entorno de programas cortos escritos por estudiantes inexpertos, no es probable que la recuperación completa de los errores sea rentable. De hecho, con la importancia creciente de la informática interactiva y los buenos entornos de programación, la tendencia parece ser hacia mecanismos sencillos de recuperación de errores.