4.5. Depurar el código Visual LISP

Hasta ahora nos hemos referido a las nuevas posibilidades que Visual LISP aporta para el desarrollo de aplicaciones. Pero en el desarrollo de programas nos toparemos inevitablemente con errores que deberán ser detectados y corregidos. Para ello las herramientas que examinaremos a continuación.


Evaluación inmediata del código

La primera opción de que disponemos es la evaluación inmediata de cada línea de código escrita. A medida que vamos escribiendo en la ventana del editor, es posible seleccionar el código que deseemos comprobar y pulsar el botón Cargar Selección (ver figura 1).

Figura 1. Barra de Herramientas Ejecutar: carga, comprueba, formatea y comenta el código.

Figura 2. Ventana del Editor con código seleccionado y punto de interrupción.

De inmediato se evalúa el código seleccionado, En la figura 2 mostramos el código de un programa que permite extraer de la lista de entidad de una LWPOYLINE las coordenadas de sus vértices. Seleccionando la línea

(setq lista (entget (car (entsel))))

y cargando esta selección, pasamos a la pantalla de AutoCAD donde se nos pide designar un objeto gráfico. A continuación, la consola Visual LISP nos mostrará el resultado devuelto, que habrá quedado almacenado en la variable lista.

Para comprobar la naturaleza de este dato basta situar el cursor sobre el nombre de esta variable y pulsar el botón Inspeccionar (ver figura 3).


Figura 3. Barra de Herramientas Ver: inspector de variables, rastreo de la ejecución, servicio de símbolos, búsqueda por aproximación y ventana de inspección en tiempo real.

Así, línea a línea sería posible ir comprobando los efectos de las diversas funciones que podemos usar para lograr determinado objetivo. ¿Qué sucedería si nuestro código encerrara un error? Supongamos que hemos olvidado introducir en esta línea de código la función car. En este caso, en lugar de un nombre de entidad obtendremos una lista del tipo:

(<Nombre de entidad: 16ca638> (0.591659 0.594869 0.0))

que al ser pasada a la función entget provocaría un error reflejado en la Consola con el mensaje:

; error: tipo de argumento erróneo: lentityp (<Nombre de entidad: 16d0638> (0.591659 0.594869 0.0))

donde lentityp es un predicado que indica la naturaleza del argumento que la función entget esperaba recibir (un nombre de entidad) y lo que realmente ha recibido. La Tabla 1 muestra algunos predicados asociados a mensajes de error.

La documentación de Visual LISP es deficiente en este sentido, no aclarando el significado de estos mensajes.

Predicado:

Argumento que se espera:

stringp

De tipo cadena (string)

numberp

Numérico (real o entero)

listp

Una lista

fixnump

Un número entero

lentityp

Un nombre de entidad

lselsetp

Un conjunto de selección

VLA-OBJECT

Un objeto Visual LISP ActiveX

output-streamp

Una salida a archivo de texto

streamp

Un archivo abierto para lectura o escritura

Tabla 1. Predicados asociados a mensajes de error

Puntos de interrupción (Break Points)

Identificada una función problemática, desearemos ver su funcionamiento paso a paso. Introduciendo puntos de interrupción se detendrá la ejecución del programa permitiendo comprobar su operación en detalle. Para ello disponemos del botón Activar/Desactivar Punto de Interrupción (ver figura 4), la correspondiente opción del menú Depurar (Debug) o simplemente la tecla de función F9.

Figura 4. Barra de Herramientas Depurar: control de la evaluación en modo interrupción, colocación de puntos de interrupción y añadir variables a inspeccionar.

El programa se ejecutará hasta llegar al primer punto de interrupción. Al llegar ahí, el control pasa a la Consola y vemos resaltada la expresión en la ventana del Editor. Observemos que el símbolo (prompt) de la consola aparece ahora numerado: _1_$ lo que nos indica que estamos en un nuevo bucle de evaluación (read-eval-print loop) anidado bajo el bucle superior (top-level) que es donde se ha llamado al programa. Podemos controlar el paso a que se evalúan las expresiones mediante los botones Entrar (Step Into) que se detiene en cada expresión anidada, Pasar al Siguiente (Step Over) que evalúa toda la expresión resaltada, o Ir al Final (Step Out) que busca el final de la función donde el programa se ha detenido y efectúa la evaluación hasta allí.

Durante este estado de interrupción podemos evaluar expresiones en la Consola que nos den información sobre el contenido de las variables (tecleando el nombre de la variable y pulsando INTRO) e incluso cambiar el contenido de las mismas a partir de la evaluación de cualquier función en la consola o empleando el Servicio de Símbolos (ver Figura 5).

Figura 5. Ventana del Servicio de Símbolos

Pulsando el botón Continuar (ver figura 4), se pasará al próximo punto de interrupción si lo hubiera. Para ascender un nivel (ya que pueden darse varios bucles de interrupción anidados) se pulsará el botón Descartar (Quit Current Level) y para regresar directamente al nivel superior el botón Restablecer (Reset to Top Level).

El programa entrará de manera automática en un bucle de interrupción al encontrar un error en tiempo de ejecución, siempre que se encuentre activada la opción Interrupción en Error (Break on Error) del menú Depurar (Debug). En ese estado tendremos acceso al contenido de todas las variables del entorno en que se ha producido el error, pero no será posible continuar la ejecución.

Para conservar los puntos de interrupción de una sesión de trabajo a otra será necesario Guardar Parámetros (Save Settings) desde el menú Herramientas (Tools). Los puntos de interrupción se pierden al aplicar las operaciones de formateo automático.

La ventana Inspección (Watch)

Tenemos también la posibilidad de vigilar los valores que devuelven las funciones. Para ello es la ventana Inspección (Watch). Para abrirla con el valor de la última expresión evaluada se puede seleccionar la opción Inspeccionar Ultima Evaluación (Watch Last Evaluation) del menú Depurar. O bien pulsar el botón de la barra de herramientas correspondiente (ver figura 4), que abre el diálogo Añadir Inspección (Add Watch). Si el cursor estuviera situado sobre el nombre de alguna variable, este aparecería en la casilla de lista desplegable. En caso contrario, podemos escribir su nombre o elegir el valor por defecto que es la variable global *LAST-VALUE* (última evaluación). La ventana Inspección (ver figura 6) se actualiza a medida que los valores de los símbolos inspeccionados cambian. Así, al entrar en un bucle de interrupción tendremos siempre a la vista los valores actuales. En cualquier momento estos valores pueden ser copiados a la ventana de Rastreo (Trace)  mediante el botón Copiar en Rastreo/Registro (Copy to Trace/Log). Si estuviera activada la opción Act/Des Registro de Rastreo, accesible desde el menú contextual de la ventana de Rastreo, esta información también se copiaría a un archivo de extensión LOG.

Figura 6. Inspección de las variables seleccionadas en tiempo real.

La opción de Animar

El menú Depurar nos ofrece la opción de Animar (Animate). Al activar esta opción, la ejecución del programa se hará toda en modo de interrupción como si pulsáramos continuamente el botón Entrar (Step Into). El intervalo de tiempo entre la evaluación de cada expresión es configurable desde Herramientas>Opciones de Entorno>Opciones Generales (ficha Diagnóstico). Para detener la animación puede pulsarse la tecla PAUSA (BREAK) y de esa manera observar y cambiar si fuera necesario el valor de las variables o colocar nuevos puntos de interrupción. Al encontrar un punto de interrupción en modo Animar, deberemos usar los botones Entrar, Pasar a Siguiente o Ir al Final para continuar la evaluación. Tanto en uno como en otro caso, la ejecución en modo Animar se reinicia pulsando el botón Continuar. El modo Animar es sumamente instructivo especialmente cuando en el programa incluye bucles anidados.

La Pila de Rastreo (Trace Stack)

La Pila de Rastreo contiene el registro histórico de la ejecución de funciones dentro del programa. Una Pila (Stack) es una estructura de programación que se caracteriza por el orden de entrada y salida de los elementos que almacena: el último elemento en entrar es el primero en salir. Su inspección (durante una interrupción del programa) permite observar lo que sucede durante la ejecución.

El invocar una función hace que se incluya un elemento en la pila. Cuando se llama a otras funciones anidadas, pueden añadirse a ella nuevos elementos. Esto se hará siempre que sea necesario a Visual LISP para recordar la vía de salida. En una pila pueden aparecer cinco tipos de elementos (ver Tabla 2).

Elemento

Contenido

Llamadas a funciones

nivel (nombre-función {argumento 1} ... )

se presentan los argumentos realmente pasados a la función

Palabras clave

nivel :palabra_clave- (datos opcionales)

ocupan los niveles superior e inferior de la pila

Formas del nivel superior

acciones iniciadas al teclear una expresión en la Consola o al cargar un archivo o una selección.

Formas lambda

se incluye cada vez que se encuentra una expresión lambda en el programa

Formas especiales

nivel (forma-función ...)

muestran las llamadas a funciones foreach y repeat. Los argumentos no se muestran

Tabla 2. Elementos de la Pila de Rastreo

Para obtener más información acerca de cualquiera de los elementos de la pila se deberá seleccionar y llamar al menú contextual pulsando el botón derecho del ratón (ver figura 7). Algunas opciones de especial interés son:

  • Variables Locales (Local Variables): examina el valor que poseían las variables locales en el momento de ejecutarse la función
  • Posición de Origen (Source Position): muestra el código fuente resaltándolo en la ventana del editor.
  • Origen del Punto de Llamada (Call Point Source): curiosamente traducido por Autodesk como "Ejecutar Origen de Punto", muestra la posición de la expresión de llamada, al igual que la opción anterior. La diferencia radica en que, según el elemento seleccionado, estará disponible una u otra opción, y a veces ambas.
Figura 7. Pila de Rastreo con su menú contextual.

Palabras Clave

Una palabra clave indica una operación específica que tiene lugar en el entorno VLISP. La Tabla 3 muestra algunas de las palabras clave que sólo aparecerán en el fondo de la pila.

Palabra clave

Operación

:ACAD-REQUEST

La llamada a la función que le sigue en la pila (más arriba) fue invocada desde la línea de comandos de AutoCAD.

:DCL-ACTION

Acción llamada desde un cuadro de diálogo. A la palabra clave le siguen dos cadenas: el nombre del diálogo y el valor de la variable $KEY. Si un número, representa el valor de la variable $REASON. El elemento que le sigue en la casilla de arriba describe la llamada a función construida a partir de la cadena asociada al botón de acción.

:TOP-COMMAND

Función invocada al cargar un archivo o selección.

:USER-INPUT

Tecleado en la Consola. La casilla de arriba muestra la expresión resultante.

Tabla 3. Palabras clave (fondo de la Pila)

Entre las palabras clave más frecuentes que pueden aparecer en la parte superior de la pila están las que muestra la Tabla 4.

Palabra clave

Operación

:BEFORE-EXP

Indica que un programa se está depurando en modo interrupción. Indica que se ha entrado en una expresión.

:AFTER-EXP

Igual que el anterior, al salir de una expresión.

:ARQ-SUBR-CALLBACK

Llamada normal de AutoCAD a una función definida en VLISP.

:BREAK-POINT

Punto de interrupción especificado por el usuario.

:ERROR-BREAK

Error en tiempo de ejecución. La opción Mostrar Mensaje (Show Message) del menú contextual muestra mensajes de error más específicos.

:FUNCTION-ENTRY

Interrupción al entrar en una función, el elemento siguiente muestra la llamada a dicha función

:KBD-BREAK

Se ha pulsado la tecla PAUSA.

:READ-ERROR

Error durante una operación de lectura.

:SYNTAX-ERROR

Se ha detectado una sintaxis AutoLISP incorrecta

Tabla 4. Palabras clave (extremo superior de la Pila)

Rastreo de Errores

Cuando se produce un error, el estado de la Pila de Rastreo se copia automáticamente a la ventana de Rastreo de Errores (Error Trace), a la que se accede desde el menú Ver>Rastreo de Errores (View>Error Trace).

Como copia que es de la Pila de Rastreo, todo lo explicado sobre ésta se aplica al Rastreo de Errores. La única diferencia es la siguiente:

Tanto en la ventana de la Pila de Rastreo como la de Rastreo de Errores hay dos botones. El de la izquierda sirve para Renovar (Refresh) el contenido de la ventana. Cuando se pulsa este botón después de salir de un bucle de interrupción pasando al bucle de nivel superior, el Renovar la Pila de Rastreo cambiará su contenido para reflejar la situación actual, mientras que Renovar el Rastreo de Errores no cambiará su contenido a menos que se haya producido un nuevo error (ver figura 8).

Figura 8. Comparación entre la Pila de Rastreo y el Rastreo de Errores. Se ha introducido la función strcat, ilegal en este contexto, para provocar intencionalmente el error.

Conclusiones

Hemos visto las principales herramientas de que dispone el IDE Visual LISP para la depuración de errores. No debemos olvidar las otras ayudas disponibles desde el mismo Editor, tales como la sintaxis coloreada (basta ver un nombre de función que no se coloree de azul para saber que está mal escrito), la detección del cierre de los paréntesis, la revisión de sintaxis, el formateo automático o la introducción de comentarios al cierre de las expresiones (ver figura 1). Sin olvidar la comprobación ulterior que se realiza al momento de compilar la función que ya comentamos en nuestro artículo del mes pasado. Con todo ello disponemos de un entorno poderoso para el desarrollo de las aplicaciones más complejas.