@c English version 2011-06-06
@menu
* Depuración del código fuente::
* Claves de depuración::
* Funciones y variables para depurado::
@end menu

@node Depuración del código fuente, Claves de depuración, , Depurado
@section Depuración del código fuente

Maxima es capaz de dar asistencia en la depuración del código fuente. Un usuario puede establecer un punto de referencia dentro del código de una función a partir del cual se siga la ejecución línea a línea. La compliación puede ser posteriormente examinada, conjuntamente con los valores que se han ido asignando a las variables.

La instrucción @code{:help}, o @code{:h}, muestra la lista de comandos para la depuración. (En general, los comandos pueden abreviarse; en algunos casos la lista de alternativas podrá ser listada.) Dentro del depurador, el usuario podrá examinar también cualquier función propia de Maxima, definirla y manipular variables y expresiones.

El punto de referencia se establecerá con la instrucción @code{:br}. Ya dentro del depurador, el usuario podrá avanzar una línea de cada vez utilizando la instrucción @code{:n} (de ``next'', en inglés). La orden @code{:bt} (de ``backtrace'') muestra la lista de la pila. Finalmente, con el comando @code{:r} (``resume'') se abandona el depurador continuando con la ejecución. El uso de estas instrucciones se muestra en el siguiente ejemplo.

@example
(%i1) load ("/tmp/foobar.mac");

(%o1)                           /tmp/foobar.mac

(%i2) :br foo
Turning on debugging debugmode(true)
Bkpt 0 for foo (in /tmp/foobar.mac line 1) 

(%i2) bar (2,3);
Bkpt 0:(foobar.mac 1)
/tmp/foobar.mac:1::

(dbm:1) :bt                  <-- pulsando :bt se retrocede
#0: foo(y=5)(foobar.mac line 1)
#1: bar(x=2,y=3)(foobar.mac line 9)

(dbm:1) :n                   <-- pulsando :n se avanza una línea
(foobar.mac 2)
/tmp/foobar.mac:2::

(dbm:1) :n                   <-- pulsando :n se avanza otra línea
(foobar.mac 3)
/tmp/foobar.mac:3::

(dbm:1) u;                   <-- se pide el valor de u
28

(dbm:1) u: 33;               <-- se cambia el valor de u a 33
33

(dbm:1) :r                   <-- pulsando :r se termina la depuración

(%o2)                                1094
@end example

El fichero @code{/tmp/foobar.mac} contiene lo siguiente:

@example
foo(y) := block ([u:y^2],
  u: u+3,
  u: u^2,
  u);
 
bar(x,y) := (
  x: x+2,
  y: y+2,
  x: foo(y),
  x+y);
@end example

USO DEL DEPURADOR EN EMACS

Si el usuario está corriendo el código bajo GNU emacs en un entorno de texto (dbl shell), o está ejecutando el  entorno gráfico @code{xmaxima}, entonces cuando una función pare en el punto de referencia, podrá observar su
posición actual en el archivo fuente, el cual será mostrado en la otra mitad de la ventana, bien resaltada en rojo, o con una pequeña flecha apuntando a la línea correcta. El usuario puede avanzar líneas simples 
tecleando M-n (Alt-n).

Bajo Emacs se debe ejecutar el programa en una ventana de texto @code{dbl}, la cual requiere el archivo @code{dbl.el} que está en el directorio elisp. El usuario debe instalar los archivos elisp o agregar el directorio elisp de Maxima a la ruta de búsqueda: por ejemplo, se puede añadir lo siguiente al archivo @file{.emacs} o al @code{site-init.el}

@example
(setq load-path (cons "/usr/share/maxima/5.9.1/emacs" load-path))
(autoload 'dbl "dbl")
@end example

entonces en emacs

@example
M-x dbl
@end example

debería abrir una ventana del sistema en la cual se pueden ejecutar programas, por ejemplo
Maxima, gcl, gdb, etc.  En esta ventana también se puede ejecutar el depurador, mostrando el código fuente en la otra ventana.

El usuario puede colocar un punto de referencia en una línea determinada sin más que teclear @code{C-x space}. Con esto se le hace saber al depurador en qué función está el cursor y en qué línea del mismo. Si el cursor está en la línea 2 de @code{foo}, entonces insertará en la otra ventana la instrucción ``@code{:br foo 2}'', a fin de detener @code{foo} justo en la segunda línea. Para tener esto operativo, el usuario debe tener activo maxima-mode.el (modo-maxima.el) en la ventana en la que está @code{foobar.mac}. Hay otros comandos disponibles en la ventana, como evaluar la función dentro de Maxima tecleando @code{Alt-Control-x}.


@node Claves de depuración, Funciones y variables para depurado, Depuración del código fuente, Depurado
@section Claves de depuración

Las claves de depuración son palabras que no son interpretadas como expresiones de Maxima. Una clave de depuración puede introducirse dentro de Maxima o del depurador. Las claves de depuración comienzan con dos puntos, ':'. Por ejemplo, para evaluar una expresión Lisp, se puede teclear @code{:lisp} seguido de la expresión a ser evaluada.

@example
(%i1) :lisp (+ 2 3) 
5
@end example

El número de argumentos depende del comando en particular. Además, tampoco es necesario teclear el nombre completo de la instrucción, tan solo lo justo para diferenciarla de las otras instrucciones. Así, @code{:br} sería suficiente para @code{:break}.

Las claves de depuración se listan a continuación.

@table @code
@item :break F n
Establece un punto de referencia en la función @code{F} en la línea @code{n} contando a partir del comienzo de la función. Si @code{F} es una cadena, entonces se entiende que se trata de un fichero, siendo entonces @code{n} el número de línea a partir del comienzo del fichero. El valor @code{n} es opcional; en caso de no ser suministrado, se entenderá que vale cero (primera línea de la función o fichero).
@item :bt
Retrocede en la pila.
@item :continue
Continua el cómputo de la función.
@item :delete
Borra los punto de referencia especificados, o todos si no se especifica ninguno.
@item :disable
Deshabilita los puntos de referencia especificados, o todos si no se especifica ninguno.
@item :enable
Habilita los puntos de referencia especificados, o todos si no se especifica ninguno.
@item :frame n
Imprime el elemento @code{n} de la pila, o el actualmente activo si no se especifica ninguno.
@item :help
Imprime la ayuda sobre un comando del depurador, o de todos los comandos si no se especifica ninguno.
@item :info
Imprime información sobre un elemento.
@item :lisp expresión
Evalúa la @code{expresión} Lisp.
@item :lisp-quiet expresión
Evalúa la @code{expresión} Lisp sin devolver el resultado.
@item :next
Como @code{:step}, excepto que @code{:next} se salta las llamadas a funciones.
@item :quit
Sale del nivel actual del depurador sin completar el cómputo.
@item :resume
Continúa con el cómputo.
@item :step
Sigue con el cómputo de la función o fichero hasta que alcance una nueva línea fuente.
@item :top
Retorna a Maxima desde cualquier nivel del depurador sin completar el cómputo.
@end table 


@node Funciones y variables para depurado, , Claves de depuración, Depurado
@section Funciones y variables para depurado


@defvr {Variable opcional} debugmode
Valor por defecto: @code{false}

Cuando en Maxima ocurre un error, Maxima inicializará el depurador si @code{debugmode} tiene el valor @code{true}. 
El usuario puede ingresar comandos para examinar la pila de llamadas, los puntos de interrupción; en pocas palabras ir a través del código de Maxima. Vea @code{debugging} para una lista de los comandos del depurador.  

Habilitando @code{debugmode} no se capturarán los errores tipo Lisp. 

@c DO WE WANT TO SAY MORE ABOUT DEBUGGING LISP ERRORS ???
@c I'M NOT CONVINCED WE WANT TO OPEN THAT CAN OF WORMS !!!

@end defvr


@defvr {Variable opcional} refcheck
Valor por defecto: @code{false}

Cuando @code{refcheck} vale @code{true}, Maxima imprime un mensaje cada vez que una variable es utilizada por vez primera en un cálculo.

@end defvr

@defvr {Variable opcional} setcheck
Valor por defecto: @code{false}

Cuando el valor de @code{setcheck} es una lista de variables (se admite que tengan subíndices) Maxima devuelve un mensaje indicando si los valores que han sido asignados a las variables lo han sido con el operador ordinario @code{:}, o con el operador de asignación @code{::} o como resultado de haberse realizado una llamada de función, pero en ningún caso cuando la asignación haya sido hecha mediante los operadores @code{:=} o @code{::=}. El mensaje contiene el nombre de la variable y su valor.

La variable @code{setcheck} admite también los valores @code{all} o @code{true} con lo que el informe incluirá todas las variables.

Cada nueva asignación de @code{setcheck} establece una nueva lista de variables a ser monitorizada, de forma que cualquier otra variable previamente asignada a @code{setcheck} es olvidada.

Los nombres asignados a @code{setcheck} deben estar precedidos del apóstrofo @code{'} a fin de evitar que las variables sean evaluadas antes de ser almacenadas en @code{setcheck}. Por ejemplo, si @code{x}, @code{y} y @code{z} ya guardan algún valor entoces se hará

@example
setcheck: ['x, 'y, 'z]$
@end example

para colocarlas en la lista de variables a monitorizar.

No se generará ninguna salida cuando una variable de la lista @code{setcheck} sea asignada a ella misma, como en @code{X: 'X}.

@end defvr

@defvr {Variable opcional} setcheckbreak
Valor por defecto: @code{false}

Si @code{setcheckbreak} es igual @code{true}, Maxima se detendrá siempre que a una variable de la lista @code{setcheck} se le asigne un nuevo valor. La detención tendrá lugar justo antes de hacerse la asignación. En ese momento @code{setval} guarda el valor que se le va a dar a la variable. Entonces el usuario podrá darle un valor diferente pasándoselo a la variable @code{setval}.

Véanse también @code{setcheck} y @code{setval}.

@end defvr

@defvr {Variable del sistema} setval

Guarda el valor que va a ser asignado a una variable cuando @code{setcheckbreak} realiza una detención. Entonces se podrá asignarle otro valor pasándoselo previamente a @code{setval}.

Véanse también @code{setcheck} y @code{setcheckbreak}.

@end defvr

@deffn {Función} timer (@var{f_1}, ..., @var{f_n})
@deffnx {Función} timer (all)
@deffnx {Función} timer ()
Dadas las funciones @var{f_1}, ..., @var{f_n}, @code{timer} coloca cada una de ellas en la lista de funciones para las cuales se generarán estadísticas relativas al tiempo de cómputo. Así, @code{timer(f)$ timer(g)$} coloca a @code{f} y luego a @code{g} en dicha lista de forma acumulativa.

La sentencia @code{timer(all)} coloca todas las funciones de usuario 
(las referenciadas por la variable global @code{functions}) en la lista
de funciones cuyos tiempos de ejecución se quieren monitorizar.

Si no se le pasan argumentos a @code{timer} se obtendrá la lista de funciones cuyos tiempos de ejecución se quieren monitorizar.

Maxima almacena la duración del cómputo de cada función de la lista, de forma que @code{timer_info} devolverá las estadísticas correspondientes, incluyendo el tiempo medio de cada llamada a la función, el número de llamadas realizadas y el tiempo total transcurrido. La instrucción @code{untimer} borra las funciones de la lista.

La función @code{timer} no evalúa sus argumentos, de forma que @code{f(x) := x^2$ g:f$ timer(g)$} no coloca a @code{f} en la lista.

Si @code{trace(f)} está activada, entonces @code{timer(f)} está desactivada; @code{trace} y @code{timer} no pueden estar operativas al mismo tiempo.

Véase también @code{timer_devalue}.

@end deffn

@deffn {Función} untimer (@var{f_1}, ..., @var{f_n})
@deffnx {Función} untimer ()
Dadas las funciones @var{f_1}, ..., @var{f_n}, @code{untimer} las elimina de la lista de funciones cuyos tiempos de ejecución se quiere monitorizar.

Si no se le suministran argumentos, @code{untimer} borra completamente la lista.

Tras la ejecución de @code{untimer (f)}, @code{timer_info (f)} aún devuelve las estadísticas de tiempo previamente registradas, pero @code{timer_info()} (sin argumentos) no devuelve información sobre aquellas funciones que ya no están en la lista. La ejecución de @code{timer (f)} inicializa todas las estadísticas a cero y coloca @code{f} nuevamente en la lista.

@end deffn

@defvr {Variable opcional} timer_devalue
Valor por defecto: @code{false}

Si @code{timer_devalue} es igual a @code{true}, Maxima le resta a cada función cuyos tiempos de ejecución se quiere monitorizar el tiempo gastado en llamadas a otras funciones presentes también en la lista de monitorización. En caso contrario, los tiempos que se obtienen para cada función incluyen también los consumidos en otras funciones. Nótese que el tiempo consumido en llamadas a otras funciones que no están en la lista de monitorización no se resta del tiempo total.

Véanse también @code{timer} y @code{timer_info}.

@end defvr

@deffn {Función} timer_info (@var{f_1}, ..., @var{f_n})
@deffnx {Función} timer_info ()
Dadas las funciones @var{f_1}, ..., @var{f_n}, @code{timer_info} devuelve una matriz con información relativa a los tiempos de ejecución de cada una de estas funciones. Sin argumentos, @code{timer_info} devuelve la información asociada a todas las funciones cuyos tiempos de ejecución se quiere monitorizar.

La matriz devuelta por @code{timer_info} incluye los nombres de las funciones, tiempo de ejecución en cada llamada, número de veces que ha sido llamada, tiempo total de ejecución y tiempo consumido en la recolección de basura, @code{gctime} (del inglés, "garbage collection time") en la versión original de Macsyma, aunque ahora toma el valor constante cero.

Los datos con los que @code{timer_info} construye su respuesta pueden obtenerse también con la función @code{get}:

@example
get(f, 'calls);  get(f, 'runtime);  get(f, 'gctime);
@end example

Véase también @code{timer}.

@end deffn


@deffn {Función} trace (@var{f_1}, ..., @var{f_n})
@deffnx {Función} trace (all)
@deffnx {Función} trace ()

Dadas las funciones @var{f_1}, ..., @var{f_n}, @code{trace} imprime información sobre depuración cada vez que estas funciones son llamadas; @code{trace(f)$ trace(g)$} coloca de forma acumulativa a @code{f} y luego a @code{g} en la lista de funciones a ser rastradas.

La sentencia @code{trace(all)} coloca todas las funciones de usuario 
(las referenciadas por la variable global @code{functions}) en la lista
de funciones a ser rastreadas.

Si no se suministran argumentos, @code{trace} devuelve una lista con todas las funciones a ser rastreadas.

La función @code{untrace} desactiva el rastreo. Véase también @code{trace_options}.

La función @code{trace} no evalúa sus argumentos, de forma que @code{f(x) := x^2$ g:f$ trace(g)$} no coloca a @code{f} en la lista de rastreo.

Cuando una función se redefine es eliminada de la lista de rastreo. Así, tras  @code{timer(f)$ f(x) := x^2$}, la función @code{f} dejará de estar en dicha lista.

Si @code{timer (f)} está activado, entonces @code{trace (f)} está desactivado, ya que @code{trace} y @code{timer} no pueden estar ambos activos para la misma función.

@end deffn

@deffn {Función} trace_options (@var{f}, @var{option_1}, ..., @var{option_n})
@deffnx {Función} trace_options (@var{f})

Establece las opciones de rastreo para la función @var{f}. Cualquier otra opción previamente especificada queda reemplazada por las nuevas. La ejecución de @code{trace_options (@var{f}, ...)} no tiene ningún efecto, a menos que se haya invocado previamente a @code{trace (@var{f})} (es indiferente que esta invocación sea anterior o posterior a @code{trace_options}). 

@code{trace_options (@var{f})} inicializa todas las opciones a sus valores por defecto.

Las claves de opciones son:

@itemize @bullet
@item
@code{noprint}:
No se imprime mensaje alguno ni a la entrada ni a la salida de la función.
@item
@code{break}:
Coloca un punto de referencia antes de que la función comience a ejecutarse y otro después de que termine su ejecución. Véase @code{break}.
@item
@code{lisp_print}:
Muestra los argumentos y valores retornados como objetos de Lisp.
@item
@code{info}:
Imprime @code{-> true} tanto a la entrada como a la salida de la función.
@item
@code{errorcatch}:
Detecta errores, otorgando la posibilidad de marcar un error, reintentar la llamada a la función o especificar un valor de retorno.
@end itemize

Las opciones de rastreo se especifican de dos formas. La única presencia de la clave de opción ya activa la opción. (Nótese que la opción @var{foo} no se activa mediante @code{@var{foo}: true} u otra forma similar; se tendrá en cuenta también que las claves no necesitan ir precedidas del apóstrofo.) Especificando la clave de opción junto con una función de predicado se hace que la opción quede condicionada al predicado.

La lista de argumentos para las funciones de predicado es siempre @code{[level, direction, function, item]} donde @code{level} es el nivel de recursión para la función,  @code{direction} puede ser tanto @code{enter} como @code{exit}, @code{function} es el nombre de la función  y @code{item} es la lista de argumentos (a la entrada) o el valor de retorno (a la salida).

A continuación un ejemplo de opciones de rastreo no condicionales:

@example
(%i1) ff(n) := if equal(n, 0) then 1 else n * ff(n - 1)$

(%i2) trace (ff)$

(%i3) trace_options (ff, lisp_print, break)$

(%i4) ff(3);
@end example

Para la misma función, con la opción @code{break} condicionada a un predicado:

@example
(%i5) trace_options (ff, break(pp))$

(%i6) pp (level, direction, function, item) := block (print (item),
    return (function = 'ff and level = 3 and direction = exit))$

(%i7) ff(6);
@end example

@end deffn

@deffn {Función} untrace (@var{f_1}, ..., @var{f_n})
@deffnx {Función} untrace ()
Dadas las funciones @var{f_1}, ..., @var{f_n},
@code{untrace} desactiva el rastreo previamente activado por la función @code{trace}. Si no se aportan argumentos, @code{untrace} desactiva el rastreo de todas las funciones.

La llamada a @code{untrace} devuelve una lista con las funciones para las que el rastreo se ha desactivado.

@end deffn


