10. Der Library Maker Inhaltsverzeichnis

 

Kapitel 11

Der Source Code Debugger

Einleitung
Debuggersteuerung
STOP Befehle und Breakpoints
Speicherfenster
Variablenfenster
Debuggereinstellungen
Fehlermeldungen des Debuggers
Praktische Beispiele





Einleitung

Wenn Sie bereits Computerprogramme geschrieben haben, kennen Sie sicherlich das Problem, dass ein Programm sich anders verhält, als man es sich überlegt hat. Ohne Hilfsmittel ist es im allgemeinen sehr schwer, einen simplen Schreibfehler oder auch einen systematischen Fehler zu finden, da man dem Programm bei der Arbeit nur bedingt zusehen kann.
Mit dem Source Code Debugger können Sie nun ganz gezielt auf Fehlersuche gehen. Dazu halten Sie Ihr Programm einfach an geeigneter Stelle an und arbeiten sich in Einzelschritten voran. Dabei können Sie verfolgen, wie sich Variablen- oder Speicherinhalte verändern und so gezielt feststellen, an welcher Stelle sich Ihr Programm anders verhält, als geplant. Ein kleines Dreick im Quellcode zeigt beim Debuggen ständig die aktuelle Position des Programmzeigers.
Aber auch für didaktische Zwecke ist der Source Code Debugger bestens geeignet. Lehrer können durch die Einzelschritttechnik Ihren Schülern auf einfache Weise vermitteln, wie ein Algorithmus funktioniert.
Hierfür gibt es auch noch den Animationsmodus, bei dem ein Programm sozusagen in Zeitlupe ausgeführt wird, so dass man die einzelnen Schritte genau verfolgen kann.


Debuggersteuerung

Um ein Programm debuggen zu können, müssen Sie zunächst das Fenster mit dem Quellcode nach oben holen und dann den Menüpunkt 'Debuggen' aus dem 'Programm' Menü anwählen. Das Programm wird dadurch in einem speziellen Format compiliert, das es dem Debugger ermöglicht, jederzeit den Programmablauf zu kontrollieren. Dabei werden auch noch ständig folgende mögliche Fehlerquellen überwacht:

- Integer-Überläufe bei Byte-, Integer- und Long-Integer-Zahlen. Z. B. würde A%=32768 oder A%L=10^12 einen solchen Fehler auslösen.

- Fliesskomma-Überläufe und Fliesskomma-Unterläufe. Diese Fehler treten auf, wenn das Ergebnis einer Rechnung in dem verwendeten Zahlenformat nicht dargestellt werden kann (z.B. A#=10^100*10^250 oder A!=10^-45).

- Divisionen durch Null.

- Unerlaubte Operation wie z. B. A#=LN(-1).

- Überlauf des BASIC-Stacks. Dies kann z.B. beim Sortieren grösserer Felder oder bei rekursiever Programmierung mit grosser Schachteltiefe auftreten.

- Bei Feldvariablen wird überprüft, ob die angegebenen Indizes im dem Bereich liegen, für den das Feld dimensioniert wurde. Z. B. DIM A#(2,3):A#(3,2)=1 würde einen solchen Fehler auslösen.

Wenn einer dieser Fehler auftritt, wird zunächst eine Alertbox angezeigt, die den Fehler beschreibt. Nach Verlassen der Alertbox erscheint die Debuggersteuerung. Sie können jetzt Speicher- und Variablenfenster öffnen und so herausfinden, wodurch der Fehler entstanden ist. Falls es sich nicht um einen fatalen Fehler handelt, kann das Programm sogar fortgesetzt werden, andernfalls wird es in jedem Fall beendet, auch wenn Sie versuchen, es fortzusetzen.

Natürlich gibt es noch viele weitere Fallen, in die ein Programmierer tappen kann und die vom Debugger prinzipbedingt nicht erkannt werden können (z. B. LPOKE 12,-1 oder wenn Sie die Extension Library verwenden, aber am Programmanfang Extension_Init vergessen haben). Bitte nicht ausprobieren, da dies mit ziemlicher Sicherheit zum Absturz Ihres Computers führt.

Damit der Debugger all diese Aufgaben erfüllen kann, wird eine Tabelle angelegt, die eine Beziehung herstellt zwischen dem Quellcode und dem vom Compiler erzeugten Objektcode. Darum kann das Programm während der Debuggingphase nicht editiert werden. Denken Sie also nicht, dass Ihr Computer abgestürzt ist, weil Sie plötzlich nichts mehr an Ihrem Programm ändern können.

Nach der Compilierung wird das Programm automatisch gestartet. Wegen des zusätzlichen Verwaltungsaufwands laufen die mit 'Debuggen' erzeugten Programme etwas langsamer, als wenn man den Menüpunkt 'Compilieren & Starten' verwendet. Das sollte bei der Fehlersuche aber keine Rolle spielen.

Hinweis: Wenn Sie mit der Lite-Version oder gar der Demo-Version arbeiten, kann es passieren, dass sich ein Programm zwar normal compilieren, aber nicht debuggen lässt. Dies liegt daran, dass im Debugmodus zusätzlicher Objectcode erzeugt wird, so dass das compilierte Programm zu lang wird für die Lite-Version bzw. die Demo-Version.


Nachdem Ihr Programm vom Debugger gestartet wurde, öffnet sich ein kleines Fenster mit der Debuggersteuerung. Das Fenster enthält 7 Buttons, mit denen Sie den Ablauf Ihres Programms beeinflussen können. Im einzelnen gibt es die folgenden Steuerungsmöglichkeiten.


[Anhalten]
Wenn Sie auf diesen Knopf klicken, wird Ihr Programm sofort angehalten. Dabei scrollt das Fenster mit dem Quellcode automatisch an die Stopstelle, die durch ein kleines Dreieck markiert wird. Diese Funktion kann auch durch [Ctrl]+[C] ausgelöst werden.

Achtung: Wenn Ihr Programm keine regelmässigen COMPILER "EVENT" oder EasyMesag Aufrufe (im Falle einer Programmierung mit EasyGem) macht, können Sie das Programm nur mit [Ctrl]+[C] anhalten.


[Fortsetzen]
Dieser Button ist nur anwählbar, wenn ein Programm angehalten wurde. Wenn Sie auf diesen Knopf klicken, wird die Programmausführung mit dem Befehl, auf den das kleine Dreieck zeigt, wieder fortgesetzt.


[Eintreten]
Dieser Button ist nur anwählbar, wenn ein Programm angehalten wurde. Wenn Sie auf diesen Knopf klicken, wird nur ein Befehl, nämlich der, auf den das kleine Dreieck zeigt, ausgeführt. Handelt es sich dabei um einen Prozedur- oder Funktionsaufruf, so springt der Programmzeiger in die Prozedur oder Funktion. Gleiches gilt auch für GOSUB Befehle. Bei Funktionen ist ausserdem zu beachten, dass diese auch in Formeln vorkommen können. In diesem Fall wird in alle Funktionen eingetreten, die in der Formel vorkommen.
Wenn die Prozedur oder Funktion von einer Library zur Verfügung gestellt wird, so tritt der Debugger nicht in das Unterprogramm ein. Dies wäre ja auch nicht sinnvoll, da der Programmcode in der Library nicht gelistet wird und Sie dadurch den Programmverlauf ohnehin nicht verfolgen könnten.

Hinweis: Einige Library-Befehle verwenden Callback-Funktionen, die Sie selbst definieren müssen und die sich daher nicht in der Library befinden (z.B. Uwin_Open aus der EasyGem Library). Wenn Sie jetzt Library-Befehle mit Eintreten aufrufen, springt der Programmzeiger zwar nicht in die Library, kann aber in Ihrer Callback-Routine landen, wenn diese gerade von der Library aus aufgerufen wird.
Wenn Sie nicht gerade genau dieses beabsichtigen, sollten Sie besser den Button [Einzelschritt] verwenden, um solche Verwirrungen zu vermeiden.


[Austreten]
Dieser Button ist nur anwählbar, wenn ein Programm angehalten wurde. Er dient dazu, eine Prozedur oder Funktion zu verlassen, ohne vorher alle innerhalb der Prozedur oder Funktion befindlichen Befehle in Einzelschritten auszuführen. Genauer gesagt wird die Programmausführung fortgesetzt, bis der Debugger auf ein RETURN, END_PROC, END_FN oder EXIT stösst, das sich in der gleichen Hierarchieebene befindet, in der der Programmzeiger war, als dieser Button angeklickt wurde.
Nach Anwahl dieses Knopfes steht der Programmzeiger also direkt hinter dem Befehl, mit dem die Prozedur oder Funktion aufgerufen wurde. Entsprechendes gilt auch, wenn Unterprogramme über GOSUB Befehle aufgerufen werden.

Hinweis: Wenn Sie diesen Button benutzen, während sich der Programmzeiger nicht in einem Unterprogramm befindet, hat er die gleiche Wirkung wie [Fortsetzen] , da sich auf der obersten Hierarchieebene keine RETURN Befehle befinden.


[Einzelschritt]
Dieser Button ist nur anwählbar, wenn ein Programm angehalten wurde. Die Funktion ähnelt der des Buttons [Eintreten], mit dem Unterschied, dass Unterprogrammaufrufe immer wie BASIC-Befehle interpretiert werden, also niemals in Unterprogrammen angehalten wird.


[Animation]
Dieser Button ist nur anwählbar, wenn ein Programm angehalten wurde. Damit lässt sich eine Programmfortsetzung in Zeitlupe erreichen. In der Standardeinstellung sorgt der Debugger dafür, dass maximal ein Befehl pro Sekunde ausgeführt wird. Dieses Intervall lässt sich über die Dialogbox 'Debuggereinstellungen' aber auch verändern.


[Beenden]
Dieser Button ist immer anwählbar. Mit ihm können Sie das vom Debugger kontrollierte Programm jederzeit beenden. Damit schliesst sich auch automatisch das Fenster für die Debuggersteuerung.



Achtung: Einige Omikron Basic Befehle warten auf Eingaben des Benutzers, bevor das Programm fortgesetzt wird. Da der Debugger ein Programm nur zwischen zwei Befehlen unterbrechen kann, nicht aber sozusagen mitten auf einem Befehl, wird in diesen Fällen ein Debuggerkommando erst wirksam, wenn der Befehl beendet wurde.
Im einzelnen sind dies die Omikron Basic Befehle INPUT, LINE INPUT, FORM_ALERT und FILESELECT bzw. FSEL INPUT sowie die EasyGem Befehle Easy_Alert, Easy_Fsel, Easy_Fnav und Pick_Color.
Wenn sich Ihr Programm z.B. in einer INPUT Anweisung befindet und Sie auf [Beenden] klicken, wird das Programm erst beendet, nachdem der Anwender die Input-Anweisung mit [Return] verlassen hat.


STOP Befehle und Breakpoints

Wenn Sie Ihr Programm über die Debuggersteuerung anhalten, ist es weitgehend vom Zufall abhängig, an welcher Stelle das Programm stoppt. Darum gibt es zwei weitere Möglichkeiten, ein Programm gezielt an einer bestimmten Stelle zu unterbrechen.

STOP Befehl
Noch bevor Sie Ihr Programm mit 'Debuggen' starten, fügen Sie einfach einen STOP Befehl an der Stelle ein, an der das Programm anhalten soll. Vielen, die früher mit BASIC-Interpretern gearbeitet haben, dürfte diese Methode bekannt vorkommen. Der STOP Befehl hält ein Programm an, ohne Variablen und Speicherinhalte zu löschen. Danach können Sie mit der Debuggersteuerung das Programm gezielt fortsetzen.

Achtung: Der STOP Befehl funktioniert nur, wenn das Programm mit 'Debuggen' gestartet wurde. Bei einem normal compilierten Programm führt der STOP Befehl zu einer Fehlermeldung mit anschliessender Beendigung des Programms.


Breakpoints
Breakpoints sind zusätzliche Unterbrechungspunkte, die Sie in Ihr Programm einfügen können. Im Unterschied zu STOP Befehlen können Breakpoints erst gesetzt werden, nachdem das Programm mit 'Debuggen' gestartet wurde. Toppen Sie dazu das Fenster mit dem Quellcode und klicken Sie einfach bei gedrückter [Ctrl] Taste auf die Stelle im Quellcode, an der ein Breakpoint gesetzt werden soll. Es erscheint eine kleine Ellipse in der Farbe der Kommentarzeilen. Sobald nun der Programmzeiger Ihres Programms über diese Stelle läuft, wird das Programm angehalten und Sie können wieder mit der Debuggersteuerung eine gezielte Analyse vornehmen. Durch nochmaligen Klick auf einen Breakpoint wird dieser wieder entfernt.
Sie können praktisch beliebig viele dieser Breakpoints setzen. Im Unterschied zu STOP Befehlen sind Breakpoints nur während einer Debuggingphase wirksam. Nach Beendigung des Programms werden Sie automatisch gelöscht. Sie können auch nicht gespeichert oder auf das Clipboard kopiert werden. Wenn Sie dauerhafte Breakpoints in Ihr Programm einbauen möchten, müssen Sie dafür den STOP Befehl verwenden.

Hinweis: Nicht an jeder Stelle eines Programms kann man einen Breakpoint setzen, da z.B. Kommentarzeilen vom Compiler ausgelassen werden und einige BASIC-Befehle nur zur Strukturierung dienen, aber keinen Objektcode erzeugen. In diesen Fällen erscheint der Breakpoint an der nächsten möglichen Programmstelle vor der Position, auf die Sie geklickt haben.

Achtung: Wenn Sie die EasyGem Library verwenden oder eine eigene Event-Handling Routine programmiert haben, kann Ihr Programm den Inhalt von Fenstern nicht restaurieren, wenn es vom Debugger angehalten wurde.
Dies gilt nicht für Omikron Basic Ausgabefenster. Diese werden nämlich von einem kleinen Assembler-Programm verwaltet, das auch dann weiterläuft, wenn das BASIC Programm vom Debugger angehalten wurde.


Speicherfenster

Speicherfenster können Sie über den gleichnamigen Menüpunkt aus dem 'Programm' Menü öffnen. Mit Speicherfenstern können Sie sich den Inhalt des RAM-Speichers ansehen.
In der linken oberen Ecke des Fensters befindet sich eine Eingabezeile, mit der Sie festlegen können, ab welcher logischen Adresse der Speicherinhalt angezeigt werden soll. Die Adresse können Sie mit einem Prefix davor in allen von Omikron Basic unterstützten Zahlensystemen angeben (z.B. $A6553 oder 123456). Durch drücken von [Return] wird der Speicherinhalt ab der angegebenen Adresse angezeigt.
Falls der angegebene Speicherbereich nicht existiert, erhalten Sie eine Fehlermeldung und es wird nichts angezeigt.
Die Art der Anzeige können Sie über die Debuggereinstellungen weitgehend beeinflussen.


Variablenfenster

In ein Variablenfenster können Sie die Namen von Variablen eingeben, deren Inhalt dann angezeigt wird. Bei Stringvariablen wird zusätzlich dahinter noch die Länge des Strings angegeben.
Für die Indizes von Feldvariablen dürfen dabei nur Konstanten oder Einzelvariablen verwendet werden (z.B. A#(X,Y) oder A#(1,3)). Solange ein Programm nicht mit 'Debuggen' gestartet wurde, ist der Inhalt von Variablen natürlich 0 bzw. bei Strings der Leerstring.
Das Zahlensystem, in dem der Variableninhalt angezeigt werden soll, können Sie durch ein Prefix festlegen. So würde z.B. die Eingabe $Tex$ den Inhalt des Strings Tex$ nicht als Zeichenkette, sondern als Bytefolge in Hexzahlen ausgeben. Ähnlich ergäbe %A den Inhalt der Variablen A als Binärzahl. Standardmässig erfolgt die Ausgabe von numerischen Variablen immer als Dezimalzahl und von Strings immer als Zeichenkette. Bei Strings kann man durch Voranstellen eines Nummernzeichens "#" auch eine Ausgabe als dezimale Bytefolge bewirken. Dies ist besonders interessant, wenn man sich für die ASCII-Werte eines Strings interessiert.
In Variablenfenstern funktionieren auch Blockfunktionen. Statt die gewünschten Variablen einzutippen, können Sie diese auch aus dem Programmfenster mit 'Kopieren' und 'Einsetzen' in das Variablenfenster übertragen.
Ausserdem können Variablenfenster gespeichert, wieder geladen oder ausgedruckt werden. Die Speicherung erfolgt dabei im ASCII-Fomat. Bei erneutem Laden werden die Variablen dem gerade oben befindlichen Programmfenster zugeordnet.
Falls eine Variable nicht existiert oder ein Feldelement nicht im dimensionierten Bereich liegt, wird die Zeile als Fehlerzeile (rot in der Standardeinstellung) markiert.
Ein Variablenfenster bezieht sich immer auf ein bestimmtes Programmfenster. Wird dieses geschlossen, so werden automatisch auch alle damit verknüpften Variablenfenster geschlossen, da die darin enthaltenen Variablen ja jetzt gar nicht mehr definiert sind.
Auch für Variablenfenster lassen sich im Dialog Debuggereinstellungen Änderungen vornehmen.


Debuggereinstellungen

Natürlich ist es auch möglich, alle wichtigen Funktionen des Debuggers individuell zu konfigurieren. Den dafür vorgesehenen Dialog finden Sie im Modus-Menü unter 'Einstellungen > Allgemein/Debugger'. Eine genaue Beschreibung dieses Dialogs befindet sich in Kapitel 3, Debugger. Die Dialogbox kann während der Arbeit mit dem Debugger geöffnet bleiben, so dass Sie z.B. während eines laufenden Animationsprozesses die Animationsgeschwindigkeit ändern können.


Fehlermeldungen des Debuggers

Das Programm "Programmname" wurde unerwartet beendet.
In einigen Fällen kann es vorkommen, dass das zu debuggende Programm auf unkontrollierte Weise spantan beendet wird. In diesen Fällen kann keine Nachricht mehr an den Debugger geschickt werden, so dass dieser von dem Ende nichts erfährt. Wenn Sie nun trotzdem versuchen, Debuggerbefehle auf das nicht mehr laufende Programm anzuwenden, erhalten Sie diese Fehlermeldung.


Der adressierte Speicherbereich existiert nicht.
Diese Fehlermeldung erscheint, wenn Sie versuchen in einem Speicherfenster einen Speicherbereich anzuzeigen, der gar nicht vorhanden ist.


Praktische Beispiele

Nachdem wir nun alle Komponenten des Debuggers beschrieben haben, wollen wir anhand einiger Beispiele zeigen, wie man den Debugger benutzt. Die Beispielprogramme sind mit Zeilennummern versehen, um besser auf bestimmte Zeilen Bezug nehmen zu können. Für den Programmablauf sind die Zeilennummern nicht erforderlich. Alle Variablen ohne Postfix sind vom Typ Long-Integer, wie es der Defaulteinstellung des Omikron Basic Editors entspricht. Wenn Sie diese Einstellung verändert haben, müssen Sie dies beim Übertragen des Programmcodes berücksichtigen.
Die hier aufgelisteten Beispielprogramme befinden sich auch im Ordner DEMO:Debugger (Demo)


Beispiel 1:

Öffnen Sie jetzt ein neues Programmfenster und übertragen Sie das folgende Programm mit 'Kopieren' und 'Einsetzen' in das leere Programmfenster. In das Beispiel 1 haben wir einen Fehler eingebaut, den wir nun mit dem Debugger finden wollen.

0 'Dieses Programm berechnet alle Primzahlen, die kleiner
1 'als 121 sind. Die verwendete Methode ist auch als Sieb
2 'des Eratosthenes bekannt. Dazu müssen alle Primzahlen,
3 'die kleiner als 11=SQR(121) sind, schon bekannt sein.
4 'Dies sind die Zahlen 2,3,5,7, die in der DATA-Zeile
5 'gespeichert sind und zu Beginn in das Feld Primes()
6 'eingelesen werden. Für die Zahlen von 11 bis 120 genügt
7 'es dann, diese nur noch auf Teilbarkeit durch eine dieser
8 '4 Primzahlen zu untersuchen. Ist eine Zahl teilbar, so
9 'wird ein Flag in dem Feld No_Prime%F() gesetzt und die
10 'Zahl auf dem Bildschirm invertiert dargestellt. Am Ende
11 'sind alle Zahlen, die nicht invertiert wurden, die
12 'gesuchten Primzahlen.
13
14 COMPILER "PRE_SIZE 500000"
15 COMPILER "BAS_MEM 500000"
16 COMPILER "OPW 340*240"
17 COMPILER "warnings off"
18
19 Prim_Dim=120:P_Dim=3
20 DIM Primes(P_Dim),No_Prime%F(Prim_Dim)
21 RESTORE Prime_Numbers:'Alle Primzahlen < 11 = SQR(121) einlesen.
22 FOR J=0 TO 2:READ Primes(J):NEXT J
23 USING "####":Columns=10:Lines=12
24 'Startzahl, Endzahl, Reihen, Spalten
25 Display_Numbers 2,Prim_Dim,Columns,Lines
26 PRINT CHR$(27)+"p";:'Revers ein.
27 X=1:Y=0
28 'Testen ob die Zahlen von 2 bis Prim_Dim durch
29 'die Primzahlen < 11=SQR(121) teilbar sind.
30 FOR I=2 TO Prim_Dim
31
 FOR J=0 TO 3
32
  IF I<>Primes(J) THEN
33
   'Nur Zahlen untersuchen, die nicht schon als Primzahlen
34
   'bekannt sind.
35
   IF I MOD Primes(J)=0 THEN
36
    'Zahl revers drucken, keine Primzahl.
37
    No_Prime%F(I)=-1:PRINT @(Y,X);MID$(STR$(I),2)
38
    EXIT :'Da I keine Primzahl ist, brauchen die anderen
39
    'Teiler nicht mehr getestet zu werden.
40
    ENDIF
41
  ENDIF
42
 NEXT J
43
 X+=4:IF (I-1) MOD Columns=0 THEN Y+=1:X=1:'Nächste Zeile.
44 NEXT I
45 REPEAT COMPILER "EVENT" UNTIL 0
46 END
47
48 -Prime_Numbers:'Die ersten 4 Primzahlen.
49 DATA 2,3,5,7
50
51 'Diese Prozedur schreibt die Zahlen von Z0 bis Z1 in einem
52 'rechteckigen Schema mit C Spalten und L Zeilen auf den Bildschirm.
53 DEF PROC Display_Numbers(Z0,Z1,C,L)
54
 LOCAL I,J
55
 CLS
56
 FOR J=0 TO L-1
57
  FOR I=0 TO C-1
58
   PRINT Z0;:Z0+=1
59
   IF Z0>Z1 THEN EXIT
60
  NEXT I
61
  PRINT :IF Z0>Z1 THEN EXIT
62
 NEXT J
63 END_PROC

Starten Sie das Programm zunächst mit 'Compilieren & Starten'. Das Programm soll die Primzahlen zwischen 11 und 120 berechnen, wobei angenommen wird, dass die Primzahlen < 11 schon bekannt sind. Wie Sie sehen, läuft das Programm normal und ohne irgendeine Fehlermeldung ab, rechnet aber falsch, denn die Zahl 49 wird als Primzahl markiert, obwohl sie durch 7 teilbar ist.

Beenden Sie das Programm und starten Sie es nochmal über den Menüpunkt 'Debuggen'. Das Programm stoppt jetzt in Zeile 35 und gibt die Fehlermeldung "Integer-Überlauf" aus. Klicken Sie auf [OK]. Sie befinden sich jetzt im Debugger. Die Position, an der das Programm angehalten wurde, ist durch ein kleines Dreieck markiert.
Um nun herauszufinden, worin der Fehler besteht, öffnen Sie ein neues Variablenfenster. Geben Sie in das Fenster I, J und Primes(J) ein, wobei Sie hinter jeder Eingabe [Return] drücken, so dass die Variablen in verschiedenen Zeilen erscheinen. Wie Sie sehen, hat I den Startwert 2, J den Endwert 3 und Primes(J)=0, so dass die Operation I MOD Primes(J) nicht definiert ist und zu dem "Integer-Überlauf" führt.
Ein Blick auf Zeile 22 zeigt, dass in der READ Schleife ein falscher Endwert für die Laufvariable J angegeben ist (2 statt 3).
Klicken Sie nun auf [Beenden] in der Debuggersteuerung. Fügen Sie danach in Zeile 18 einen STOP Befehl ein und korrigieren Sie den falschen Endwert in Zeile 22 (2 in 3 ändern).
Danach starten Sie das Programm wieder mit 'Debuggen'. Das Programm wird jetzt direkt hinter dem STOP Befehl angehalten. Im Variablenfenster wird Primes(J) als Fehlerzeile dargestellt. Dies liegt daran, dass dieses Feld noch nicht dimensioniert wurde. Gehen Sie jetzt in Einzelschritten voran, indem Sie in der Debuggersteuerung auf [Einzelschr.] klicken. Nachdem der DIM Befehl in Zeile 20 ausgeführt wurde, wird Primes(J)=0 korrekt im Variablenfenster angezeigt. Wenn Sie jetzt in Einzelschritten die READ Schleife abarbeiten, können Sie im Variablenfenster verfolgen, wie die Primzahlen nacheinander in das Feld Primes() eingelesen werden. Am Ende der Schleife wird Primes(J) wieder als Fehler dargestellt, da J jetzt 4 ist und Primes(J) nur bis 3 dimensioniert wurde.

Wenn Sie in Zeile 25 angekommen sind, können Sie entscheiden, ob Sie die Prozedur Display_Numbers mit [Einzelschr.] wie einen Befehl ausführen wollen oder ob Sie mit [Eintreten] in die Prozedur hineinspringen wollen. Um die Funktionen des Debuggers zu demonstrieren, entscheiden wir uns hier für [Eintreten].
Da in der Prozedur Display_Numbers PRINT Ausgaben in das Omikron Basic Ausgabefenster gemacht werden, sollten Sie das Programmfenster so zur Seite schieben, dass Sie das Ausgabefenster sehen können.
Sie könnten jetzt natürlich in Einzelschritten alle Befehle in der Prozedur einzeln ausführen, da hier aber nichts spektakuläres passiert, wollen wir die Gelegenheit nutzen, eine weitere Funktion des Debuggers zu demonstrieren. Klicken Sie dazu auf Animation. Der Debugger führt jetzt alle Befehle in Zeitlupe aus. Dabei können Sie verfolgen, wie der Programmzeiger sich durch die beiden Schleifen arbeitet und dabei die Zahlen in das Omikron Basic Ausgabefenster geschrieben werden. Wenn Sie genug gesehen haben, klicken Sie auf [Anhalten]. Das Programm stoppt an der aktuellen Stelle. Wenn Sie jetzt auf [Austreten] klicken, werden alle Befehle innerhalb der Prozedur ausgeführt und das Programm erst wieder hinter dem Prozeduraufruf, also in Zeile 26 angehalten.

Halten Sie jetzt die [Ctrl] Taste gedrückt und klicken Sie mit der Maus auf das FOR in Zeile 31. Dadurch wird vor das FOR ein Breakpoint gesetzt, der als Ellipse dargestellt wird. Klicken Sie jetzt auf [Fortsetzen]. Der Programmzeiger stoppt genau auf dem Breakpoint. Wenn Sie jetzt wiederholt auf [Fortsetzen] klicken, können Sie verfolgen, wie jede einzelne Zahl daraufhin untersucht wird, ob es sich um eine Primzahl handelt. Dabei können Sie im Variablenfenster die Werte von I und der anderen Variablen verfolgen und im Omikron Basic Ausgabefenster sehen, wie einzelne Zahlen als Nicht-Primzahlen markiert werden.
Halten Sie jetzt wieder die [Ctrl] Taste gedrückt und klicken Sie auf den Breakpoint in Zeile 31. Der Breakpoint wird wieder entfernt. Setzen Sie einen neuen Breakpoint in Zeile 43 hinter das THEN. Klicken Sie danach auf [Fortsetzen]. Das Programm stoppt jetzt immer dann, wenn eine neue Zeile begonnen wird.
Entfernen Sie den Breakpoint wieder und klicken Sie auf [Fortsetzen]. Es werden jetzt alle Nicht-Primzahlen markiert und das Programm befindet sich danach in der Warteschleife in Zeile 45.

Klicken Sie jetzt auf [Anhalten]. Das Programm stoppt in der Warteschleife. Das funktioniert nur, weil in der Warteschleife ein EVENT Aufruf steht (COMPILER "EVENT" bzw. Easy_Mesag bei EasyGem Programmierung). Wenn sich Ihr Programm in einer Schleife befindet, in der keine EVENT Aufrufe gemacht werden, können Sie es aber immer noch mit [Ctrl] +[C] anhalten.

Klicken Sie jetzt auf [Beenden]. Eratosthenes wird beendet, die Debuggersteuerung verschwindet und Sie können den Quellcode wieder editieren, um z. B. weitere Primzahlen zu berechnen.


Beispiel 2:

Das zweite Beispiel enthält keinen Fehler und dient nur dazu, die Debuggerfunktionen weiter zu erläutern. Öffnen Sie zunächst wieder ein neues Programmfenster und übertragen Sie den Programmcode mit 'Kopieren' und 'Einsetzen' in das Fenster. Danach müssen Sie noch mit dem Menüpunkt 'LIBRARY zuladen' aus dem 'Bearbeiten' Menü die Extension Library zuladen.

0 'Dieses Programm berechnet die relativen Häufigkeiten der Zahlen
1 'von 0 bis 35, wie sie bei einem Roulette-Spiel vorkommen. Dazu
2 'wird zu Demonstrationszwecken zunächst mit einem Zufallsgenera-
3 'tor ein Datensatz erzeugt und in die Datei "RouletteData" ge-
4 'schrieben.
5 'Danach wird die Datei wieder geladen und statistisch ausgewertet.
6 'In der Realität müsste man natürlich die tatsächlich ausgespiel-
7 'ten Zahlen eines realen Roulette-Tisches als Datensatz verwenden,
8 'um dann über die statistische Auswertung herauszufinden, ob durch
9 'mechanische Inhomogenitäten des Gerätes bestimmte Zahlen häufiger
10 'gezogen werden als andere.
11 'Bevor Sie jetzt Ihr ganzes Geld verspielen, sollten Sie aber be-
12 'denken, dass bei nur 10000 Zahlen die statistische Schwankungs-
13 'breite noch recht gross ist ;-)
14
15 COMPILER "PRE_SIZE 1000000"
16 COMPILER "BAS_MEM 500000"
17 COMPILER "OPW 200*560"
18 COMPILER "warnings off"
19
20 Extension_Init
21 STOP
22 Items=35:Max_Numbers=10000
23 Generate_Data Items,Max_Numbers
24 'Ab hier beginnt die Auswertung der Daten.
25 DIM Quantity(Items)
26 'Daten zunächst einlesen.
27 OPEN "U",1,FN Get_Fsspec$(0,0,"RouletteData")
28 Max_Numbers=LOF(1)
29 Adr=MEMORY(Max_Numbers)
30 'Den ganzen Dateiinhalt in einen Speicherbereich übertragen.
31 GET 1,Adr,Max_Numbers
32 CLOSE 1
33 'Statistische Auswertung.
34 FOR Ptr=Adr TO Adr+Max_Numbers
35
 N=PEEK(Ptr)
36
 Quantity(N)+=1
37 NEXT Ptr
38
39 Set_Print_Size 12
40 PRINT "Relative Häufigkeit der"
41 PRINT "Roulettezahlen in Prozent"
42 PRINT
43 PRINT " Zahl";TAB(10);"Häufigkeit"
44 Set_Print_Size 10
45 FOR N=0 TO Items
46
 P#=100*Quantity(N)/Max_Numbers:'Relative Häufigkeit.
47
 PRINT USING "#####";N;TAB(10); USING "#####.##";P#
48 NEXT N
49
50 REPEAT COMPILER "EVENT" UNTIL 0
51 END
52
53 'Diese Prozedur erzeugt einen zufälligen Datensatz
54 'und schreibt ihn anschliessend in die Datei "RouletteData"
55 DEF PROC Generate_Data(N,M)
56
 LOCAL Adr,Ptr
57
 Adr=MEMORY(M)
58
 FOR Ptr=Adr TO Adr+M
59
  POKE Ptr,RND(N+1)
60
 NEXT Ptr
61
 OPEN "U",1,FN Get_Fsspec$(0,0,"RouletteData")
62
 'Den Datensatz als Ganzes in eine Datei schreiben.
63
 PUT 1,Adr,M
64
 CLOSE 1
65
 FRE Adr
66 END_PROC

Starten Sie das Programm jetzt mit 'Debuggen'. Wie zu erwarten stoppt es in Zeile 22, direkt hinter dem STOP Befehl. Gehen Sie nun mit [Eintreten] voran, bis Sie in Zeile 58 angekommen sind. Öffnen Sie jetzt ein neues Variablenfenster und geben Sie dort $Adr ein. Nach Drücken der [Return] Taste wird die Adresse des in Zeile 57 angeforderten Speicherblocks als Hexzahl im Variablenfenster angezeigt.
Öffnen Sie jetzt ein neues Speicherfenster und danach die Debuggereinstellungen über 'Modus/Editoreinstellungen/Debugger'. Stellen Sie in dem sich öffnenden Dialog 'Bytes pro Gruppe' auf 1, 'Bytes pro Zeile' auf 8, 'Bytes anzeigen in' auf dezimal und 'Zeichenkette anzeigen' auf aus. Klicken Sie danach auf [Ausführen]. Der Inhalt des Speicherfensters wird jetzt in Form von 3-stelligen Dezimalzahlen angezeigt. Die Anzeige als Zeichenkette verschwindet. Übertragen Sie jetzt den Wert, der für Adr im Variablenfenster angezeigt wird, mit 'Kopieren' und 'Einsetzen' in das Adressfeld des Speicherfensters und bestätigen Sie mit [Return].
Wenn Sie jetzt in Einzelschritten weiter durch das Programm gehen, können Sie im Speicherfenster verfolgen, wie die Zufallszahlen in den Speicher geschrieben werden.
Gehen Sie jetzt wieder in die Debuggereinstellungen und stellen Sie die 'Verzögerung bei Animation' auf 100. Danach mit [Ausführen] bestätigen. Sorgen Sie dafür, dass das Speicherfenster und das Fenster mit dem BASIC-Programm sichtbar sind und klicken Sie dann auf [Animation] in der Debuggersteuerung. Sie können jetzt beobachten, wie die Zufallszahlen im Zehntelsekundentakt in den Speicher geschrieben werden.
Wenn Sie genug gesehen haben, klicken Sie auf [Anhalten] und danach auf [Austreten]. Damit verlassen Sie die Prozedur und befinden sich danach hinter dem Aufruf in Zeile 25.

Setzen Sie jetzt einen Breakpoint in Zeile 39, indem Sie bei gedrückter [Ctrl] Taste mit der Maus vor Set_Print_Size klicken und danach das Programm fortsetzen. Das Programm stoppt in Zeile 39. Klicken Sie jetzt auf [Eintreten]. Obwohl als nächstes eine Prozedur ausgeführt wird, springt der Programmzeiger in die nächste Zeile, weil sich die Prozedur Set_Print_Size in einer Library befindet.

Holen Sie jetzt das Omikron Basic Ausgabefenster nach oben. Klicken Sie danach auf [Animation]. Sie können jetzt verfolgen, wie die statistischen Daten ins Omikron Basic Ausgabefenster geschrieben werden.


Beispiel 3:

Bei diesem Beispiel handelt es sich um ein ganz einfaches Programm, mit dem man aber leicht anzeigen kann, welche Werte von MOUSEBUT und INKEY$ zurückgegeben werden, wenn man bestimmte Tasten drückt. Öffnen Sie zunächst wieder ein neues Programmfenster und übertragen Sie den Programmcode mit 'Kopieren' und 'Einsetzen' in das Fenster.

0 COMPILER "PRE_SIZE 500000"
1 COMPILER "BAS_MEM 500000"
2 COMPILER "OPW 320*200"
3 COMPILER "warnings off"
4
5 REPEAT
6
 Mb=MOUSEBUT
7
 Kbrd$=INKEY$
8
 COMPILER "EVENT"
9 UNTIL 0
10 END

Gehen Sie in die Debuggereinstellungen und schalten Sie 'Variablenfenster permanent aktualisieren' an. Klicken Sie danach auf [Ausführen]. Öffnen Sie jetzt ein neues Variablenfenster und tragen Sie dort die Variablen %Mb und %Kbrd$ ein.

Starten Sie das Programm jetzt mit 'Debuggen'. Wenn Sie jetzt die Maustaste alleine oder in Verbindung mit irgendwelchen Modifier-Keys drücken, können Sie im Variablenfenster sofort verfolgen, welche Bits dabei gesetzt werden. Entsprechendes gilt für die normalen Tasten des Keyboards. Die dabei erzeugten ASCII-Codes, Virtual-Key-Codes und Modifier-Key-Codes werden in Kbrd$ angezeigt.

10. Der Library Maker Inhaltsverzeichnis

Support | Bestellen | Start | Home: http://www.berkhan.de


© 1997-2001 Berkhan-Software