Fehlersuche (Maxima Manual)

## 29 Fehlersuche

### 29.1 Quellcode-Debugger

Maxima hat einen Quellcode-Debugger. Es können Unterbrechungspunkte gesetzt werden, um die Ausführung einer Funktion abzubrechen und um schrittweise die Funktion zu testen. Der Stapelspeicher und Variable können untersucht werden.

Das Kommando `:help` oder `:h` zeigt eine Liste mit den Debugger-Kommandos. Innerhalb des Debuggers können alle Maxima-Funktionen genutzt werden, um Variablen und Ausdrücke auszugeben, zu definieren oder anderweitig zu manipulieren.

Eine Unterbrechnung wird mit dem Kommando `:br` gesetzt. Mit dem Kommando `:n` oder `:next` wird die nächste Programmzeile ausgeführt. Das Kommando `:bt` oder `:backtrace` zeigt eine Liste der Stack Frames. Mit dem Kommando `:r` oder `:resume` wird der Debugger verlassen.

Beispiele:

    (%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                        <-- :bt typed here gives a backtrace
    #0: foo(y=5)(foobar.mac line 1)
    #1: bar(x=2,y=3)(foobar.mac line 9)

    (dbm:1) :n                         <-- Here type :n to advance line
    (foobar.mac 2)
    /tmp/foobar.mac:2::

    (dbm:1) :n                         <-- Here type :n to advance line
    (foobar.mac 3)
    /tmp/foobar.mac:3::

    (dbm:1) u;                         <-- Investigate value of u
    28

    (dbm:1) u: 33;                     <-- Change u to be 33
    33

    (dbm:1) :r                         <-- Type :r to resume the computation

    (%o2)                                1094

Die im obigen Beispiel geladene Datei `/tmp/foobar.mac` hat den folgenden Inhalt:

    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);

#### Nutzung des Debuggers mit Emacs

Wird Maxima unter GNU Emacs in einer Shell ausgeführt oder wird die Nutzeroberfläche Xmaxima verwendet, dann wird in einem zweiten Ausgabefenster die Position einer Unterbrechung im Quellcode angezeigt. Mit dem Emacs-Kommando `M-n` kann dann schrittweise die Funktion ausgeführt werden.

Um diese Funktionalität zu nutzen, sollte Emacs in einer `dbl`-Shell ausgeführt werden. Dazu benötigt Emacs die Datei `dbl.el` im elisp Verzeichnis. Dazu müssen die elisp-Dateien installiert oder das Maxima elisp Verzeichnis bekannt sein. Dazu können die folgenden Kommandos der Datei `.emacs` hinzugefügt werden:

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

Mit dem Emacs-Kommando `M-x dbl` wird eine Shell gestartet, in der Programme wie Maxima, gcl, gdb u. a. ausgeführt werden können. In dieser Shell kann auch der Maxima-Debugger ausgeführt werden.

The user may set a break point at a certain line of the file by typing `C-x space`. This figures out which function the cursor is in, and then it sees which line of that function the cursor is on. If the cursor is on, say, line 2 of `foo`, then it will insert in the other window the command, “`:br foo 2`”, to break `foo` at its second line. To have this enabled, the user must have maxima-mode.el turned on in the window in which the file `foobar.mac` is visiting. There are additional commands available in that file window, such as evaluating the function into the Maxima, by typing `Alt-Control-x`.

### 29.2 Debugger-Kommandos

Es gibt spezielle Kommandos, die von Maxima nicht als ein Ausdruck interpretiert werden. Diese Kommandos beginnen mit einem Doppelpunkt `:` und können in der Kommandozeile oder nach einer Unterbrechung ausgeführt werden. Mit dem Kommando `:lisp` werden zum Beispiel Lisp-Zeilen ausgewertet:

    (%i1) :lisp (+ 2 3)
    5

Die Anzahl der Argumente hängt vom jeweiligen Kommando ab. Die Kommandos können mit den ersten zwei Buchstaben abgekürzt werden. Zum Beispiel genügt es `:br` für das Kommando `:break` einzugeben.

Die speziellen Kommandos sind folgende:

`:break F n`

  Setzte einen Unterbrechnungspunkt in der Funktion `F` in der Zeile `n` vom Anfang der Funktion. Wird `F` als eine Zeichenkette angegeben, dann wird `F` als der Name einer Datei angenommen. `n` ist in diesem Fall die `n`-te Zeile in der Datei. Wird `n` nicht angegeben, wird der Wert zu Null angenommen.

`:bt`

  Gebe einen Backtrace des Stack Frames aus.

`:continue`

  Setze die Ausführung der Funktion fort.

`:delete`

  Lösche den spezifizierten Unterbrechnungspunkt oder alle, wenn keiner spezifiziert wird.

`:disable`

  Schalte den spezifierten oder alle Unterbrechnungspunkte ab.

`:enable`

  Schalte den spezifizierten oder alle Unterbrechnungspunkte ein.

`:frame n`

  Gebe den Stack Frame `n` oder den aktuellen aus, wenn keiner spezifiert wird.

`:help`

  Gebe einen Hilfetext zu einem spezifierten Kommando oder zu allen Kommandos aus, wenn kein Kommando spezifierten wird.

`:info`

  Gebe Information über einen Eintrag aus.

`:lisp some-form`

  Werte `some-form` als eine Lisp-Form aus.

`:lisp-quiet some-form`

  Werte `some-form` als eine Lisp-Form aus, ohne eine Ausgabe zu erzeugen.

`:next`

  Wie `:step`, führt aber Funktionsaufrufe als einen Schritt aus.

`:quit`

  Beende den Debugger.

`:resume`

  Setzte die Ausführung des Programms fort.

`:step`

  Setzte die Auswertung des Programms bis zur nächsten Zeile fort.

`:top`

  Beende die Auswertung und kehre zur Maxima-Eingabe zurück.

### 29.3 Funktionen und Variablen der Fehlersuche

Optionsvariable: debugmode ¶

  Standardwert: `false`

  Hat die Optionsvariable `debugmode` den Wert `true`, wird der Maxima-Debugger gestartet, wenn ein Programmfehler auftritt. Nach der Unterbrechung des Programms kann der Debugger genutzt werden. Siehe das Kapitel Debugger-Kommandos für eine Liste der Kommandos des Debuggers.

  Der Maxima-Debugger behandelt keine Lisp-Programmfehler.

Optionsvariable: refcheck ¶

  Standardwert: `false`

  Hat `refcheck` den Wert `true`, gibt Maxima eine Meldung aus, wenn einer Variablen zum ersten Mal ein Wert zugewiesen wird.

Optionsvariable: setcheck ¶

  Standardwert: `false`

  Der Optionsvariablen `setcheck` kann eine Liste mit den Namen von Variablen zugewiesen werden. Dies können auch indizierte Variablen sein. Immer wenn einer der Variablen mit den Operatoren `:` oder `::` ein Wert zugewiesen wird, gibt Maxima eine Meldung aus, die den Namen der Variablen und den zugewiesenen Wert enthält.

  `setcheck` kann den Wert `all` oder `true` erhalten. In diesem Fall wird für alle Variablen eine Meldung ausgegeben.

  Jede Zuweisung an `setcheck` initialisert eine neue Liste mit Variablen. Vorherige Zuweisungen werden überschrieben.

  Die Auswertung der Namen der Variablen muss mit dem Quote-Operator `'` unterdrückt werden, wenn den Variablen bereits Werte zugewiesen wurden. Haben zum Beispiel die Variablen `x`, `y` und `z` Werte, dann werden die Variablen mit dem folgenden Befehl angegeben:

      setcheck: ['x, 'y, 'z]$

  Es wird keine Meldung ausgegeben, wenn eine Variable sich selbst zugewiesen wird, zum Beispiel `X: 'X`.

Optionsvariable: setcheckbreak ¶

  Standardwert: `false`

  Hat `setcheckbreak` den Wert `true`, startet Maxima den Debugger, wenn einer Variablen, die in der Liste `setcheck` enthalten ist, ein Wert zugewiesen wird. Die Unterbrechung wird noch vor der Zuweisung des Wertes ausgeführt. Die Variable `setval` enhält den Wert, der zugewiesen werden soll. Dieser Variablen kann ein anderer Wert zugewiesen werden.

  Siehe auch `setcheck` und `setval`.

Systemvariable: setval ¶

  Enthält den Wert, der einer Variable zugewiesen werden soll, wenn die Zuweisung mit der Optionsvariablen `setcheckbreak` unterbrochen wurde. `setval` kann ein anderer Wert zugewiesen werden.

  Siehe auch `setcheck` und `setcheckbreak`.

Funktion: timer (f_1, …, f_n) ¶
Funktion: timer (all) ¶
Funktion: timer () ¶

  Sammelt Statistiken über die Ausführungszeiten von Funktionen. Die Argumente f_1, …, f_n sind die Namen von Funktionen zu denen Statistiken gesammelt werden. `time(g)` fügt die Funktion `g` der Liste an Funktionen hinzu, zu denen Informationen gesammelt werden.

  `timer(all)` fügt alle nutzerdefinierten Funktionen, die in der Informationsliste `functions` enthalten sind, der Liste der Funktionen hinzu, über die Informationen gesammelt werden.

  Wird `timer()` ohne Argumente aufgerufen, wird eine Liste der Funktionen zurückgeben, über die Informationen gesammelt werden.

  Maxima misst die Zeit, die eine Funktion für die Ausführung benötigt. `timer_info` gibt eine Statistik für alle Funktionen zurück, für die die Ausführungszeiten gemessen werden. Die Statistik enthält die durchschnittliche Ausführungszeit der Funktionen und die Anzahl der Aufrufe der Funktionen. Mit der Funktion `untimer` wird die Aufzeichnung der Ausführungszeiten beendet.

  `timer` wertet die Argumente nicht aus. Daher werden im Folgenden `f(x) := x^2$ g:f$ timer(g)$` für die Funktion `f` keine Ausführungszeiten aufgezeichnet.

  Wird für die Funktion `f` mit dem Kommando `trace(f)` der Ablauf verfolgt, hat das Kommando `timer(f)` keinen Effekt. Für eine Funktion können nicht gleichzeitig Ausführungszeiten aufgezeichnet und der Ablauf verfolgt werden.

  Siehe auch `timer_devalue`.

Funktion: untimer (f_1, …, f_n) ¶
Funktion: untimer () ¶

  `untimer` beendet die Aufzeichnung von Informationen zur Ausführungszeit für die Funktionen f_1, …, f_n.

  Wird `untimer` ohne Argument aufgerufen, wird die Aufzeichnung für alle Funktionen beendet.

  Die aufgezeichneten Informationen zu einer Funktion `f` können mit dem Kommando `timer_info(f)` auch dann abgerufen werden, wenn zuvor mit dem Kommando `untimer(f)` die Aufzeichnung für die Funktion `f` beendet wurde. Jedoch werden die aufgezeichneten Informationen für die Funktion `f` nicht mit dem Kommando `timer_info()` angezeigt. Das Kommando `timer(f)` setzt alle aufgezeichneten zurück und startet die Aufzeichnung für die Funktion erneut.

Optionsvariable: timer_devalue ¶

  Standardwert: `false`

  Hat `timer_devalue` den Wert `true`, subtrahiert Maxima bei der Aufzeichnung der Ausführungszeiten die Zeiten, welche eine Funktion in anderen Funktionen verbringt. Ansonsten enthalten die aufgezeichneten Zeiten auch die Ausführungszeiten der Funktionen, die aufgerufen werden.

  Siehe auch `timer` und `timer_info`.

Funktion: timer_info (f_1, …, f_n) ¶
Funktion: timer_info () ¶

  Gibt eine Tabelle mit den aufgezeichneten Informationen über die Ausführungszeiten der Funktionen f_1, …, f_n zurück. Wird kein Argument angegeben, werden Informationen für alle Funktionen angezeigt, zu denen Informationen aufgezeichnet sind.

  Die Tabelle enthält die Namen der Funktionen, die Ausführungszeit pro Aufruf, die Anzahl der Aufrufe, die gesamte Zeit und die `gctime`-Zeit. Die `gctime`-Zeit bedeutet "Garbage Collection Time".

  Die Daten, die von der Funktion `timer_info` angezeigt werden, können auch mit der Funktion `get` erhalten werden:

      get(f, 'calls);  get(f, 'runtime);  get(f, 'gctime);

  Siehe auch `timer`.

Funktion: trace (f_1, …, f_n) ¶
Funktion: trace (all) ¶
Funktion: trace () ¶

  Startet die Ablaufverfolgung für die Funktionen f_1, …, f_n. Mit dem Kommando `trace(g)` kann eine weitere Funktion hinzugefügt werden.

  `trace(all)` startet die Ablaufverfolgung für alle nutzerdefinierten Funktionen, die in der Informationsliste `functions` enthalten sind.

  Das Kommando `trace()` zeigt eine Liste aller Funktionen für die eine Ablaufverfolgung gestartet wurde.

  Mit der Funktion `untrace` wird die Ablaufverfolgung beendet. Siehe auch `trace_options`.

  `trace` wertet die Argumente nicht aus.

  Die Ablaufverfolgung kann für eine Funktion `f` nicht gestartet werden, wenn für die Funktion bereits mit der Funktion `timer` Informationen über die Ausführungszeiten gesammelt werden.

Funktion: trace_options (f, option_1, …, option_n) ¶
Funktion: trace_options (f) ¶

  Setzt Optionen für die Ablaufverfolgung einer Funktion f. Bereits vorliegende Optionen werden ersetzt.

  `trace_options(f)` setzt alle Optionen auf die Standardwerte zurück.

  Die Optionen sind:

  `noprint`

    Gebe keine Meldung beim Eintritt in eine oder dem Austritt aus einer Funktion aus.

  `break`

    Setze eine Unterbrechnung vor dem Eintritt in eine Funktion und nach dem Austritt aus einer Funktion. Siehe `break`.

  ``lisp_print``

    Zeige die Argumente und Rückgabewerte in der Lisp-Syntax an.

  `info`

    Gebe `-> true` beim Eintritt in und Austritt aus einer Funktion aus.

  ``errorcatch``

    Catch errors, giving the option to signal an error, retry the function call, or specify a return value.

  Es können bedingte Optionen für die Ablaufverfolgung definiert werden. Dazu wird eine Option zusammen mit einer Aussagefunktion angegeben. Die Argumente der Aussagefunktion für eine bedingte Option sind immer `[level, direction, function, item]`. `level` ist die Rekursionstiefe der Funktion, `direction` enthält die Werte `enter` oder `exit`, `function` ist der Name der Funktion und `item` ist eine Liste der Argumente oder der Rückgabewert beim Verlassen der Funktion.

  Dies ist ein Beispiel für eine Ablaufverfolgung ohne Bedingungen:

      (%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);

  In diesem Fall wird eine Aussagefunktion für eine bedingte Ablaufverfolgung angegeben:

      (%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);

Funktion: untrace (f_1, …, f_n) ¶
Funktion: untrace () ¶

  Beendet die Ablaufverfolgung für die Funktionen f_1, …, f_n. Das Kommando `untrace()` beendet die Ablaufverfolgung für alle Funktionen.

  `untrace` gibt eine Liste der Funktionen zurück, für die die Ablaufverfolgung beendet wurde.