Magic Disk 64

home to index to text: KURS-BASICKURS.txt
     BASIC-Kurs : "Von Adam und Eva..." (Teil 1)     
     

Sehr geehrter Leser, pünktlich zum Anfang des neuen Jahres möchten wir uns gleich an unsere guten Vorsätze für 1989 halten, und unser Versprechen einlösen, die Anfänger unter Ihnen nicht zu kurz kommen zu lassen. Sie lesen nämlich im Moment gerade die ersten einleitenden Zeilen unseres neuen BASIC-Kurses für Einsteiger. Wie der Name dieses Kurses schon vermuten läßt, wollen wir ganz am Anfang beginnen, so daß auch der, der noch überhaupt keine Ahnung von der Programmierung eines Computers hat, von Adam und Eva an alles schön mitverfolgen kann.
Beginnen wir nun mit der Frage nach dem WARUM. Warum BASIC? Nun, BASIC ist die Abkürzung für " Beginners Allpurpose Symbolic Instruction Code", was frei übersetzt etwa " Universeller Befehlscode mit Symbolwörtern für Anfänger" bedeutet. Und dies sagt uns schon fast alles über den Grund und die Aufgabe von BASIC aus, denn man wollte mit BASIC eine Computersprache erschaffen, mit der jeder normale Mensch, der etwas Englisch versteht und logisch denken kann, einen Computer programmieren kann. Zu früheren Zeiten, als das, was heute in einem zündholzkopfgroßen Mikrochip untergebracht ist noch ganze Räume und Gebäude ausfüllte, war die Programmierung von Computern noch äußerst kompliziert, und bestand meist darin, nichtsaussagende, trockene Zahlenreihen von der Art 0101000110101 . . . in die sage und schreibe 1 KiloByte großen Hauptspeicher der damaligen Rechner regelrecht " hineinzumorsen" . Da dies eine sehr mühsame und langwierige Arbeit war entwickelte man mit der Zeit immer mehr Computersprachen, die auf Grund der immer höher werdenden Leistungsfähigkeit der Computer immer komfortabler und benutzerfreundlicher wurden, so daß das Programmieren eine leichte Sache wurde. BASIC stellt wohl so eine Art Endstufe dieser Entwicklung dar, was zumindest die Einfachheit der Programmierung betrifft. Heutzutage ist ehrlich gesagt fast jede Sprache leistungsfähiger als BASIC, doch die meisten noch lange nicht so einfach zu erlernen. Diese Sprache eignet sich außerdem hervorragend für Anfänger die Funktionsweise und den Bau eines Computers zu erler- nen und gibt eine unverzichtbare Grundlage für andere, schnellere Programmiersprachen. Deshalb wollen wir nun endlich beginnen und einmal einen Blick auf die einfachsten, trotzdem aber häufig benutzten BA-SIC- Befehle werfen. . .
Leider ist es nicht so einfach einen Kurs mit kleinen Beispielen zu gestalten, wenn Sie selbigen gerade auf Ihrem C64 lesen. Deshalb werde ich bei praktischen Beispielen in Zukunft so tun, als säßen Sie gerade nicht vor der MAGIC DISK 64, sondern nur vor einem eingeschalteten Computer, der auf eine Eingabe wartet. Ich werde grundsätzlich das Ergebnis, das auf Grund einer Anweisung, die wir dem Computer eingegeben haben auf dem Bildschirm erscheinen sollte hier im Kurs aufzeigen, doch sollten Sie nicht davon Abschrecken, die aufgeführten Beispiele auch selbst einmal auszuprobieren ( wenn Sie fertig sind mit der MAGIC DISK 64), indem Sie sie sich ganz einfach aufschreiben, oder wenn ein Drucker vorhanden ist, einfach ausdrucken können.
Also: Bitte geben Sie einmal folgende Zeile in Ihren angeschalteten, auf eine Eingabe wartenden 64 er ein:

PRINT "DAS IST MEIN ERSTER AUSDRUCK !"               

Drücken Sie nun die RETURN-Taste. Auf dem Bildschirm erscheint nun folgendes :

DAS IST MEIN ERSTER AUSDRUCK !                       
READY.                                               

Das war doch schon mal ein Erfolgserlebnis! Fassen wir doch einmal zusammen, was passiert ist:
Sie haben eine Zeile eingegeben, an deren Anfang der Befehl " PRINT" stand. Anschließend gaben Sie in " Gänsefüßchen" oder " Anführungsstrichen" einen Text ein und haben die RETURN-Taste gedrückt. Nun ist unter Ihrer eingegebenen Zeile der Text, den Sie in Anführung hatten, ausgedruckt worden, und der Computer hat sich mit " READY." wieder zurückgemeldet.
Was ist genau geschehen? Nun, der PRINT-Befehl wird, wie Sie schon richtig erkannt haben, dafür benutzt um Texte auf dem Bildschirm auszugeben. Sie gaben also Ihre Zeile ein und signalisierten mit der RE-TURN- Taste dem Computer, daß Sie mit Ihrer Eingabe fertig sind und daß er Ihre Zeile bearbeiten soll.
Dieser erkannte die ersten 5 Buchstaben als einen PRINT-Befehl, druckte den anschließenden Text und meldete ordnungsgemäß mit " READY." seine Betriebsbereitschaft für weitere Befehle.
Sollte das oben beschriebene in Ihrem Fall nicht eingetreten sein, dann kann es nur sein, daß Sie einen Fehler bei der Eingabe gemacht haben. Sollte also jetzt anstatt unseres Textes die Zeilen:

?SYNTAX  ERROR                                       
READY.                                               

bei Ihnen auf dem Bildschirm stehen, so haben Sie sich wahrscheinlich beim Eingeben unseres Beispiels vertippt. Der Computer ist da sehr genau, denn er versteht nur einen bestimmten Befehlssatz, bezie- hungsweise kann er mit einigen Formulierungen oder Eingaben nichts anfangen, da er seine vorprogrammierten Befehlswörter zu erkennen versucht. Wenn man obige Fehlermeldung einmal in deutsche Übersetzt, wird einem das sogar noch etwas klarer: Syntaktischer Fehler. Zur Erläuterung, die Syntax einer Sprache ist die Art und Weise, wie diese grammatikalisch und vokabular aufgebaut ist. Sie haben sich also im Dialog mit Ihrem C64 sozusagen " versprochen", weshalb dieser Sie auch nicht verstand. Und wir möchten ja, daß Sie die Sprache BASIC " akzentfrei" sprechen können.
Keine Panik also, wenn der Computer bei Ihren ersten Gehversuchen Ihnen ein paar Errormeldungen in den Weg wirft. Sehen Sie sich Ihre Eingaben dann nochmal ganz genau an und Sie werden bestimmt die Ursache des Fehlers finden. Manchmal ist dies etwas schwieriger, da bei bestimmten Dingen die der Computer für Sie erledigen soll auch ganz spezielle Fehler auftreten können. Doch nicht verzagen, im C64 Bedienungshanbuch, Anhang L sind alle möglichen Fehlermeldungen zusammen mit Ihren Ursachen aufgelistet. Hier können Sie bei Bedarf Hilfe suchen.
Nun wieder zurück zu unserem PRINT-Befehl. Sollten Sie ein wenig Englisch können, werden Sie erkennen, daß dieser Befehl nicht umsonst so heißt. PRINT ist die Übersetzung für DRUCKE und sagt somit eigentlich alles aus, was dieser Befehl tut. Dies ist, wie Sie bald merken werden, bei allen BASIC-Befehlen so, so daß man sich diese sehr leicht merken kann, was ja auch der Sinn der Sache sein soll, damit ein leichtes Programmieren ohne lange Suche nach Befehlen gewährleistet ist.
Gehen wir nun aber etwas weiter. Langweilige Texte ausdrucken macht eh nicht soviel Spaß, zumal man ganze 7 Zeichen ( PRINT und 2 Mal ") mehr eingeben muß, will man einen Text ausdrucken. Doch der PRINT-Befehl ist noch zu viel mehr gut, denn immerhin hat man hier einen dicken Computer stehen, der solche kleinen Dinge, wie sie zum Beispiel ein Taschenrechner erledigt doch mit dem " kleinen Finger" bringt. Ja, mit PRINT können Sie rechnen, sei es, daß es Ihnen einen Text ausdruckt, oder das Ergebnis einer Addition. Die Syn-Syntax hierzu ist denkbar einfach:
PRINT 101+35 Dieser Befehl addiert die Zahlen 101 und 35 und druckt anschließend das Ergebnis auf dem Bildschirm aus:

 136                                                 
READY.                                               

Sie sehen, die Eingabe erfolgt genau wie bei Textausdrücken, nur daß Sie hier die Zahlen nicht in Anführungsstriche zu setzen brauchen, ja sie MÜSSEN Sie sogar weglassen, denn sonst meint der Computer, Sie möchten eine Zeichenkette ausdrucken, weshalb bei dem folgendem Befehl auch die folgende Reaktion des Computers zu erwarten ist:
PRINT "101+35"

101+35                                               
READY.                                               

Ich hoffe, daß Ihnen hiermit etwas klarer geworden ist, wie Sie zu unterscheiden haben :

             ⌈––––––––––––––––––––––––––⌉            
             |MIT  "" wird Text gedruckt|            
             |OHNE "" wird gerechnet.   |            
             ⌊––––––––––––––––––––––––––⌋            

Doch weiter mit der Rechnerei. Sie können ohne weiteres auch andere Rechenfunktionen verwenden. Die 4 Grundrechenarten möchte ich hier jetzt erwähnen, obwohl auch Wurzeln oder trigonometrische Funktionen für unseren C64 kein Problem darstellen, doch werde ich diesen Rechenfunktionen später noch ein eigenes Kapitel widmen. Im Moment reichen die folgenden vollkommen aus. Genau so, wie Sie bei "101+35" einen "+"- Operator eingestzt hatten, so ist dies auch bei der Subtraktion, Multiplikation und Division möglich, hierfür müssen Sie allerdings folgende Zeichen verwenden, um dem Computer klar zu machen, was Sie von Ihm wollen:

"+" - zum addieren                                   
"-" - zum subtrahieren                               
"*" - zum multiplizieren                             
"/" - zum dividieren                                 

Somit sind folgende Zeilen auch leicht denkbar :

PRINT 222*67                                         
PRINT 1000-100                                       
PRINT 81/9                                           

Probieren Sie es einmal aus, und experimentieren Sie mal ein wenig. Grundsätzlich gilt auch für andere Beispiele die ich geben werde, daß Sie ruhig auch einmal eigene Versuche machen können, um sich mit den neu erlenten Dingen in allererster Linie vertraut zu machen, denn wie heißt es so schön:" Probieren geht über studieren." zumal Sie mit Ihren Eingaben grundnichts an Ihrem Computer kaputt machen können, es sei denn, Sie versuchen die Tasten mit einem Hammer zu betätigen. . .
Bei Ihrer Rechnerei dürfen Sie sogar auch Kommazahlen verwenden. Hierbei müssen wir uns allerdings auch wieder ein wenig ans Englische anpassen, denn der Computer versteht auch Kommazahlen nur in englischer Schreibweise. Das normale Komma ist für einen anderen Zweck reserviert. Das heißt im Klartext, daß die Zahl"3,14" für unseren kleinen Siliziumfreund so aussehen muß:"3 .14" . Die Amerikaner benutzen grundsätzlich den Punkt als Dezimalkomma, und hieran müssen Sie sich gewöhnen. Richten Sie sich danach, dann machen Rechnungen wie die Folgende keine Probleme mehr :
PRINT 2*20*3 .14 Vielleicht haben Sie ja bemerkt, daß der Kreisumfang für einen Kreis mit dem Radius 20 cm ( oder m oder km) berechnet wurde. Denn gemäß der Kreisumfangsformel 2 mal Radius mal die Zahl Pi (π) haben wir hier die Zahl π mit der Dezimalzahl 3,14 dargestellt, nur mit einem Dezimalpunkt. Wie Sie sehen, können auch mehrere Rechenoperationen aneinander gehängt werden, wobei der Computer die allgemeingültige " Punktvor- Strich"- Regel natürlich ordnungsgemäß einhält. Das heißt, daß bei der Rechnung 20+3*100 das Ergebnis 320 herauskommt ( und nicht etwa 2300), da auf Grund dieser Regel die Multiplikation ( und auch die Division) Vorrang vor der Addition ( oder Subtraktion) hat.
Es wurde also folgendermaßen gerechnet:

1.) 3*100 (=300) 2.) 20+300 (=320)                   

Möchte man den anderen Weg benutzen, nämlich daß gerechnet wird:

1.) 20+3   (=23)                                     
2.) 23*100 (=2300)                                   

so muß man mit Klammern arbeiten, denn genau wie bei den allgemeinen algebraischen Rechenregeln auch, kann man mit Klammern die Prioritäten der einzelnen Rechnungen verändern. Wollen wir also 2300 herausbekommen, so müssen wir folgenden Befehl benutzen:
PRINT (20+3)*100 Anstelle von " PRINT 20+3*100", wobei nämlich 320 herauskäme.
Dies zum Rechnen mit PRINT. Doch müssen Sie schon zugeben, daß das, was wir hier taten, alles nichts " handfestes" war, zumal wir mit den errechneten Ergebnissen nicht weiterarbeiten konnten. Natürlich, Sie hatten diese nach Ihrer Rechnung dann auf dem Bildschirm stehen und konnten sie dann in einer neuen PRINT-Zeile weiterverarbeiten, doch dies wird sehr umständlich mit der Zeit. Angenommen Sie erhalten bei einer Rechnung folgendes Ergebnis:2 .75399753 . Jetzt müßten Sie diese Zahl nochmal gänzlich abtippen um Ihre Rechnung durchführen zu können. Doch wie Sie vielleicht bemerkten, beutzte ich soeben den Irrealis (" müssten"), das heißt, daß es noch eine andere Art der Rechnung gibt, eine bequemere Art, bei der das nochmalige Abtippen nicht mehr nötig ist. Ich spreche von dem Rechnen mit Variablen. Ich möchte mich nun ein klein wenig von der Rechnerei lösen, um Ihnen dieses äußerst wichtige Kapitel besonders verständlich darlegen zu können. Denn das Verständnis über Variablen ist die Vorraussetzung für BASIC ( und auch für die meisten anderen Hochsprachen) . Um Variablen dreht sich alles in BASIC, denn sie sind ein äußerst einfaches und praktisches Hilfsmittel. Wollen wir beginnen:
Falls Sie sich vielleicht noch ein wenig an die Schulzeit errinnern, oder vielleicht sogar noch Schüler sind, dann werden Sie sich bestimmt auch noch an Rechnungen mit Unbekannten und Variablen errinnern.
Gleichungen von der Art " y =2 x" dürften Ihnen dann nicht unbekannt sein. Genauso wie hier die Zeichen " x" und " y" Platzhalter für eine beliebige Zahl sind, so sind die Variablen gewissermaßen Platzhalter für unsere drei Datentypen." Gewissermaßen" deshalb, weil sie allgemein tatsächlich Platzhalter für Zahlen oder Texte sind, mit dem Unterschied, daß mit Ihrem Inhalt allerdings sofort gerechnet werden kann, dieser also nicht eher imaginär ist, so wie bei den mathematschen Variablen.
Um Ihnen dies noch ein wenig besser erläutern zu können, kann man Variablen auch mit Schubladen vergleichen ( wobei jede Schublade ihren eigenen Namen besitzt, mit dem man sie ansprechen kann) und in der jeweils bestimmte Dinge, beziehungsweise Daten enthalten sind. Möchte ich zum Beispiel einmal in die Schublade PI hineinschauen, so öffne ich sie und kann mir dann bei Bedarf den Zahlwert 3 .14159 dort herausholen.
Sie sehen also, daß das Ganze eigentlich äußerst einfach ist. Sie geben einer Variable einen Namen und sagen, was in Ihr enthalten ist. Wir sprechen hier von einer sogenannten Variablendefinition. Ab sofort brauchen Sie solche Werte dann nicht mehr von Hand hinzuschreiben, sondern brauchen nur noch anstatt der getippten Zahl in Ihrer Rechnung die entspechende Variable zu verwenden. Als kleines Beispiel möchte ich Ihnen einmal eine kleine Rechnung zeigen, bei der dies durchaus von Nutzen sein kann.
Angenommen, wir wollen die Oberfläche eines Zylinders berechnen. Die Formel, die man hierfür allgemein benutzt sieht folgendermaßen aus:
o=2 rπ( r+ h), wobei die Platzhalter ( oder neuerdings für uns die Variablen) folgende Bedeutung haben:
r = Radius der Zylindergrundfläche, h = Höhe des Zylinders,π nimmt hier eine Sonderstellung ein. Die Zahl PI müssen wir nämlich nicht mehr eingeben, Sie ist in Ihrem C64 schon fest gespeichert und immer greifbar. Sogar bis auf 8 Stellen hinter dem Komma!
Ihre Taste befindet sich rechts oben, direkt neben der RESTORE-Taste Ihres 64 ers, und Sie können Sie mit nur mit gleichzetigem drücken der SHIFT und der ↑- Taste erreichen.
Nehmen wir nun einmal an, wir wollen in etwa die Oberfläche einer Coladose berechnen, also wieviel Quadratzentimeter Weißblech zur Herstellung einer solchen Dose verbraucht werden. Eine normale Getränkedose ist allgemein 11 .5 cm hoch und hat einen Durchmesser von 6 .5 cm. Um den Radius nun zu erhalten, den wir ja brauchen, dividieren wir einfach noch durch 2, also 6 .5/2=3 .25 . Ich habe hier absichtlich einmal die Operatoren und die Schreibweise des Computers gewählt, damit Sie sich ein wenig daran gewöhnen.
So, eine Höhe und einen Radius haben wir ja jetzt, wollen wir nun einmal rechnen. Wie wir ja vorhin gelernt haben, können wir unsere Formel o=2 rπ( r+ h) ganz normal übernehmen, nur müssen wir darauf achten, daß wir dem Computer noch die in der Formel fehlenden Multiplikationsoperanden " unterschieben" können, da diese in der Mathematik im allgemeinen weggelassen werden ( um eine kompaktere Schreibform zu erreichen), unser C64 sie allerdings unbedingt benötigt, da er sonst nicht von Varablen und Zahlen unterscheiden könnte. Dies liegt einfach daran, daß Variablennamen auch Zahlen beinhalten können. Doch zur Nomenklatur von Variablen später etwas mehr. Widmen wir uns nun wieder unserem Problem, und lassen wir die in der Formel verwendeten Variablen stehen. Geben Sie doch dem Computer nun einmal unsere Beispielrechnung direkt ein, indem Sie die Werte für Höhe und Radius der Dose ganz einfach schon einsetzen. Dann kämen Sie zu folgender Zeile :

PRINT 2*3.25*π*(3.25+11.5)                           

Mal abgesehen davon, daß Sie hiermit auch zu dem richtigen Ergebnis kommen, nämlich 301 .200196 qcm, hätte man hier ein wenig sparen können, zumal man zweimal den selben Wert eingeben mußte, nämlich 3 .25 für den Radius. Machen wir es uns also einfacher und benutzen wir Variablen. Eine Wertzuweisung an eine Variable ist denkbar einfach. Sie schreiben einfach den Namen der Variable hin, setzen ein Gleichheitszeichen "=" dahinter und schreiben dann den Zahlwert hinter dieses Zeichen.
a=1 wäre also die Zuweisung des Wertes 1 an die Variable " a" . Geben Sie nun " PRINT a" ein, dann wird der Computer Ihnen die Zahl 1 ausdrucken, Sie haben also gerade eben in die Schublade " a" geschaut und ihren Inhalt auf dem Bildschirm dargestellt.
In unserem Beispiel müßten Sie also folgende Zeilen eingeben:

r=3.25                                               
h=11.5                                               

Hiermit haben Sie nun den Beiden Variablen " r" und " h" ihren Wert zugewiesen. Jetzt geht es um die Formulierung der Rechnung, die genial einfach ist. Sie müssen nur alle vorher eingesetzten Werte mit den Variablennamen austauschen.
Statt:

PRINT 2*3.25*π*(3.25+11.5)                           

heißt es jetzt nur noch:
PRINT 2* r*π*( r+ h) womit wir der Ursprungsform der mathematischen Formel schon etwas näher wären. Das tolle daran ist, daß Sie nun für alle Werte, die Sie einsetzen möchten, ein und dieselbe Zeile weiterverwenden können, nämlich die oben angezeigte. Sie müssen vorher nur den Variablen andere Werte zuweisen, z. B. :

r=2.8                                                
h=5.4                                                

Das ganze mit den Variablen hat natürlich einen Sinn:
Später, wenn Sie Programme schreiben, sind solche Universalanweiungen unerläßlich, zumal Sie einem das Programmieren erleichtern und zusätzlich auch noch unwahrscheinlich flexibel sind. . .
Wollen wir uns nun einmal ein wenig um die Variablennamen kümmern, zumal hierbei bestimmte Regeln eingehalten werden müssen, da sonst BASIC nicht mehr mitspielt, oder falsche Ergebnisse liefert.
Zusammenfassend möchte ich Ihnen diese Regeln hier einmal Auflisten :
1 .) Eine Variable darf aus Buchstaben ( also az) und aus Zahlen (0-9) bestehen. Sonderzeichen, wie z. B. :" ., ; :" oder ähnliches sind NICHT erlaubt.
Das erste Zeichen einer Variable MUSS immer ein Buchstabe sein, Sie dürfen also hierfür keine Zahlen verwenden.
2 .) Eine Variable darf höchstens 2 Zeichen lang sein.
Sie können zwar soviel Zeichen verwenden wie Sie wollen, doch sind grundsätzlich die ersten 2 nur von Bedeutung. Das heißt, daß Sie eine Variable zwar " RADIUS" nennen dürfen, doch ist diese Variable z. B. mit der Variable " RADIESCHEN", oder " RAMBOCK" absolut identisch, weil unser 64 er halt nur mit Hilfe der ersten 2 Zeichen die Variable unterscheidet. In diesem Fall heißen also alle 3 Variablen für unsern kleinen Freund " ra" . Gewöhnen Sie sich also auf keinen Fall eine solche Namensgebung an, da es so leicht zu Mißverständnissen kommen kann und damit zu Programmfehlern, nach denen man ewig sucht 3 .) Ansonten gilt natürlich, daß nur in Kleinschrift geschriebene Variablen erlaubt sind, beziehungsweise, falls Sie den Grafikzeichensatz des 64 ers benutzen sollten - er ist direkt nach dem Einschalten vorhanden - keine Grafikzeichen. Zusammengefaßt heißt das, daß Sie niemals geSHIFTete Zeichen verwenden dürfen, sondern nur solche, die Sie ohne SHIFT-Taste erreichen können, und die unter den in 1 . aufgezeigeten Zeichen sind.
Erlaubte Variablennamen wären also :

a                                                    
b                                                    
xx                                                   
ja                                                   
pi                                                   
c1                                                   
c2                                                   

Nicht erlaubt sind z. B. :

s.                                                   
%r                                                   
&g                                                   
i/                                                   
Bb                                                   
aB                                                   
1c                                                   
2c                                                   

Kommen wir nun zu den Variablentypen. Falls Sie einmal ausprobiert haben sollten, folgende Anweisung zu geben :
a= Das ist ein Text dann werden Sie vielleicht festgestellt haben, daß der Computer dann nach dem anschließenden " PRINT a" ganz und garnicht den Text -" Das ist ein Text" ausdruckte, sondern entweder einen SYNTAX ERROR oder eine 0 .
Wie Sie nun vielleicht bemerkt haben, haben wir bei unseren PRINT-Anweisungen 3 verschiedene Arten von Ausgabedaten verwendet. Fassen wir einmal zusammen :
1 .) Wir hatten Texte ausgegeben. Diese bestanden ausmehreren beliebigen Zeichen, die wir in Anführungszeichen eingeschlossen hatten.
2 .) Wir hatten dann mit Zahlen gearbeitet, indem wir mit ihnen rechneten und die Gesamtergenisse uns ausgeben ließen. Hierbei handelte es sich anfänglich wohlgemerkt um ganzzahlige Zahlen. Es wurde kein Dezimalpunkt benutzt.
3 .) Anschließend haben wir dann die sogenannten reellen Zahlen hinzugenommen. Diese sind Zahlen mit Dezimalkomma ( beziehungsweise Dezimalpunkt, in BASIC - Beispiel: pi =3 .14159 . . .) .
Grundsätzlich kann man nun sagen, daß es drei Arten von Datentypen gibt: Zeichenketten, ganze Zahlen und Kommazahlen.
Genauso müssen wir bei den Variablen unterscheiden.
Es gibt damit also 3 Variablentypen, in denen nur jeweils eine bestimmte Art von Daten gespeichert werden darf:
1 .) Texte, bestehend aus Zeichenfolgen. Diese Texte nennt man allgemeinhin im Computerjargon " Strings" .
2 .) Ganze Zahlen, sogenannte Integers.
3 .) Dezimalzahlen, sogennannte " Floats", oder Floatingpoint- Variablen ( deutsch: Fließkomma-Variablen) .
Ich möchte hier noch bemerken, daß ich diese Begriffe von nun an immer benutzen werde. Prägen Sie sie sich also gut ein, da man mit Ihnen am besten die Typen unterscheiden kann, ohne noch langwierige Umschrebungen liefern zu müssen.
Wie bringen wir also nun unserem C64 bei, welche der 3 Arten wir nun wünschen, zumal er sie nicht selbst unterscheiden kann? Nun das ist sehr einfach, wir hängen einfach noch ein bestimmtes Zeichen an den Variablennamen an, mit dem diese Unterscheidung möglich wird, und das typisch für seine Variablenart ist.
Für die einzelnen Variablen gibt es folgende Zeichen:
1 .) Strings wird ein "$" angehängt, so daß ein Variablenname für einen String beispielsweise anstatt " a" nun " a$" heißt.
2 .) Integers bekommen ein "%"- Zeichen dahinter. Also " a%" anstatt " a" .
3 .) Floats sind am einfachsten zu bilden, sie bekommen keinen Anhang. Sie sehen also, daß die Variablen, die wir in unsrem obigen Beispiel gebildet hatten, alles Floatvariablen waren, was auch notwendig war.
Floatvariablen heißen also wirklich " a" .
Wie Sie einer Floatvariable einen Wert zuweisen, wissen Sie ja mittlerweile aus unserem Beispiel mit der Coladose ( nämlich mit " x= Zahl") Die Wertzuweisung von Integern verläuft analog zu dieser Methode, da es sich hier ja auch um Zahlen handelt. Also " x%=10" .
Bei Strings verhält sich dies allerdings ein wenig anders. Zwar wird die Zuweisung mit " a$=" kenntlich gemacht, doch muß der zuzuweisende Text unbedingt, wie auch bei PRINT, noch in Anführungsstriche gesetzt werden, da sonst ja nicht von Programmtext unterschieden werden könnte. Also muß unsere Zuweisung dann lauten:
a$=" Das ist ein Text" Nun wäre diese Zeichenfolge auch gespeichert. Jetzt können Sie sie auch ruhig einmal mit " PRINT a$" abrufen. Der Computer wird Ihnen nun wie erwartet den String " Das ist ein Text" ausdrucken. Sie sehen also, daß Sie sich hierdurch sehr viel Tipparbeit ( und außerdem auch Speicherplatz) sparen können, wenn Sie für einen häufig in einem Programm vorkommenden Satz Strings benutzen. Natürlich sind Variablen zu noch viel mehr nutze, obwohl eine Wertzuweisung auch eine Menge Tipparbeit mehr bedeutet, doch um sie dreht sich wie gesagt alles in BASIC, und ohne sie wäre es kaum möglich, sinnvolle Programme zu schreiben. Diese Wertzuweisung hat natürlich auch nur im Programm einen Sinn, doch dazu wollen wir allerdings in der nächsten Ausgabe kommen.
Hier trotzdem noch eine kleine Anmerkung. Vielleicht ist Ihnen ja aufgefallen, daß die Integers irgendwo überflüssig sind, da Floatzahlen ja auch ganze Zahlen darstellen können. Eine Zuweisung von der Art " y=100" ist also nicht nur möglich, sondern meist auch die am häufigsten verwendete Methode. Sie als Anfänger dürfen ruhig so arbeiten, doch sei hier gesagt, daß das Rechnen mit Integern sehr viel schneller vom Computer ausgeführt werden kann, als das Rechnen mit Floats.
Dies liegt darin begründet, daß die Darstellungsweise von Floats im Computer intern sehr kompliziert ist, und viel internes hinund hergerechne verursacht, wohingegen die Integers dem Computer wieder einfacher erscheinen, da er selbst diese nur benutzt. Floats sind eher umständlich simulierte Dezimalzahlen, da ein Computer diese Zahlenmenge nicht kennt, sondern halt nur die natürlichen Zahlen.
Außerdem ist die Verwendung von Integern auch noch speicherplatzsparend, da die Darstellungsweise wie gesagt nicht so komliziert ist. Sollten Sie also später einmal größere Programme schreiben, bei denen dann auf einmal die 37911 Bytes, die BASIC als Hauptspeicher frei hat ( siehe auch Einschaltmeldung), zu knapp werden, dann können Sie häufig mit der gezielten Benutzung von Integern wieder ein paar Bytes " herausschinden" .
Wohlgemerkt ist die Benutzung von Integern nur dann angebracht, wenn wirklich nur mit ganzen Zahlen gerechnet wird, bzw. wenn eine Integervariable für eine Rechnung eine ganze Zahl darstellen soll. Hier sei auch noch gesagt, daß bei Integerwerten mit Nachkommastellen diese grundsätzlich abgeschnitten werden.
Das heißt, das bei der Zuweisung " a%=5 .78" die Variable dann den Wert 5 enthält. Oder daß bei der Division 3/2(=1 .5) das Ergebnis 1 ausgegeben wird.
Wir werden trotz allem wahrscheinlich doch immer Floats benutzen, weil es so einfacher zu schreiben ist ( da wir ja kein Prozentzeichen anzuhängen brauchen) und es außerdem schwieriger ist das Ganze zu verstehen, wenn z. B. in einer Formel verschiedene Variablentypen vorkommen. Doch ist es grundsätlich besser, Integers zu verwenden, wobei ich Ihnen freistelle, wie Sie dies handhaben möchten. Sie könnten ja zum Beispiel auch die hier im Kurs behandelten Programme einmal umschreiben, wobei Sie allerdings sehr weit voraus denken müssen, um prüfen zu können, ob eine Variable nicht doch irgendwann einmal einen Dezimalwert annimmt, wegen dem dann die ganze Rech- nung zunichte wird, da falsche Ergebnisse herauskommen, zumal der Computer sich bei solchen Operationen ja nicht beschwert, sondern ganz einfach die Nachkommastellen abschneidet.
Ich hoffe, daß Sie bis jetzt meinen Gedankengängen und vor allem denen des Computers folgen konnten und möchte mich nun verabschieden bis nächsten Monat, wo wir dann endlich zur Sache gehen werden, was das Schreiben von Programmen angeht.
Hiermit möchte ich nun schließen und wünsche Ihnen viel Erfolg beim experimentieren,

                                     Ihr Uli Basters.
                  Basic-Kurs Teil 2                  
                  

Lieber Leser. Nachdem wir uns das letzte Mal ja ausgiebig um die Variablen und den PRINT-Befehl gekümmert haben, möchten wir uns diesen Monat nun endlich dem Programmeschreiben, also der wirklichen Programmerung, von BASIC befassen.
Letzte Ausgabe hatten wir unsere Befehle und Anweisungen ja immer direkt auf den Bildschrirm geschrieben, und der Computer hat sie dann auch immer, nachdem wir die Taste RETURN gedrückt hatten, sofort ausgeführt, insofern er nichts an der Syntax der Zeile auszusetzen hatte. Nun müssen Sie allerdings zugeben, daß unsere kleinen PRINT-Anweisungen sich als relativ umständlich und sinnlos erwiesen, zumal man, um einen Text auf den Bildschirm zu drucken, ja mehr Schreibarbeit hatte, als wenn man ihn einfach " von Hand" auf den Bildschirm geschrieben hätte. Man hatte ja noch zusätzlich den PRINT-Befehl zu schreiben und die Anführungszeichen, die den Text einschlossen.
Nun, all dies hat natürlich einen Sinn, denn der PRINT-Befehl ist, ebenso wie die meisten anderen BA-SIC- Befehle, nicht dafür geschaffen worden, direkt Texte auszugeben, sondern um in Programmen zu arbeiten, wo die Textausgabe zur Kommentierung des Programms absolut unerläßlich ist, zumal dann ein völlig ahnungsloser Benutzer auch dann mit dem Programm etwas anfangen kann, wenn er es sich zum ersten Mal ansieht. Doch wie sag ichs meinem Computer? Wie machen wir denn unserem C64 klar, daß wir die eingegeben Zeile nicht jetzt, sondern irgendwann später ausgeführt haben wollen, und daß er sich diese Zeile für jenen späteren Zeitpunkt merken soll? Nun, geben Sie doch einfach einmal folgende Zeile ein :
10 print" Das ist ein Programm !" Sie sehen, daß Sie nichts sehen. Denn sobald Sie die RETURN-Taste drücken, druckt Ihnen Ihr 64 er nicht den Text " Das ist ein Programm !" aus sondern springt mit dem Cursor ( das ist das kleine hellblaue Viereck, das immer so blinkt, und Ihnen Ihre Schreibposition angibt) einfach in die nächste Bildschirmzeile und war- tet nun wiederum auf eine Eingabe. Noch nicht mal eine Fehlermeldung ist zu sehen. Eine Riesensauerei! ! !
Doch keine Panik ! Ihr C64 ist nicht etwa beleidigt, oder kaputt, sondern er hat sich soeben gerade eine Programmzeile gemerkt. Doch was heißt das eigentlich?
Nun, wie Ihnen bestimmt aufgefallen ist, haben wir vor unsre PRINT-Anweisung noch eine Zahl geschrieben.
Dies ist die sogenannte Zeilennummer. Ihr Computer merkt sich Ihre Eingaben intern nämlich mit Nummern, die er nach ihrer Größe ordnet. Das heißt, daß Sie mit dieser Zahl auch immer wieder auf eben jene Zeile zurückgreifen können. Sie ist sozusagen das " Erkennungszeichen" einer Programmzeile. Was das genau bedeutet, möchte ich Ihnen mit einem kleinen Beispiel noch ein wenig näher bringen. Geben Sie doch einmal ein:
list Sie sehen nun folgendes:

10 print"Das ist ein Programm !"                     
ready.                                               

Nach Eingabe des BASIC-Befehls LIST hat uns der C64 die eben eingegebene Programmzeile wieder aufgeLI-STet; so, wie wir sie eingegeben hatten, nämlich mit ihrer Zeilennummer vorangestellt. Er hat sich diese Zeile also gemerkt. Sie können gerne einmal probieren ob es auch funktioniert wenn Sie den Bildschirm gelöscht haben ( dies tun Sie mit der Tastenkombination SHIFT und CLR/ HOME), auch nun wird Ihnen der Text noch haargenauso angezeigt, wie Sie ihn eingaben, es hat also nichts damit zu tun, daß unsere Zeile noch auf dem Bildschirm stand. Das ist auch gut so, denn der C64 merkt sich solche Programmzeilen in seinem Programmspeicher ( ebenso wie die Variablen) von wo er sie auch wieder auf dem Bildschirm anzeigen kann, halt mit eben jenem Befehl LIST.
Auch für Zeilennummern müssen Sie bestimmte Regeln einhalten, damit Ihnen keine Fehler angezeigt werden.
Hier eine Zusammenfassung dieser Regeln :
1 .) Sie können alle Zahlen von 0 bis 63999 für eine Zeilennummer benutzen. Dabei sollten Sie jedoch die Zeilennummern immer in 10 er-Schritten ( also 10,20,30,40, etc.) vergeben, warum dies von Vorteil ist, werde ich Ihnen später erklären.
2 .) Egal in welcher Reihenfolge Sie die Zeilen eingeben, der C64 ordnet diese immmer wieder neu nach der Größe ihrer Zahlen ein. Sollten Sie also einmal folgende Zeilen in der hier dargestellten Reihenfolge eingeben:

    30 print"Zeile 30"                               
    10 print"Zeile 10"                               
    20 print"Zeile 20"                               
    40 print"Zeile 40"                               

So wird Ihnen Ihr C64 nach der Eingabe von LIST immer wieder folgendes Bild liefern :

    10 print"Zeile 10"                               
    20 print"Zeile 20"                               
    30 print"Zeile 30"                               
    40 print"Zeile 40"                               

3 .) Sollten Sie eine Zeile eingeben, die eine Zeilennummer hat, die schon im Speicher existiert, dann wird die alte Zeile im Speicher durch die neue ersetzt. Sollten Sie also bei obigem Programm ( so können wir es jetzt nennen) die Zeile:
30 print" Aetsch! Das is jetzt anders." eingeben, dann wird das Programm beim nächsten Listen so aussehen :

    10 print"Zeile 10"                               
    20 print"Zeile 20"                               
    30 print"Aetsch! Das is jetzt anders."           
    40 print"Zeile 40"                               

4 .) Sollten Sie eine Zeile eingeben, die nur aus einer Zeilennummer besteht OHNE darauffolgende Befehle, so wird die entspechende Zeile mit dieser Nummer, sollte sie im Speicher stehen, gelöscht werden. Würden Sie also:
30 eingeben, dann würde Zeile 30 aus unserem Programm oben gelöscht werden.
Jetzt möchte ich Ihnen die Syntax des LIST-Befehls erst einmal noch etwas genauer erklären, bevor ich weitergehe und Ihnen zeige, wie Sie unser kleines Progrämmchen zum Ablauf bringen.
Sie können dem LIST-Befehl nämlich sogar noch spezifischer sagen, in welche Programmzeilen Sie einen Einblick wünschen. Hierzu müssen Sie dem Befehlswort LIST ganz einfach die Zeilenummer der Zeile, die Sie sich ansehen wollen hinterherstellen. Der Befehl:
list 20 bewirkt also, daß Ihnen anstatt des ganzen Programms nur die Zeile 20 angezeigt wird. Ich glaube jetzt wird es Ihnen hoffentlich auch etwas deutlicher, warum eine Zeile eine Nummer braucht. Durch sie kann man jede einzelne Zeile ansprechen wie man möchte, der Computer versteht also sofort, welche Zeile Sie von ihm sehen wollen.
Doch die Anwendung von LIST geht noch weiter. Sie können sich ebenso auch einen ganz bestimmten Bereich aus Ihrem Programm ansehen, geben Sie etwa folgendes ein:
list 20-30 so werden die Zeilen 20 und 30 auf dem Bildschirm gelistet. Sie geben also einfach eine obere und eine untere Grenze an, und LIST wird seine Arbeit auf diese Zeilengrenzen beschränken. Ebenso können Sie diese Schranke nach oben und unten offen lassen. Dann wird dementsprechend einfach von der ersten Zeile bis zu der angegebenen Zeile, beziehungsweise von der angegebenen Zeile bis zur letzten Zeile gelistet. Probieren Sie doch einfach einmal folgendes mit unserem kleinen Beispielprogramm im Speicher. Geben Sie ein:
list -30 Nun werden die Zeilen 10,20 und 30 gelistet, weil das Programm ab Zeile 10 anfängt.
Bei dem Befehl:
list 20- werden die Zeilen 20,30 und 40 gelistet. Der C64 fängt bei der von Ihnen angegebenen Zeile an und hört erst am Ende des Programms auf.
Wie der LIST-Befehl funktioniert wissen Sie jetzt ja, klären wir also schnell noch die Frage, warum man im Allgemeinen besser Zeilennummern in 10 er-Schritten verteilt. Nun, dies liegt einfach darin begründet, daß Sie, wie jeder Mensch auch, nicht unfehlbar sind, und daß es Ihnen durchaus einmal passieren kann, daß Sie, aufgrund eines Fehlers im Programm, noch eine Zeile einfügen müssen. Würden Sie in 1 er-Schritten die Programmzeilen eingeben, so müßten Sie erst einmal Platz schaffen, indem Sie alle der einzufügenden Zeile folgenden Zeilen nochmals neu einzutippen hätten, da diese ja im Speicher stehen bleiben sollten, aber zwischen den Zeilen 33 und 34 kein Platz mehr für eine weitere Zeile wäre. Deshalb benutzen Sie besser 10 er Zahlen, so, daß Sie bequem zwischen die Zeilen 20 und 30 beispielsweise eine weitere Zeile, vielleicht mit der Zeilennummer 25, einfügen könnten.
Gewöhnen Sie sich diese Programmierweise also gleich an, Sie werden sehen, es lohnt sich ganz bestimmt.
Doch widmen wir uns nun unserem Problem, unser Programm auch zum Ablaufen zu bringen. Auch hierfür gibt es einen Befehl: den RUN-Befehl ( von engl. : to run = laufen) . Haben Sie unser kleines Programm noch im Speicher? Gut. Dann geben Sie doch einmal ein:
run Und nun, siehe da, werden unsere ersehnten PRINT-Zeilen endlich aktiv, denn Sie sehen nun folgendes auf dem Bildschirm :

Zeile 10                                             
Zeile 20                                             
Aetsch! Das is jetzt anders.                         
Zeile 40                                             
ready.                                               

Und nun sehen Sie auch den Vorteil des PRINT-Befehls.
Sie können nämlich so auf einfache Art und Weise lange, lange Texte eingeben, die dann dem Benutzer während des Ablaufs eines Programms wertvolle Meldungen und Hinweise geben können.
Der RUN-Befehl kann übrigens ähnlich wie LIST angewandt werden. Sie können Ihm nämlich auch sagen, wo genau er beginnen soll, ein Programm abzuarbeiten.
Nämlich indem Sie ihm, wie bei LIST, eine Zeilennummer nachstellen, ab der er beginnen wird das Programm abzuarbeiten. Gäben Sie also :
run 30 ein, so würde Sie folgendes Bild auf dem Bildschirm anstrahlen :

Aetsch! Das is jetzt anders.                         
Zeile 40                                             
ready.                                               

Eines sollte noch gesagt sein: sollten sich Variablen im Speicher befinden, wenn Sie eine neue Programmzeile eingegeben haben, so werden diese nach dem drücken der RETURN-Taste restlos gelöscht. Das liegt daran, daß der 64 er zum Eingliedern der neuen Zeile in die richtige Zahlenreihenfolge den gesamten Programmspeicher hinund herschieben muß und daß bei dieser Schieberei sehr leicht der Inhalt einer Variablen zerstört werden kann. Deshalb werden alle Variablen vorher gelöscht, damit später kein Mist im Programmtext stehen kann, und falsche Variablenwerte zu falschen Programmreaktionen führen können.
Ebenfalls aus letztem Grund heraus werden grundsätzlich vor der Ausführung eines RUN-Befehls alle Variablen vom Computer gelöscht, da so ebenfalls ungewollte Veränderungen der Variablen entstehen könnten.
Außerdem kann für die beiden Befehle LIST und RUN gesagt werden, daß sie durch das Drücken der RUN/ STOP-Taste wieder angehalten werden können.
Das heißt also, wenn LIST Ihnen gerade ein Programm auflisten sollte, und Sie sich einen Teil etwas genauer ansehen wollten, Sie dadurch den Vorgang des Listens unterbrechen könnten.
Ebenso bei RUN. Möchten Sie aus irgendeinem Grund Ihr Programm anhalten, vielleicht weil es nicht das tut, was Sie von Ihm wollen, dann können Sie es ebenfalls auf diese Weise unterbrechen. Sollten Sie es dann allerdings doch an der Stelle fortsetzen wollen, an der Sie es angehalten haben, allerdings ohne den Inhalt aller Variablen zu zuerstören, dann können Sie den Befehl CONT benutzen. Er hat haargenau selben Effekt wie RUN, nur, daß er zum einen die Variablenwerte nicht vorher löscht, und zum anderen genau hinter dem Befehl weiterarbeitet, bei dem das Programm vorher abgebrochen wurde, vorrausgesetzt es wurde zwischendurch nicht verändert. Am besten zeige ich Ihnen noch einen weiteren Befehl, damit Sie hier auch ein wenig experimenieren können: der GOTO-Befehl.
Übersetzen wir GOTO aus dem Englischen, wissen wir auch schon gleich, was wir mit diesem Befehl anfangen können. GEHE ZU einer Zeilennummer und arbeite das Programm von dort aus weiter ab. Hinter GOTO muß also noch eine Zeilennummer folgen. Probieren wir also wieder an unserem kleinen Progrämmchen etwas aus.
Geben Sie doch zusätzlich noch folgende Zeile ein:
50 goto 10 Starten Sie nun das Programm mit RUN. Sie sehen nun immer wieder unseren Demotext auf dem Bildschirm " runterlaufen", also etwa folgendes Bild :

...                                                  
Zeile 40                                             
Zeile 10                                             
Zeile 20                                             
Aetsch! Das ist jetzt anders.                        
Zeile 40                                             
Zeile 10                                             

. . .
Verfolgen wir einmal unseren C64, wie er sein Programm abarbeitet. Zuerst werden die Zeilen 10-40 wie gewohnt durchlaufen. Der Text in den PRINT-Zeilen erscheint also auf dem Bildschirm. Anschließend trifft der Computer in Zeile 50 auf den GOTO Befehl, der besagt, daß er bei Zeile 10 weiterarbeiten soll.
Er führt diesen Befehl aus, und beginnt wieder von vorne bei 10 . Dies wiederholt sich nun bis ins Unendliche. Pausenlos wird der Text ausgedruckt, und unser 64 er würde dies Jahre lang machen, vorrausgestzt es gäbe keinen Stromausfall. Er befindet sich in einer sogenannten " Endlosschleife" eine Schleife, die immer wieder durchlaufen wird, ohne daß Sie zu einem Ende kommt. Eine Schleife ist also ein bestimmter Programmabschnitt, der mindestens zweimal durchlaufen wird. Um nicht den ganzen Programmteil nochmals eingeben und somit das Programm unnötig verlängern zu müssen verwendet man also den GOTO-Befehl. Nun kommt der Auftritt für die RUN/ STOP-Taste. Drücken Sie sie einmal. Es erscheint nun:

break in  xx                                         
ready.                                               

Der Computer meldet Ihnen also, daß Sie soeben das laufende Programm in Zeile xx abgebrochen haben. Für " xx" können alle Zeilennummern des Programms stehen, da es Zufall ist, in welcher Zeile Sie gerade abgebrochen haben. Auf alle Fälle sind Sie nun unserer Endlosschleife entkommen und können wieder an Ihrem Programm weiterarbeiten. Sollten Sie allerdings wieder den Wunsch hegen, schöne Zeichenketten auf dem Bildschirm " runterlaufen" zu sehen, dann können Sie jetzt ganz einfach wieder mit CONT das Programm fortfahren lassen ( CONT von engl. : to continue = fortsetzen, fortfahren) .
Fassen wir doch einmal zusammen, wie weit wir schon fortgeschritten sind. Wir können mittlerweile kleine Programme schreiben, die etwas auf dem Bildschirm ausgeben, wir können rechnen, Programme mit Hilfe von LIST editieren und kennen auch RUN, um diese zum laufen zu bringen. Außerdem kennen wir uns mit den Namen und Typen von Variablen aus. Nunja, auf den ersten Blick erscheint dies ja sehr viel, doch direkt weltbewegende Programme können wir noch nicht so ganz schreiben, da wir eigentlich nur einen einzigen Befehl kennengelernt haben, mit dem sich innerhalb von Programmen etwas anfangen läßt, den PRINT-Befehl. Die anderen sind mehr oder weniger ausschließlich außerhalb von Programmen, im sogenannten " Direktmodus" nützlich, obwohl sie ebenso in Programmen funktionie- ren würden. Wollen wir also nun unser Befehlsspektum noch ein wenig mehr erweitern und wenden wir uns einem sehr mächtigen Befehl zu, mit dem schon etwas mehr zu machen ist.
Erinnern wir uns doch einmal an unser Beispiel vom letzten Monat mit der Coladose. Wir hatten mit Hilfe von Variablen die Oberfläche einer Coladose berechnet. Diese Dose hatte eine Höhe von 11 .5 cm und einen Deckelradius von 3 .25 cm. Mit Hilfe der Formel o=2* r*π*( r+ h) sind wir dann zu dem Ergebnis 301 .2 qcm gekommen. Bedenkt man nun, daß durch den Trend zum Umweltschutz es heutzutage durchaus möglich sein könnte, daß man ein anderes Material für Einwegdosen erfinden wird, und daß man deshalb vielleicht ein anderes Dosenformat wählen muß, so wäre unsere schöne mühselige Rechnung nur noch Müll, da unbrauchbar. Man müßte die ganze Prozedur nochmals mit den Werten der neuen Dosen durchführen. Eine mehr oder wenig umständliche Sache also. Doch wozu können wir jetzt Programme schreiben, wir hatten ja gelernt, daß die Formel für die Zylinderoberfläche, wie ich sie oben schon aufgeführt hatte, ja allgemeingültig ist und somit mit allen nur erdenklichen Werten für r und h einen richtigen Wert liefert. Im Prinzip könnte man nun ein Programm schreiben, daß diese Formel benutzt, und würde dann hierfür die Variablen in einer vorangehenden Zeile mit den entspechenden Werten versorgen. Doch wir machen es uns noch komfortabler, wir benutzen den INPUT-Befehl, der für Eingaben vom Benutzer aus sehr empfänglich ist ( im wahrsten Sinne des Wortes, denn INPUT bedeutet nichts anderes als " EINGABE") . Mit ihm wird es uns gestattet, eine Abfrage zu machen, auf die der Benutzer mit einer Eingabe antworten kann, und dies alles sogar mitten im im Programm! ! !
Wir benötigen also Werte für Radius und Höhe. Wie beim letzten Mal wollen wir hierfür die Variablennamen r und h wählen. Sehen wir uns nun doch einmal die ersten Zeilen unseres Programms an :
10 print chr$(14) ;
20 print"[ CLR,4 SPACE] Zylinderoberflaechenberechnung"30 input"[2 DOWN] Radius " ; r 40 input" Hoehe " ; h Da haben wir ja schon eine ganze Menge neue Anweisungen. Fangen wir einmal in Zeile 10 an. Sie sehen hier einen PRINT-Befehl, doch was dieser Befehl ausdruckt, können Sie nicht wissen. Eine String-Variable ist das nicht ( obwohl es fast so aussieht), ich kann Ihnen allerdings versichern, daß es etwas ähnliches darstellt. Dies ist die CHR$- Funktion. ACHTUNG! Ich betone das Wort FUNKTION! Es handelt sich hierbei wohlgemerkt NICHT um einen Befehl, das dürfen Sie nie verwechseln. Eine Funktion wird zwar ebenfalls durch ein BASIC-Schlüsselwort dargestellt, doch sie ist ohne einen verknüpfenden Befehl, oder eine Variablenzuweisung nicht ausführbar, da der Computer in diesem Fall nicht spezifisch weiß, was er mit ihr anfangen soll. Das heißt also, daß Sie Funktionen immer mit PRINT ausgeben, oder einer Variablen zuweisen können.
Zum Beispiel so:

a$=chr$(65)                                          
print a$                                             

Es gibt übrigens noch mehr Anwendungsmöglichkeiten für Funktionen, doch werden wir hierzu später kommen, da Sie die entprechenden Befehle hierzu noch nicht kennen.
Was bewirkt die CHR$- Funktion? Nun, CHR$, wird benutzt um einzelne Zeichen spezifiziert aufrufen zu können. Jedes Zeichen auf Ihrer Tastatur besitzt einen eigenen Zahlencode. Geben Sie der CHR$- Funktion nun diesen Zahlcode eines Zeichen in Klammern an, dann steht die ganze Funktion für eben dieses Zeichen. In unserem Beispiel von eben haben wir der Variable a$ den Zeichencode 65 zugeordnet. Anschließend wurde die Variable a$, in der ja nun dieser Zeichencode als Buchstabe dargestellt war, auf dem Bildschirm ausgegeben. Dieses Zeichen, das zu dem Code 65 gehört, ist das kleine " a" . Somit ist unsere Variablendefinition gleich der Definition:
a$=" a" mit der ja auch der Buchstabe " a" dem String a$ zugeordet wird. Ich hoffe Sie haben dies verstanden.
Somit hat der folgende PRINT-Befehl auch das " a" auf dem Bildschirm ausgedruckt. Genauso hätten Sie auch schreiben können:
print chr$(65) womit Sie das selbe Ergebnis erzielt hätten, allerdings nicht mehr über den Umweg mit der Stringvariable. Hier sei auch noch gesagt, daß das Ergebnis der CHR$- Funktion immer einer Stringvariablen zugeordnet wird, nicht also einer Floatoder Integervariable, da diese Variablentypen ja keine Zeichen darstellen können. Allerdings können Sie problemlos auch Anweisungen von dieser Art vergeben:

a=65                                                 
a$=chr$(a)                                           
Hier  haben  wir  nicht den Zeichencode 65 in "a" ge-
speichert, sondern einfach nur den Zahlwert  65  (bei
"PRINT a" kriegen Sie wie  erwartet  "nur"  die  Zahl
65  auf  den  Bildschirm  gedruckt).  Sie dürfen also

Floats und Intergers benutzen, um den Zahlwert in Klammern ( von CHR$) anzugeben, dies führt also zu dem selben Ergebnis, CHR$ holt sich den Wert von a aus dem Speicher und ordnet dann dem String a$ den Zeichencode des Zahlwerts von a zu. Auf der Rückseite dieser Magic Disk finden Sie diesmal auch ein kleines Programm namens ASCII-Code. Es zeigt Ihnen alle möglichen ASCII-Codes ( das sind eben jene Codes der Zeichen) des C64 an.
Wollen wir in diesem Zusammenhang gerade noch die Umkehrfunktion von CHR$ betrachten, die ASC-Funktion, mit der Sie sich beispielsweise den ASCII-Wert ( so nenne ich ab jetzt diesen Zeichencode, ASCII ist ein internationaler Standard, an den sich die meisten Computerhersteller halten, die Zeichen haben also auf den meisten Computern die selben Codes. Leider ist dies beim C64 aus unerfindlichen Gründen nicht der Fall, trozdem wird auch hier von ASCII gesprochen) eines Zeichens ausgeben lassen können. Hier geht alles genau umgekehrt, hier geben Sie ein Zeichen an, und es kommt ein Zahlwert heraus. Dies müssen Sie also auch bei Variablenzuweisungen beachten. Die ASC-Funktion sieht so aus:
print asc(" a") Wie chr$, nur daß Sie jetzt das zu untersuchende Zeichen in Anführungsstrichen in die Klammer einsetzen müssen. Die Anführungsstriche deshalb, weil Sie hier auch Strings als sogenanntes Funktionsargument verwenden dürfen, diese dann allerdings OHNE Anführungsstriche. Also:

a$="a"                                               
print asc(a$)                                        

hätte die selbe Wirkung wie die oben aufgezeigte Zeile. Sie können sich so also alle CHR$- Codes, bzw.
ASCII-Codes ausgeben lassen, und dann bei Bedarf verwenden. Auch ASC-Funktionswerte kann man Variablen zuweisen :

a$="x"                                               
a=asc("x")                                           
a%=asc(a$)                                           

Die beiden letzten Zeilen führen zum selben Ergebnis, nur daß der eine Wert in der Floatvariable " a" gespeichert ist und der andere in der Integervariablen " a%" . Außerdem ist der Weg, mit dem die Ergebnise erreicht werden jeweils ein anderer, doch das dürften Sie mittlerweile ja kennen.
Doch wollen wir uns nun, nach unsrem langen langen Ausflug zu den ASCII-Codes wieder unserer Zylinderberechnung widmen. Wir sind ja gerade dadurch auf dieses Thema gekommen. . .
In Zeile 10 stand der Befehl PRINT CHR$(14) . Es wurde also ein ASCII-Zeichen ausgegeben, mit dem Zeichencode 14 . Dieser Code steht für eine sogenannte " Steuerfunktion" . Mit einer Steuerfunktion können Sie ein Zeichen ausgeben, das nicht direkt als Buchstabe auf dem Bildschirm sichtbar wird, sondern eher eine " unsichtbare" Funktion ausübt, wie zum Beispiel den Bildschirm zu löschen, den Cursor eine Zeile höher oder tiefer rücken zu lassen, oder die Zeichenfarbe zu verändern. Unser Code 14 bewirkt, daß der Zeichensatz von Großauf Kleinschrift umgeschaltet wird. Er hat also die selbe Wirkung wie das gleichzeitige Drücken der SHIFTund der Commodoretaste. Dies ist deshalb notwendig, damit beim späteren Ausdruck von " Zylinderoberflächenberechnung" in Zeile 20, der Großbuchstabe " Z" nicht etwa als Grafikzeichen ausgegeben wird, was leicht passieren kann, zumal die Großschrift doch direkt nach dem Einschalten des 64 ers vorhanden ist.
Sicher ist Ihnen der Text in den eckigen Klammern -[]- aufgefallen, dies ist kein Programmtext im allgemeinen, hiermit habe ich ebenfalls angegeben, welche Steuerzeichen an dieser Stelle eingefügt werden müssen. Sie wissen ja, unsere Zeichen, die keine sind, sondern etwas bestimmtes ausführen. Man kann Sie nämlich auch direkt in die PRINT-Anweisung einfügen, zumal das auch einfacher und platzsparender ist. Ich tat dies bei CHR$(14) bewußt nicht, da Sie so bei der Gelegenheit einmal die CHR$- und ASC-Funktion kennenlernen konnten, und weil außerdem dieses Steuerzeichen nicht als solches in einer PRINT-Anweisung darstellbar ist ( es gibt zwar schon einen Weg, doch das wäre jetzt hier zuviel) . Doch wie sollen Sie denn überhaupt diese Steuerzeichen in die PRINT-Anweisung hereibringen? Die Lösung ist ebenso einfach wie genial. Sie müssen lediglich, NACHDEM Sie den auszugebenden Text mit einem Anführungszeichen schon angekündigt haben, die entspechende Taste drükken, und schon wird unser Steuerzeichen mit einem inversgedruckten Zeichen dargestellt. Von nun an wissen Sie, daß an dieser Stelle dann ein Steuerzeichen gedruckt wird. Die Steuerzeichen können Sie ebenso wie normale Buchstaben überall innerhalb der Anführungsstriche einfügen. Mit der Zeit werden Sie dann auch lernen, diese an Ihren Reverszeichen zu erkennen.
Inverszeichen wurden deshalb gewählt, da man sie innerhalb einer PRINT-Klammer nicht verwenden kann, man kann trotzdem aber inverse Texte ausgeben, indem man einfach die Steuerzeichen für RVS ON und RVS OFF benutzt. Die Zeichen zwischen diesen Steuerzeichen werden dann auch invers gedruckt.
In unserem Fall müssten Sie also ein CLR ( CLEAR ( dtsch. : lösche)= SHIFT + CLR/ HOME-Taste) einfügen. Ich werde in Zukunft bei solchen Steuerzeichen bestimmte Ausdrücke in eckigen Klammern angeben.
Damit Sie wissen welche Zeichen nun gemeint sind. Die Programme, die sich ja auf der Rückseite der Magic Disk befinden, werden dann natürlich immer schon die entspechenenden Steuerzeichen in Reversdarstellung enthalten, da wir ja keine " geschweiften" Texte nachher auf dem Bildschirm haben wollen. Diese Ausdrücke, die ich verwenden werde, werde ich Ihnen dann im nachfolgenden Text immer noch erläutern, damit Sie wissen, was gemeint war.
Nachdem wir uns jetzt wohl zur Genüge in den ersten 2 Zeilen unseres Programms verrannt haben, wollen wir uns nun endlich dem Befehl widmen, von dem ich anfangs gesprochen hatte. Sie werden ihn schon in den Zeilen 30 und 40 bemerkt haben. Es ist der INPUT-Befehl. Übersetzen wir doch einmal:

INPUT = engl. EINGEBEN, EINGABE                      

Na wunderar, wir können also etwas eingeben. Und das auch noch wahnsinnig komfortabel, denn Sie brauchen lediglich dem INPUT-Befehl eine Variable zu geben, in der er die Eingabe ablegen soll und schon weiß unser Programm genauer, was sein Benutzer von ihm will.
Sehen wir uns die Syntax einmal genauer an:
30 INPUT" Radius " ; r Ich muß hier noch anmerken, daß ich bei diesem Beispiel, die im Programm vorkommenden Steuerzeichen weggelassen habe. Es ist dort von [2 DOWN] die Rede, womit Sie aufgefordert sind,2 mal die Taste " Cursor runter" zu drücken.
Wie Sie an den Steuerzeichen und auch an den Anführungsstrichen erkennen können, kann man auch bei IN-PUT einen Text angeben, der vor Ausführung der eigentlichen Eingabe ausgegeben werden soll. Hinter einem Semikolon ( oder Strichpunkt - ;) wird dann noch der Name einer Variablen angehängt, in unserem Fall " r" für den Radius. Probieren Sie doch einmal obige Zeile als Programm aus.
Sie MÜSSEN übrigens unbedingt den INPUT-Befehl im Programm verwenden, da es vom Direktmodus aus zu Fehlern kommen kann, da der INPUT-Befehl im Direktmodus keinen Sinn hat. Deshalb haben die Programmierer von BASIC 2 .0 sich gesagt, daß die Benutzung dieses Befehls im Direktmodus nicht erlaubt sein darf und des- halb mit einer Fehlermeldung quittiert wird.
Sie sehen, wenn Sie alles richtig eingegeben haben, nun folgendes auf dem Bildschirm :
Radius ?
und einem blinkenden Cursor hinter dem Fragezeichen.
Sie sind nun dazu aufgefordert einen Wert für den Radius einzugeben. Tun Sie dies also. Geben Sie doch beispielsweise einmal 3 .25 ein:
Radius ?3 .25 und drücken Sie die Return-Taste. Das Programm endet nun, vorausgesetzt, Sie hatten auch wirklich nur diese eine Zeile im Speicher stehen. Geben Sie doch jetzt einmal im Direktmodus:
print r ein. Was sehen Sie? Es erscheint der Zahlwert 3 .25 auf dem Bildschirm! Genau Ihre Eingabe, die Sie soeben taten. Na ist ja entzückend - würde Kojak, lollilutschend, jetzt sagen. Merken Sie was INPUT tat? Es hat Ihre Eingabe gleich einer Variablenwertzuweisung, der Variable " r" zugeordnet und in ihr gespeichert! Dies geht sogar noch weiter! Sie dürfen sogar Strings und Integers benutzen, um Eingaben in Variablen ablegen zu können. Ein solches Programm wäre also auch denkbar:
10 input" Wie heissen Sie bitte " ; n$20 input" Und wie alt sind Sie " ; a%30 print" Sie heissen " ; n$ ;" und sind " a%" Jahre alt." Sie sehen, hier benutzen wir einen String n$( für Name) und eine Integervariable a%( für Alter) . Den Integer können wir bedenkenlos anwenden, da ja Alter im allgemeinen mit ganzen Zahlen angegeben wird.
Vielleicht ist Ihnen allerdings etwas aufgefallen:
Obwohl wir KEIN Fragezeichen in unserem Text stehen hatten, erschien doch eins auf dem Bildschirm. Wie denn das? Nun, INPUT druckt grundsätzlich immer ein Fragezeichen am Ende seines Textes aus, da ja nach etwas gefragt wird, und somit dieses Fragezeichen auch berechtigt ist. Es wird vielleicht Fälle geben, in denen es Sie stören wird, da es nicht in den Kontext der Frage passt, doch werden wir später einmal behandeln, wie man es abschalten kann.
Im Übrigen brauchen Sie auch nicht unbedingt einen Text mit INPUT auszugeben, Sie können dies auch unterdrücken, indem Sie die Anführungsstriche und das Semikolon einfach weglassen und den Variablennamen einfach anhängen. Also so beispielsweise:

10 input a$                                          
20 input a                                           
30 input xx%                                         

Ebenfalls ist es möglich, mehrere Eingaben gleichzeitig aufzunehmen. Ich finde diese Methode allerdings sehr unbequem, und außerdem gefällt es mir getrennt besser, doch möglich wäre auch dies:
10 input " Koordinaten ( X/ Y)" ; x, y Sie können hier also gleich mehrere Werte abfragen, die allerdings mit einem Komma voneinander getrennt sein sollten. Jetzt wissen Sie auch, wofür das Komma reserviert ist, da wir ja gesagt hatten, daß das Dezimalkomma bei Floatvariablen immer einem Punkt entspricht. Die Eingabe müßte dann so aussehen:
Koordinaten ( X/ Y) ?22 .3,10 Den Variablen x und y wären dann folgende Werte zugeordnet worden:

x=22.3                                               
y=10                                                 

Leider muß ich nun an dieser Stelle abbrechen, um keinen Informationsstau bei Ihnen hervorzurufen. Versuchen Sie erst einmal die eben erkannten neuen Befehle kennenzulernen. Sie können sich ja auch einmal das gesamte Zylinderberechnungsprogramm auf der Rückseite dieser Magic Disk 64 ansehen. Nächsten Monat werde ich es dann auf jeden Fall zu Ende kommentieren. Des weiteren wollen wir uns dann mit der Schleifenprogrammierung und den Entscheidungsbefehlen ( und - operatoren) widmen.
Bis dahin wünsche ich Ihnen weiterhin ein allzeit " Gut Hack",

                                      Ihr Uli Basters
G                                                    
     BASIC-Kurs : "Von Adam und Eva..." (Teil 3)     
     

Auf in die dritte Runde in unserem Basickurs. Diesen Monat wollen wir endlich unser Zylinderberechnungsprogramm zu Ende abhandeln, um uns anschließend noch ein paar kleine, nichtsdestotrotz ebenso wichtige Befehle anzuschauen.
So. Nun also weiter. Nachdem Sie die Fülle an Informationen letzten Monats hoffentlich verarbeitet haben, möchten wir uns nun gleich frisch ans Werk machen und den Rest unseres Zylinderberechnungsprogramms abhandeln. Erinnern wir uns:
Wir hatten uns die ersten 40 Zeilen angeschaut und dabei den INPUT-Befehl kennengelernt, sowie die CHR$- und die ASC-Funktion. Außerdem hatten wir uns noch ein wenig mit den Steuercodes befaßt, und ich hoffe, daß Sie mit dem ASCII-Druck- Programm auf der Rückseite ebenfalls etwas anzufangen wußten, hier gab es nämlich auch noch eine Menge weiterer Steuerfunktionen zu finden, die wir im einzelnen im Laufe des Kurses noch kennenlernen werden.
Doch nun weiter im Text, sprich im Listing ( so nennt man die vom Computer geordnete Liste der einzelnen Programmzeilen) unseres kleinen Programms, machen wir weiter ab Zeile 50, also LIST 50-( Sie wissen doch wohl hoffentlich noch, was dies bewirkt ? ! ?) :

50 o=2*r*π*(r+h)                                     
60 print"[2 DOWN]Die Oberflaeche eines Zylinders mit"
70 print"der Hoehe"h"und dem Radius"r                
80 print"betraegt";o                                 
90 input"[2 DOWN]Noch eine Berechnung (J/N)";a$      
100 if a$="j"then run                                
110 end                                              

Zeile 50 kennen wir ja noch von unseren Versuchen im Direktmodus. Mit ihr können wir die Berechnung unseres Zylinders durchführen, und das allgemeingültig, denn wir können für Radius ( r) und Höhe ( h) beliebige Werte angeben. Diese müssen halt nur vorher festgelegt werden. Wie Sie sich erinnern, hatten wir dies in den Zeilen 30 und 40 erledigt, wo wir die zwei INPUT-Befehle untergebracht hatten, die diese beiden Variablen einlesen sollten. Also wird in dieser Zeile nun die eigentliche Berechnung durchgeführt, anschließend steht dann in der Variablen " o" die Oberfläche des verlangten Zylinders. Bitte verwechseln Sie nie den Buchstaben o mit der Zahl 0 !
Die Zeilen 60-80 sind jetzt nur noch für die korrekte, beziehungsweise formatierte Ausgabe des Ergebnisses der Rechnung verantwortlich. Damit das alles ein weing besser aussieht ( denn darauf sollte man als Programmierer ebenfalls achten, daß die Nachrichten, die ein solches Programm ausgibt auch leichtverständlich und ansprechend lebendig sind), habe ich das Ergebnis in einen kleinen Satz eingebunden. Zunächst wird einmal Platz geschaffen, indem die Textausgabe 2 Zeilen tiefer geschoben wird ( das Steuerzeichen DOWN dürften Sie ja noch aus der letzten Ausgabe kennen), jetzt haben wir das ganze schön abgesetzt von den anderen Buchstaben auf dem Bildschirm plaziert. Nun druckt Zeile 60 den Text " Die Oberflaeche eines Zylinders mit" aus. In der nächsten Zeile geht es dann weiter mit " der Hoehe" und nun sehen Sie nach den Anführungsstrichen den Buchstaben " h" eingefügt. Da sich dieser außerhalb der " Gänsefüßchen" befindet, wird er auch nicht als Text, sondern, wie wir es bei vorherigen PRINT-Anweisungen ja schon gesehen haben, als Variablenname interpretiert. Deshalb wird jetzt nicht ein " h" ausgedrucht sondern ganz einfach der Wert der Variablen h. Ebenso geht es dann bei dem anschliessenden Text, der direkt nach unserer Variablen wieder in Anführungszeichen folgt. Auch hier wird am Ende dann der Wert der Variablen " r" ausgedruckt.
Interessant wird es dann wieder in Zeile 80, hier ist eine weitere Funktion des PRINT-Befehls enthalten, die Ihnen vielleicht aufgefallen ist:
Nach dem Text " betraegt" folgt ein Semikolon ( oder Strichpunkt) wie bei INPUT und anschließend der Name der Variablen, die hier folgen soll (" o") . Ich muß gleich zugeben, daß der Strichpunkt an dieser Stelle eigentlich total überflüssig ist und daß man ihn auch genausogut weglassen könnte, nur paßt er gerade gut in den Stoff, weshalb ich Ihnen seine Funktion nicht vorenthalten möchte.
Wie Ihnen vielleicht aufgefallen ist, arbeitet jeder PRINT-Befehl so, daß er nachdem er einen Text ausgegeben hat in eine neue Zeile springt, wo der nächste PRINT-Befehl dann wieder seine Arbeit fortseten kann.
Ersichtlich wird das in folgendem kleinen Programm:

10 PRINT"DAS IST IN EINER "                          
20 PRINT"ZEILE !!!"                                  

Starten Sie es, so sehen Sie folgendes auf dem Bildschirm :

DAS IST IN EINER                                     
ZEILE !!!                                            

Was zum ausgegebenen Text wohl total im Gegensatz steht. Doch PRINT hat hier genau das getan, was er sollte. Nach Zeile 10 hat er den Cursor an den Anfang der nächsten Zeile gesetzt und dann den Text aus Zeile 20 ausgedruckt ( durch einen erneuten PRINT-Aufruf) .
Doch was hat das alles mit unserem Semikolon zu tun ?
Nun, das Semikolon am Ende eines PRINT-Befehls bewirkt, daß das eben beschriebene Springen in die nächste Zeile unterdrückt wird. Ändern Sie doch einmal unser Programm folgendermaßen ab:

10 PRINT"DAS IST IN EINER ";                         
20 PRINT"ZEILE !!!"                                  

Starten Sie es jetzt so sehen Sie:

DAS IST IN EINER ZEILE !!!                           

Womit diesmal tatsächlich alles " in einer Zeile ist" .
In unserem Zylinderberechnungsprogramm hat das eigentlich keinen Zweck, denn das, was nach dem Semikolon ausgedruckt wird, würde sowieso schon direkt folgen, da das Drucken der Variablen " o" ja noch zum selben PRINT-Befehl gehört. Doch wäre durchaus auch so etwas denkbar:

80 PRINT "betraegt";                                 
85 PRINT o                                           

Würden Sie diese beiden Zeilen in unser Programm einfügen, so kämen Sie ebenfalls zum selben Ergebnis.
Nun weiter in den folgenden Zeilen, von 90-110 . Hier gibt es nämlich wieder etwas neues zu lernen: der IF-THEN- Befehl. Ich liste Ihnen diese Zeilen hier noch einmal auf, damit Sie sich das ein wenig genauer ansehen können:

90 input"[2 DOWN]Noch eine Berechnung (J/N)";a$      
100 if a$="j"then run                                
110 end                                              

Zunächst einmal Zeile 90 . Hier fragen wir, nachdem wir die Augabe um 2 Zeilen nach unten geschoben haben, um dem ganzen einen besseren Eindruck zu verleihen zunächst einmal, ob der Benutzer noch eine weitere Zylinderberechnung verlangt. Das heißt, ob er den Rechenvorgang eventuell wiederholen möchte oder nicht.
Hier kann er, wie vom Text vorgeschlagen, mit J für JA, oder mit N für NEIN antworten. Die Antwort, zu der er sich entscheidet, wird dann in der String-Variablen " a$" abgespeichert.
Nun das neue: in Zeile 100 sehen wir die sogenannte IF-THEN- Klammer. Übersetzen wir doch erst eimal wieder aus dem Englischen : WENN-DANN. Wie Sie vielleicht erraten, ist dieser Befehl dazu gedacht bestimmte Abrfragen auf ihren Wahrheitsgehalt zu prüfen, um anschliessend entsprechend im Programm zu verzweigen. Ich kann gleich anmerken, daß dies wohl einer der wichtigsten Befehle für Programme ist, da Sie ohne ihn kaum komplexere Dinge schreiben könnten, als unsere einfache Zylinderberechnung. Hier benutze ich ihn eigentlich nur, um das Programm ein klein wenig komfortabler zu machen, und um außerdem diesen äußerst wichtigen Befehl einzuführen. Was geschieht nun in Zeile 100 ?
Ganz einfach :
1 .) Der IF-Befehl prüft, ob die ihm folgende Bedingung erfüllt ist, das heißt, ob in der Variablen " a$" der Buchstabe " j" enthalten ist.
2 .) Sollte diese Bedingung " wahr" sein, so wird der Computer ganau das ausführen, was hinter dem THEN-Wort folgt. In unserem Fall würde er den RUN-Befehl aufrufen, der unser kleines Programm wieder von vorne ablaufen lassen würde. Aber jetzt kommt der Clou:
3 .) Sollte die Bedingungen " unwahr" sein, oder ganz einfach " falsch", dann wird der Teil hinter THEN ignoriert und einfach in der Zeile hinter der IF-THEN- Klammer weitergemacht. In unserem Fall steht hier der Basic-Befehl END, den wir noch nicht kennen, den ich Ihnen später jedoch genauer erläutern werde. Erst einmal zu IF-THEN :
Sie sehen also, hier wurde ganz einwandfrei eine Entscheidung vom Computer getroffen. Aufgrund einer Eingabe des Benutzers wurde eine bestimmte Reaktion veranlasst. Wenn Sie " j" eingaben, dann startete das Programm wieder von vorne, wie es ja auch sein sollte, wenn man " noch eine Berechnung" wünscht, andern- falls wurde das Programm beENDet ( nichts anderes tut der END-Befehl, doch ist trotzdem noch mehr zu ihm zu sagen) .
Um den IF-THEN- Befehl ( es ist nur ein Befehl, da die beiden Teilworte alleine keinen Sinn ergeben und vom Computer auch mit einem ERROR quittiert werden) zu benutzen brauchen wir also zum einen eine Bedingung, nach der unterschieden werden soll und zum anderen einen oder mehrere Befehle, die beim Zutreffen der gestellten Bedingung ausgeführt werden sollen.
Als Bedingungen können Sie hier mit allen Variablen " spielen" die unser Computer kennt, oder Sie können auch einfach nur Argumente angeben, wobei dies nicht unbedingt sinnvoll ist, da eine folgende Bedingung ja immer wahr wäre, und man somit sich die Abfrage sparen könnte:
IF 3=3 THEN PRINT"3 ist gleich 3 ." Dies allerdings nur einmal als kleines Beispiel, damit Sie auch verstehen, was mit " Bedingung" gemeint ist. Weitaus sinnvoller als Abfrage wäre schon eher so etwas:
IF A= B THEN PRINT" A und B sind gleich." Hier könnten die beiden Variablen tatsächlich einmal verschieden von einander und einmal gleich sein.
Bei den Bedingungen, die Sie angeben können, müssen Sie, wie Ihnen vielleicht aufgefallen ist, immer einen sogenannten " Vergleichsoperator" angeben. Dies ist ein Operator, mit dem wir dem Computer klar machen, in welcher Weise nun verglichen werden soll, denn man kann die einzelnen Vergleichsargumente auch relativ aufeinander beziehen. So wären zum Beispiel die folgenden Ausdrücke vollkommen identisch :

IF A>B THEN PRINT"A ist groesser B."                 
IF B<A THEN PRINT"A ist groesser B."                 

Zumal ja automatisch mit der Bedingung, daß " A" kleiner als " B" ist, auch gesagt ist, daß " B" größer als" A" ist. Hier werden natürlich die Variablenwerte verglichen. Wie wir ja gelernt haben müßte das bei Strings ja dann in Gänsefüßchen stehen. Sie können übrigens problemlos auch ganze Wörter vergleichen:

IF a$="BASIC" THEN PRINT "BASIC find ich auch super!"

Doch nun wieder zu den Vergleichsoperatoren. Hier können Sie mehrere Arten verwenden, die ich Ihnen hier einmal auflisten möchte:

a=b   A gleich B                                     
a<>b  A ungleich B (entweder größer oder kleiner)    
a>b   A größer B                                     
a<b   A kleiner B                                    
a>=b  A größer oder gleich B                         
a<=b  A kleiner oder gleich B                        

Zu den beiden letzten Punkten sei noch zu sagen, daß sie ebenso auch folgendermaßen lauten könnten :

a=>b  A gleich oder größer B                         
a=<b  A gleich oder kleiner B                        

Hierbei bewirken beide Schreibarten dasselbe.
Es gibt übrigens noch 3 weitere Vergleichsoperatoren, die wir aber hier vorläufig übergehen wollen, da zu deren Verständnis weitere Grundkenntnisse vorausgesetzt sein müssen. Nun noch zu END:
Wie bereits erwähnt sorgt dieser Befehl dafür, daß ein Basicprogramm beENDet wird. Der Computer bricht an dieser Stelle ganz einfach ab und meldet sich im Direktmodus mit " READY." wieder zurück. Auch dieser Befehl ist an der Stelle im Programm eigentlich ganz überflüssig, denn sollte Ihr C64 irgendwann einmal am Ende eines Listings, also in der letzten Zeile des Programms, daß er zu diesem Zeitpunkt gerade abarbeitet angelangt sein, so wird er es sowieso beenden und in den Direktmodus zurückspringen. Ich habe diesen Befehl eigentlich auch nur deshalb benutzt, weil ich ihn Ihnen halt vorstellen wollte. Ich hätte Ihn besser anders benutzt, dann wäre er sinnvoller gewesen.
Sie können ja die Zeilen 100 und 110 unseres Programms einmal folgendermaßen abändern:

100 IF a$="n" THEN END                               
110 RUN                                              

Dies hat den selben Effekt, nur daß Sie nun den Sinn des END-Befehls sehen. Hier ist es unbedingt nötig das Programm abzubrechen, und da es dies nicht von selbst tut, da es ja noch eine Zeile hat die es ausführen könnte, müssen wir dieses Beenden sozusagen " künstlich" erzwingen. . .
Wie Ihnen womöglich auffiel, hatte ich vorhin übrigens von mehreren Befehlen ( also Plural) gesprochen, die nach dem THEN ausgeführt werden können.
Doch wie? Hierzu kennt BASIC das Befehlstrennzeichen " :" . Ja, ein ganz schlichter Doppelpunkt, mit ihm können Sie dann 2 Befehle in einer Zeile voneinander trennen, ohne einen SYNTAX ERROR zu erhalten, bei IF-THEN sähe das so aus :
IF a$=" n" THEN PRINT" Tschuess dann, bis zum naechsten Mal. . ." : END Sie sehen, hier haben wir zunächst einen PRINTund dann den END-Befehl, beide getrennt durch einen Doppelpunkt. Diesen Trick können Sie auch so in einer normalen Zeile ( also in einer solchen, in der KEIN IF-THEN steht) anwenden. Etwa so:
10 PRINT" Das ist eine Endlosschleife mit viel Gedrukke! ! !" ; : GOTO 10 Probieren Sie es, nun haben wir unsere Endlosschleife vom letzten Mal in nur EINE Zeile gepackt, und sie funktioniert genauso zuverlässig. Wie man sie jetzt auch wieder " endlich" macht wissen Sie ja mittlerweile - einfach RUN/ STOP drücken.
Die einzige Grenze für Zeilen mit Doppelpunkten stellt die maximale Länge einer BASIC-Programm- Zeile dar. Grundsätzlich darf eine Programmzeile nämlich nie mehr als 80 Zeichen lang sein ( also 2 Bildschirmzeilen) . Dies ist eine computerinterne Regel, die etwas mit der Art und Weise zu tun hat, mit der eine Zeile im Speicher des Computers abgespeichert wird.
Alles, was Sie mehr eingeben, wird radikal vom Compu- ter abgeschnitten, er akzeptiert also nur maximal 80 Zeichen.
Ich kann Ihnen übrigens gleich verraten, daß der Doppelpunkt auch seine Nachteile hat.
Vorteilhaft ist, daß der Computer Programme mit vielen Doppelpunkten, wo die einzelnen Befehle also in lange Zeilen zusammengefasst sind, grundsätzlich schneller abarbeitet, als die gleiche Befehlsfolge in mehreren Zeilen. Dies hat ebenfalls etwas mit internen Vorgängen zu tun, nämlich ganz einfach damit, daß der Computer einen Doppelpunkt schneller erkennt, als eine neue Programmzeile, beziehungsweise ist er gezwungen, beim Abarbeiten einer jeden neuen Zeile ein paar Arbeitsvorgänge mehr ablaufen zu lassen. Deshalb also ein ( ganz, ganz) geringer Zeitgewinn bei der Benutzung des Doppelpunkts.
Ebenso vorteilhaft ist auch, daß durch die Benutzung des Doppelpunkts Speicherplatz gespart wird. Die Speicherung einer neuen Programmzeile kostet mehr Platz im Hauptspeicher des C64 als ein einzelner Doppelpunkt.
Doch nun der große Nachteil, weshalb ich Ihnen auch sehr von der Benutzung des Doppelpunkts außerhalb von IF-THEN- Klammern abrate. Dadurch, daß alles so durcheinander über 2 Bildschirmzeilen verteilt steht, entsteht ein wahres Chaos auf dem Bildschirm, wenn Sie Ihr Programm einmal listen sollten. Es wird durch den Doppelpunkt sehr, sehr unübersichtlich, was eine Tücke von BASIC ist, die einem als Anfänger häufig Schwierigkeiten macht. Ich empfehle Ihnen also, den Doppelpunkt nur dann zu benutzen, wenn nicht sehr viel Unheil durch ihn im Gesamtbild des Listings auf dem Bildschirm entsteht ( also nur, wenn alle durch ihn getrennten Befehle noch in EINE Bildschirmzeile - das sind 40 Zeichen - passen) . Und in IF-THEN- Klammern, wo es manchmal unerläßlich ist, mehrere Befehle auszuführen, bevor BASIC dann in der IF-THEN folgendenden Zeile mit seiner Arbeit fortfährt.
Hier gibt es übrigens auch eine Alternative mit der Sie auch bei IF-THEN keine Probleme bekommen sollten, was die Formatierung des Programmtextes angeht, denn nichtsdestotrotz wird eine " Doppelpunkt-IF- THEN-Zeile" ebenso unübersichtlich wie eine normale 80- Zeichen-Zeile. Hierbei hilft uns eine kleine Eigenart des THEN-Befehls. Sie könnten nämlich eine längere Befehlsfolge ebensogut auch in mehreren Zeilen unterbringen, die Sie, von ihren Zahlennummern her gesehen, ein wenig vom Hauptprogramm absetzen, und diese dann mit ihrer Zeilennummer DIREKT anspringen. Denkbar wäre folgendes :

10 INPUT"[CLR]WOLLEN SIE TEXT SEHEN (J/N) ";a$       
20 IF a$="J" THEN 200                                
30 PRINT"DANN NICHT...":END                          
40 :                                                 
200 PRINT"DAS IST IHR GEWUENSCHTER TEXT..."          
210 PRINT"UND HIER NOCH EINE KLEINE ZUGABE AN"       
220 PRINT"TEXT, DAMIT SIE SICH NICHT VERAEPPELT"     
230 PRINT"FUEHLEN, UND DAMIT HIER AUCH NOCH MEHR"    
240 PRINT"ZEILEN GEFUELLT WERDEN."                   

Zuerst haben wir in Zeile 10 die Abfrage, ob die Einsicht vom Benutzer in den Text überhaupt erwünscht ist. Die Antwort, wieder ein J oder ein N, wird in der Variablen a$ gespeichert. Dann folgt eine IF-THEN- Abfrage, ob die Anwort ein " J" war. Wenn nicht, dann wird der Text " DANN NICHT. . ." ausgedruckt und das Programm wird beendet.
Sollte die Antwort allerdings tatsächlich " J" gewesen sein, traf unsere Bedingung also zu, so springt der Computer gleich weiter zu Zeile 200, wo er dann den gewünschten Text ausdruckt, der hier getrennt in 5 eigenen Zeilen abgelegt wurde. Bestimmt ist Ihnen aufgefallen, daß merkwürdigerweise nur die Zeilennummer unserer gewünschten Zeile hinter dem THEN folgt.
Dies ist eben jene Eigenart des THEN-Befehls, von der ich eben sprach. Er interpretiert Zahlen, die direkt nach ihm folgen grundsätzlich immer als eine Zeilennummer, auf die er springen soll. Er führt sozusagen den Befehl GOTO 200( oder GOTO xxxx) aus. Ändern Sie Zeile 20 doch einmal folgendermaßen um:
20 IF a$=" J" THEN GOTO 200 Sie werden feststellen, daß Sie hiermit genau dasselbe erreichen wie vorher, allerdings mit dem Unterschied, daß diese Zeile langsamer abgearbeitet wird, da der GOTO-Befehl ja noch erkannt werden muß, und daß sie außerdem auch noch mehr Speicherplatz verbraucht. Die Kurzschreibweise ist also nur von Vorteil und sollte eigentlich immer verwandt werden.
Auf diese Weise können Sie übrigens auch Programmzeilen überspringen, etwa so:

10 INPUT"[CLR]WUENSCHEN SIE TEXT (J/N) ";a$          
20 IF a$="N" THEN 40                                 
30 PRINT"HIER IST TEXT FUER SIE..."                  
35 END                                               
40 PRINT"NIX TEXT!"                                  

Die ersten 2 Zeilen sind ja mittlerweile ein " alter Hut" für uns. In Zeile 20 sehen Sie, daß bei der Antwort " N" ganz einfach der Teil, der bei " J" gekommen wäre ( bzw. auch bei jedem anderen Zeichen, das ungleich " N" gewesen wäre, wie auch in den Beispielen zuvor, ich hatte es dort allerdings nie erwähnt, die Zeilen 30 und 35 ausgeführt werden. Sie können es gerne einmal ausprobieren und mit " Y" oder " Z" antworten. . .) übersprungen wird. Wenn nicht, dann wird der folgende Teil ausgeführt. Von hier können Sie entweder gleich mit END aufhören, oder Sie springen dann von dort wieder mit GOTO hinter die Zeilen, die bei " N" ausgeführt worden wären. Dies sähe dann so aus:

10 INPUT"[CLR]WUENSCHEN SIE TEXT (J/N) ";a$          
20 IF a$="N" THEN 40                                 
30 PRINT"HIER IST TEXT FUER SIE..."                  
35 GOTO 50                                           
40 PRINT"NIX TEXT!"                                  
50 END                                               

Ich hoffe Ihnen nun klar und deutlichst die Benutzung und vor allen Dingen den Sinn von IF-THEN dargelegt zu haben und möchte mich nun einmal der übersichtlichen Programmierung zuwenden. In diesem Zusammenhang wollen wir dann auch noch 2 neue Befehle kennenlernen.
Doch zunächst möchte ich schnell noch etwas nachholen. Ich habe nämlich - ich muß es gestehen - einen äußerst wichtigen Befehl vergessen, als ich Ihnen letzten Monat erläuterte, wie man Programme schreibt: den NEW-Befehl.
Dieser Befehl braucht keinerlei Parameter, und ist daher auch ganz schnell und einfach abgehandelt. Er dient dazu, ein Programm aus dem Programmspeicher Ihres C64 wieder zu löschen. Dies ist insofern wichtig, da Sie ab jetzt wohl häufiger Programme schreiben werden, und Sie diese nun ganz einfach mit NEW wieder löschen können, falls Sie ein neues eingeben möchten, und nicht mehr immer gleich den ganzen Computer ausschalten müssen, beziehungsweise alle vorkommenden Zeilennummern eines Programms einzeln eintippen müssen, um diesen Effekt zu erzielen.
Außer den gesamten Programmspeicher zu löschen, löscht NEW auch alle sich zu diesem Zeitpunkt sich im Speicher befindlichen Variablen! Wundern Sie sich also nicht, wenn manche vorher von Ihnen definierte Variablen plötzlich leer sind.
Den gleichen Effekt, nämlich daß alle Variablen im Speicher gelöscht werden können Sie ebenso mit dem Befehl CLR ( für CLEAR = löschen) erzielen. Mit dem einzigen Unterschied zu NEW, daß Ihr geschriebenes Programm noch im Speicher steht, die Variablen allerdings gelöscht sind. Dieser Befehl wird eigentlich kaum benutzt, allerdings ist es gut, ihn zu kennen, da es auch hier und da mal Gelegenheiten geben wird, wo er ganz angebracht ist. Sie werden schon sehen. . .
Dies also zu NEW und CLR, die übrigens beide keine Parameter brauchen - leider, da es manchmal ganz angebracht wäre, wenn man einfach nur einen bestimmten Bereich eines Programms löschen könnte, doch leider ist dies nicht möglich und wirklich nur so zu realisieren, indem man halt sämtliche Zeilennummern dieses Bereichs durch einzelnes Eintippen löscht.
Wenden wir uns nun einmal dem übersichtlichen, der formatierten Programmierung zu, wie ich es weiter oben schon angekündigt hatte.
Vielleicht haben Sie sich unser kleines Textausgabeprogramm von vorhin einmal genauer angeschaut und sicher sind Ihnen daran auch mindestens eine Sache, wenn nicht sogar 2, aufgefallen. Wie? Nein? Na dann schauen Sie doch einfach nochmal rein:

10 INPUT"[CLR]WOLLEN SIE TEXT SEHEN (J/N) ";a$       
20 IF a$="J" THEN 200                                
30 PRINT"DANN NICHT...":END                          
40 :                                                 
200 PRINT"DAS IST IHR GEWUENSCHTER TEXT..."          
210 PRINT"UND HIER NOCH EINE KLEINE ZUGABE AN"       
220 PRINT"TEXT, DAMIT SIE SICH NICHT VERAEPPELT"     
230 PRINT"FUEHLEN, UND DAMIT HIER AUCH NOCH MEHR"    
240 PRINT"ZEILEN GEFUELLT WERDEN."                   

Na? Klingelt es bei Ihnen? Genau - die eine Sache liegt ja wohl auf der Hand. Zeile 40 ist ja wohl total überflüssig! Nicht nur, daß sie niemals abgearbeitet wird, da das Programm ja vorher in Zeile 40 schon mit END beendet wurde, sie ist außerdem auch von ihrem Aussehen etwas merkwürdig, zumal KEINE Anweisungen in ihr vorkommen, und sie einfach nur aus einem Doppelpunkt besteht. Warum also überhaupt eine solche Zeile? Na wie Sie sich schon denken können, da es hier ja um die Formatierung des Programmtextes geht, hat das ganze etwas mit eben jenem zu tun.
Ich habe diese Zeile ganz einfach deshalb eingefügt, um die vorherige Abfrage und den anschließenden Text ein wenig voneinander abzusetzen. Damit man, sollte man sich dieses Listing zu einem späteren Zeitpunkt nocheinmal ansehen, sofort erkennt, daß die beiden Programmteile verschiedene Aufgaben haben und nicht zusammengehören und hintereinander abgearbeitet werden. Zugegeben - bei einem solch kleinen Programm wie diesem hätte ich diese Feststellung wahrscheinlich auch so noch hingekriegt, doch stellen Sie sich einmal vor, Sie hätten ein etwas längeres Listing vor sich mit ca.10000 Zeilen ( natürlich in 10 er Schritten gerechnet)- Sie müssen zugeben, daß es hier nicht mehr ganz so einfach wäre das Ganze zu überschauen.
Benutzen Sie also, um einzelne Programmteile, sogenannte Module, optisch voneinander abzusetzen immer eine oder mehr Doppelpunktzeilen, damit Sie sich später wieder in Ihrem eigenen Programm zurechtfinden.
" Wieso soll ich mich denn nicht mehr in meinem eigenen Programm zurechtfinden können, zumal ich es doch selbst geschrieben habe?" werden Sie sich jetzt vielleicht fragen, doch glauben Sie mir, denn ich speche aus Erfahrung, wenn Sie nach einiger Zeit mal wieder in ein altes Programm reinschauen, um es vielleicht zu verbessern, dann wissen Sie manchmal selbst nicht mehr, was Sie da eigentlich bewirken wollten und es passiert dann schnell, daß man dann einfach die Lust verliert, an so einem Anweisungschaos weiterzuarbeiten. Das ist wohl auch eine der Hauptschwächen von BASIC, die dem Anfänger anfangs das Programmieren sehr erschwert. Also immer die einzelnen Module eines Programms gut sichtbar voneinander absetzen, das kostet zwar ein kleines bißchen Speicherplatz, aber es lohnt sich wirklich !
Übrigens: wir hatten zwar festgestellt, daß die Doppelpunktzeile 40 in unserem Programm nicht abgearbeitet wird, da dieses vorher ja mit END beendet wird, aber es sei hier auch noch gesagt, daß der Computer sie auch ruhig hätte ausführen können - sie hätte keine Fehlermeldung bewirkt, sondern wäre sozusagen ganz einfach " übergangen" worden, obwohl dies nicht der richtige Ausdruck hierfür ist. Sie wird nämlich wie eine normale Programmzeile behandelt.
Der Grund, warum nichts passiert, wenn der Computer eine solche Zeile durchläuft ist ganz einfach der, daß der Doppelpunkt, wie wir ja gelernt haben, als Trennzeichen zweier Befehle dient. In unserer Zeile trennt er ganz einfach den " Befehl" NICHTS von dem " Befehl" NICHTS, wird also als gültiges Trennzeichen erkannt; daß diesem gar kein Befehl folgt, steht auf einem anderen Blatt. Der Computer " übersieht" das sozusagen. Er erkennt nur, daß dann die Programmzeile endet, und daß er die nächste abzuarbeiten hat, was er auch prompt tut. Daß wir ihm soeben eine völlig hirnund sinnlose Zeile vorgesetzt hatten ist ihm egal, solange er nichts an dieser auszusetzen hatte, was ja nicht der Fall war. Sie könnten also ebenso einzelne Funktionsmodule im Programmfluß voneinander trennen:

10 input"Bitte geben Sie einen Text ein ";a$         
20 a$="Das ist Ihr Text : "+a$                       
30 :                                                 
40 PRINT                                             
50 PRINT a$                                          

Sie sehen, in Zeile 10 wird ein Text in die Variable a$ eingelesen, und in Zeile 20 wird vor diesen Text noch der Prefix " Das ist Ihr Text :" gehängt. Die Variablenzuweisung dürfte Ihnen ja bekannt sein, hier wird a$ ganz einfach das zugeordnet, was auf der rechten Seite steht. Hierbei gilt natürlich noch der alte Inhalt der Variablen a$- genau also wie bei dem Ausdruck I= I+1 . Sie müßten das noch von dem letzten Kurs her kennen. . .
Hier sieht man übrigens auch sehr schön, wie man Strings aneinanderhängen kann, nämlich ganz einfach, indem man sie wie Zahlen mit dem Pluszeichen addiert ( ACHTUNG! In umgekehrter Richtung, also mit Minus ist nichts zu machen! Wie das geht kommt später. . .) In Zeile 30 wird nun das Modul, das für die Vorbereitung des auszudruckenden Textes zuständig ist, mit einem Doppelpunkt von einem zweiten Modul, nämlich das, das den Text dann ausgibt, getrennt. Der Computer arbeitet also auch diese Zeile ab, sie hat allerdings keinerlei Einwirkung auf den Programmablauf ansich, außer daß dieser vielleicht um wenige Mikrosekunden verlangsamt wird.
Vielleicht ist Ihnen in Zeile 40 auch das einsame PRINT aufgefallen, das, ganz im Gegensatz zu unseren PRINTs, keinen Text oder gar eine Variable hinter sich stehen hat. Dieses PRINT, ohne Parameter also, tut nichts anderes, als den Cursor an den Anfang der nächsten Zeile zu setzen. Hiermit haben wir also wieder ein absetzen der Ausgabe vom bisherigen Text erreicht. Genausogut hätte ich in Zeile 40 schreiben können :
40 PRINT "[ DOWN]" ;
Also einfach einmal " Cursor runter", allerdings dürfen Sie hier das Semikolon ( ;) nicht vergessen, da sonst 2( !) Zeilen freigelassen werden. Da PRINT ja nach jeder Ausgabe den Cursor in die nächste Zeile vorschiebt, und wir dies mit dem Semikolon unterbinden können. Hier sehen Sie auch warum PRINT alleine einfach nur eine Zeile weitergeht - nachdem es den Text ausdruckte, den es ja leider bei dieser alleinigen Anweisung nicht gibt, warum auch nichts ausgegeben wird, rückt es eine Zeile weiter. . .
Als letztes möchte ich jetzt noch den REM-Befehl einführen. REM steht für REMark, was so viel heißt wie " Anmerkung", womit schon wieder alles gesagt ist.
REM wird nämlich dazu benutzt, kleine Anmerkungen in Programmen unterzubringen, die später dem Programmierer erklärend wieder Anzeigen sollen, was dieser an bestimmten Stellen mit seinen Programmierkünsten bewirken wollte.
REM wird folgendermaßen angewandt :

10 REM DAS IST EIN KOMMENTAR                         

Hinter dem eigentlich Befehlswort REM folgt ganz einfach ein beliebiger Text, der Hinweise auf etwas geben kann. Hier können Sie grundsätzlich alle Zeichen verwenden, die auf Ihrer Tastatur vorkommen, allerdings sollten Sie von den Grafikzeichen absehen, da diese interne Probleme verursachen könnten. Im allgemeinen sollte man allerdings mit den Buchstaben und Zahlen auskommen.
Was genau passiert jetzt bei REM im innern unseres 64 ers? Nun, sobald dieser erkannt hat, daß er hier einen REM-Befehl vor sich hat, springt er sofort in die nächste Programmzeile, um diese abzuarbeiten, und ignoriert ganz einfach den Text der hinter REM kommt.
Somit kann dann natürlich auch keine Fehlermeldung entstehen, von dem was da steht, zumal die meisten Computersprachen mehr auf Englisch ansprechen ( wie wir ja mittlerweile oft genug gemerkt haben) als auf Deutsch, und somit unser C64 wohl nicht mehr als einen SYNTAX ERROR in solchen Fällen auf Lager hätte.
Versuchen Sie es doch einmal so :

10 DAS IST EIN KOMMENTAR                             

Sie werden sich denken können, was passiert. . .
Was jetzt noch erwähnenswert wäre, ist, daß bei REM grundsätzlich ALLES, was in dieser Zeile noch folgt, übersprungen wird. Also auch Befehle, oder Anweisungen, die hier stehen könnten. Eine solche Zeile wäre also ein fataler Fehler:

10 PRINT"ERST DAS.":REM AUSDRUCK 1:PRINT"DANN DAS."  

Der Ausdruck, den Sie jetzt sähen, wäre folgender:
ERST DAS.
Die zweite PRINT-Anweisung, wäre übergangen worden, da grundsätzlich alles ignoriert wird, also auch die PRINT-Anweisung, was hinter dem Befehlswort REM steht. Dies sollten Sie sich einprägen !
Der Vorteil von REM liegt mittlerweile ja dann auch auf der Hand. Mit diesem Befehl kann man seine Programme auf sehr einfache Art und Weise sehr übersichtlich gestalten. Natürlich gibt es auch Nachteile, nämlich wieder die selben, wie beim Doppelpunkt - REM verbraucht Speicherplatz und verlangsamt das Programm um wenige Mikrosekunden, doch ist es immer besser ein gut formatiertes Listing zu haben, als einen Haufen Spaghetti-Code durch den man selbst nicht mehr durchsteigt. Wen es wurmt, daß sein Programm dadurch langsamer und Speicherintensiver wird, der kann ja, nachdem er eine Kopie von der kommentierten Version angefertigt hat, die überflüssigen Zeilen löschen und es in dieser endgültigen Version dann benutzen, so hat man dann immer noch eine kommentierte Kopie, an der man leicht wieder kleine Veränderungen machen kann.
Hiermit möchte ich dann wieder schließen und mich bis April von Ihnen verabschieden, wo wir uns dann noch zwei wichtige Befehle zur formatierten Programmierung ansehen werden, und anschließend endlich die schon letzten Monat versprochenen Schleifen anschauen werden. Bis dahin Servus,

                           Ihr Uli Basters           
     BASIC-Kurs:  "Von Adam und Eva..." (Teil 4)     
     

Hiermit möchte ich Sie zum vierten Teil unseres Basickurses herzlichst begrüßen. Diesen Monat werden wir uns noch ein wenig mit der formatierten Programmierung befassen und werden uns anschließend endlich den lang versprochenen Schleifenbefehlen zuwenden.
Letzten Monat hatten Sie ja gelernt, wie man, mit Hilfe von REM und sogenannten " Doppelpunktzeilen" ein wenig Ordnung in einen Programmtext bringt. Eine richtige " Programmierung" war das ja noch nicht, zumal die von uns eingefügten Zeilen und Kommentare ja nichts mit dem eigentlichen Programmablauf zu tun hatten, und wir sie genausogut auch hätten weglassen können, wie ich zum Schluß andeutete.
Deshalb kommen wir heute zum GOSUB-Befehl, der in zusammenhang mit dem RETURN-Befehl uns ungeheuerliche Weiten zur platzsparenden, einfachen und formatierten Programmierung öffnet.
GOSUB steht für GO to SUBroutine, was soviel heißt, wie GEHE zu UNTERprogramm, und ist in etwa vergleichbar mit GOTO. Hinter GOSUB wird ebenfalls eine Zeilennummer angegeben, zu der der Computer springen soll. Bis hierhin tut GOSUB genau dasselbe, was auch GOTO tut, nämlich ganz einfach zu einer bestimmten Zeile im Programm springen. Die Programmzeilen, die dort stehen und folgen werden ganz normal abgearbeitet. Doch nun kommt der Clou: nachdem diese Zeilen abgearbeitet wurden, können Sie mit dem RETURN-Befehl wieder an die Stelle im Programm zurückspringen, von wo der GOSUB-Befehl in das Untersprogramm ( so nennt sich das nämlich) eingesprungen ist. Dies hat den Vorteil, daß Sie beliebige Programmsequenzen, die Sie innerhalb eines Programms benötigen, beliebig oft benutzen können, aber nur EINMAL schreiben müssen.
Der Computer merkt sich jedesmal die Stelle, von welcher Sie in das Unterprogramm eingesprungen sind, und wird jedesmal auch wieder dorthin zurückkehren. In der Praxis sieht das so aus:

5 REM *****************                              
6 REM * hauptprogramm *                              
7 REM *****************                              
8 :                                                  
10 GOSUB 200                                         
20 PRINT"Hallo Leute..."                             
30 GOSUB 200                                         
40 PRINT"Unn weils so schön war, grad nochmal...";   
50 GOSUB 200                                         
60 END                                               
90 :                                                 
195 REM ************                                 
196 REM * demotext *                                 
197 REM ************                                 
198 :                                                
200 PRINT                                            
205 PRINT"Das ist ein Text, der hier zur Demon-"     
210 PRINT"stration insgesamt 3 Mal ausgedruckt"      
220 PRINT"wird."                                     
230 PRINT                                            
240 RETURN                                           

Genau so sollte ein gut formatiertes Programm übrigens aussehen. Vor jedem Modul (= Programmabschnitt, das hatten wir letzten Monat ja schon einmal. . .) steht ein unübersehbarer Kommentar. Zuerst haben wir das " HAUPTPROGAMM" . Der Programmteil also, der am Anfang auch mit RUN gestartet wird, und der alle benötigten Unterprogramme, so wie zum Beispiel das Programm " DEMOTEXT", zu dem Zeitpunkt aufruft, zu dem sie benötigt werden.
Schauen wir uns doch einmal unser Programm ein wenig näher an. Gleich am Anfang, in Zeile 10, wird unser kleines Unterprogramm schon beansprucht und aufgerufen. Dann wird in Zeile 20 der Text " Hallo Leute. . ." ausgegeben. Anschließend kommt wieder das Unterprogramm dran. Dann kommt etwas aus dem Hauptprogramm, nämlich der Text " Unn weils so schoen war, grad nochmal. . ." . Schließlich und endlich wird DEMOTEXT noch ein letztes Mal aufgerufen und das Hauptprogramm mit END beendet. Der Ausdruck, den Sie somit erhalten, sieht im Endeffekt dann so aus:

Das ist ein Text, der hier zur Demon-                
stration insgesamt 3 Mal ausgedruckt                 
wird.                                                

Hallo Leute. . .

Das ist ein Text, der hier zur Demon-                
stration insgesamt 3 Mal ausgedruckt                 
wird.                                                

Unn weils so schoen war, grad nochmal. . .

Das ist ein Text, der hier zur Demon-                
stration insgesamt 3 Mal ausgedruckt                 
wird.                                                

Sie sehen, obwohl Sie den Text, der hier, wie so oft angezeigt," insgesamt 3 Mal ausgedruckt wird", nur einmal eingegeben haben, erscheint er tatsächlich drei Mal auf dem Bildschirm. Sie haben sich also ersteinmal ein wenig Tipparbeit gespart, und dann auch noch Speicherplatz, da drei mal mehr Platz verbraucht worden wäre, hätten Sie jedesmal unseren Text nochmal eingegeben. Außerdem sieht unser Programm so jetzt schön sauber und ordentlich aus - Unterprogramm schön vom Hauptprogramm getrennt. . .
Und es gibt da noch einen kleinen Vorteil: angenommen, Sie sind gerade dabei ein Programm zu schreiben, zu dem Sie ein bestimmtes Unterprogramm benötigen, das eine ganz bestimmte Aufgabe erfüllen soll. Welche Aufgabe im Einzelnen, sei jetzt einmal dahingestellt.
Dieses Unterprogramm haben Sie vor längerer Zeit allerdings schon einmal in einem anderen Programm benutzt, und haben es dort noch voll funktionsfähig drin stehen. Das einzigste, was Sie jetzt zu tun haben, ist das Unterprogramm aus Ihrem alten Programm herauszuisolieren, und es dann in Ihr neues einzubinden. Also ein weiterer Vorteil von Unterprogrammen, da Sie sie jederzeit wiederverwenden können, können Sie sich Ihre Programme sozusagen aus vielen kleinen Modulen ( also Unterprogrammen)" zusammenbauen", wie als wenn Sie mit Bauklötzen einen Turm konstruieren würden.
Ich muß Ihnen allerdings gestehen, daß dies gar nicht so einfach ist, wie es sich anhört, da man beim BA-SIC V2 .0 des C64 nicht so einfach riesige Programmabschnitte löschen kann, geschweige denn, daß man einzelne Module so einfach aneinander hängen könnte.
Doch nicht verzagen, in einer der nächsten Ausgaben, wird wahrscheinlich ein kleines Hilfsprogramm hierzu erscheinen, daß diese Aufgaben bewältigen wird.
Wie oben schon erwähnt, kann man GOSUB auch zum " herumspringen" genauso wie GOTO verwenden, doch möchte ich Ihnen DRINGENDST davon abraten. Denn wie ebenfalls schon gesagt, merkt sich der GOSUB-Befehl ( im Gegensatz zu GOTO) eben jene Stelle, von wo aus er in ein Unterprogramm eingesprungen ist. Da der Computer allerdings nur einen begrenzten Speicherplatz für solche Rücksprünge bereithält, kann es Ihnen somit passieren, daß Ihr Programm irgendwann aus Speichermangel einen Fehler ausspuckt. Benutzen Sie also immer GOTO, wenn Sie " nur" springen möchten. Dies ist auch ein kleiner Hinweis für Sie, falls Sie mal ein Programm haben sollten, das nicht so laufen sollte, wie Sie es wünschen. Eine häufige Fehlerquelle ist nämlich auch die Tatsache, daß vergessen wurde, das Unterprogramm mit RETURN abzuschließen. Sollte nämlich jetzt zufällig wieder der Programmteil folgen, von dem aus das Unterprogramm aufgerufen wurde, dann wiederholt sich dieser Aufruf solange, bis der Computer abbrechen muß, da sein Merkspeicher " überläuft"( so nennt man das, wenn bei einer internen Operation der Computer über die Speichergrenze hinaus einen Zugriff machen muß) . Das soll jetzt natürlich NICHT heißen, daß Sie ein Unterprogramm nicht wiederum von einem weiteren Unterprogramm aus aufrufen könnten.
Natürlich geht das, Sie müssen nur jedes Unterprogramm immer wieder ornungsgemäß mit dem RETURN-Befehl abschließen, um keinen Ärger zu bekommen. Theoretisch könnten Sie sogar 24 Unterprogramme untereinander verschachteln, doch werden Sie diese Grenze wohl nie erreichen. . .
Wollen wir uns nun endlich den Scheifenbefehlen zuwenden. Zuerst einmal, was ist eine Schleife? Wie Sie sich vielleicht erinnern, hatten wir, beim Abhandeln des GOTO-Befehls eine sogenannte " Endlosschleife" geschrieben. Deshalb Endloschleife, weil ein ganz bestimmter Programmteil immer und immer wieder abgearbeitet wurde, so, daß das Programm endlos lange weitergelaufen wäre, hätten wir es nicht mit RUN/ STOP angehalten. Hier nochmals ein solches Programm:
10 PRINT" Das ist eine Endlosschleife. . ." ;
20 GOTO 10 Hier wird der Text " Das ist eine Endlosschleife. . ." also immer wieder ausgegeben, da in Zeile 20 ja immer wieder zu Zeile 10 verzweigt wird, womit sich unser Programm also immer wieder selbst aufruft. Klarer wird es, wenn Sie Zeile 20 wie folgt abändern:
10 PRINT" Das ist eine Endlosschleife. . ." ;
20 RUN Jetzt startet sich das Programm also immer wieder selbst, ohne daß es jemals zu einem Ende kommen würde.
Sie müssen allerdings zugeben, daß solche Endlosschleifen, so wie sie hier dargestellt sind zumindest, wenig Sinn ergeben. Es wäre doch viel besser, wenn man eine solche Schleife unter Kontrolle hätte, und sie endlich machen könnte, so also, daß sie nach eine bestimmten Anzahl von Durchläufen beendet wird.
Zum Einen könnte man das, wenn wir uns auf unser bisheriges Wissen stützen, sehr gut mit der IF-THEN- Klammer lösen. Nämlich so:

5 i=0                                                
10 i=i+1                                             
20 PRINT"DAS IST EIN TEXT"                           
30 IF i<>5 THEN 10                                   
40 END                                               

Zuerst wird in Zeile 5 die Variable I auf 0 gesetzt.
Anschließend wird diese Laufvariable ( so wollen wir es einmal nennen), ihres Zeichens eine Floatvariable, um eins erhöht. Dann drucken wir den Text " DAS IST EIN TEXT" aus. In Zeile 30 vergleichen wir nun, ob I den Wert 5 enthält. Wenn nicht, dann wird wieder zu Zeile 10 gesprungen und der Vorgang des Um-Eins- Erhöhens und des Ausdruckens wiederholt sich. Andernfalls wird das Programm beENDet. Sie sehen, daß diese Schleife nur 5 Mal durchlaufen werden kann, da sich nämlich bei jedem Durchlauf die Variable I um eins erhöht, hat sie nach 5 Durchgängen den Wert 5 tatsächlich erreicht. Also wird die Schleife abgebrochen, und es geht in Zeile 40 weiter im Programm.
Hiermit hätten wir also eine Endlichschleife geschaffen, doch dies geht auch einfacher und übersichtlicher, denn BASIC stellt uns extra zur Schleifenprogrammierung zwei Befehle zur Verfügung, FOR und NEXT, die die FOR-NEXT- Schleife bilden.
FOR-NEXT arbeitet ähnlich, wie unsere IF-THEN- Schleife. Auch hier benötigen wir eine Laufvariable, nur, daß wir hier gleich in einem Zug angeben können, von welchem Wert zu welchem Wert gezählt werden soll.
Also haben wir hier die Zeilen 5 und 30 unseres ersten Schleifenprogramms in EINEM zusammengefaßt. Sehen Sie sich doch einfach einmal dieses kleine Programm an, das die selbe Arbeit verrichtet, wie unser letztes Programm, allerdings mit Hilfe von FOR-NEXT:

10 FOR I=1 to 5                                      
20 PRINT"DAS IST EIN TEXT"                           
30 NEXT                                              

Das war alles! Auf den ersten Blick sieht das zwar genauso lang aus, wie unser erstes Schleifenprogramm, doch der FOR-Befehl hat noch einige Eigenarten, die ihn zum einen komfortabler machen, und zum anderen ÜBERSICHTLICHER, was ja außerordentlich wichtig ist, wie wir festgestellt hatten. Nicht umsonst nämlich hatte ich ein ganzes Kapitel der formatiertien Programmierung gewidmet!
Das Übersichtliche an FOR-NEXT ist, daß der gesamte Schleifenrumpf, der Teil also, der immer wieder abgearbeitet werden soll, durch FOR und NEXT eingegrenzt wird. Sehen wir uns nun einmal an, was im Innern unsers Computers abläuft, wenn er eine solche Schleife abarbeitet:
In Zeile 10 erkennt der 64 er erst einmal ( an FOR), daß hier gleich eine Schleife folgt. Direkt hinter dem FOR-Befehl wird dann die Laufvariable mit einem Grundwert " initialisiert", das heißt, daß ein bestimmter Wert als Ausgangswert für diese Variable festgelegt wird. Diese Initialisierung entspricht Zeile 5 unseres ersten Programms, hier wurde die Variable ' I' auf 0 gesetzt. Daß wir sie nicht mit 1 initialisierten, wie bei FOR, liegt einfach daran, daß sie anschließend, in Zeile 10, schon auf 1 gezählt wurde. Womit sie den selben Anfangswert hat, wie in unserem zweiten Programmbeispiel.
Wie gesagt haben wir nun die untere und die obere Grenze festgelegt, innerhalb der der Computer zählen soll. In unserem Beispiel ist das von 1 bis 5 .
In Zeile 20 geht' s jetzt weiter mit dem Schleifenrumpf, der hier nur diese eine Zeile, mit Nummer 20, lang ist. Natürlich könnten Sie hier auch mehrere Zeilen stehen haben, Hauptsache ist, daß Sie diese dann auch zwischen FOR und NEXT sozusagen " einklammern" . Unser Schleifenrumpf besteht also aus der Anweisung, den Text " DAS IST EIN TEXT" auszudrucken.
In Zeile 30 nun trifft der Computer auf die NEXT-Anweisung. Jetzt zählt er die Schleifenoder Laufvariable erst einmal um 1 hoch. Entsprechend also der Zeile 10 unseres ersten Programms:
10 I= I+1 Anschließend prüft er, ob der Inhalt dieser Variable mittlerweile größer ist, als der obere Grenzwert, ob dieser also schon überschritten wurde. Ist dies der Fall, so wird die Schleife beendet und der Computer fährt in Programm fort. Ist die Laufvariable allerdings noch kleiner oder gleich dem Grenzwert, so wird wieder an den Befehl im Programm verzweigt, der nach der FOR-Anweisung kommt. Dies wiederholt sich dann halt solange, bis der Grenzwert dann endlich überschritten wurde. Ich möchte hier auch noch darauf aufmerksam machen, daß die Laufvariable VOR dem Vergleich hochgezählt wird. Deshalb hat Sie nach dem Aussprung aus der Schleife immer den Inhalt des oberen Grenzwertes plus 1 ! ! ! Dies zu wissen kann äußerst wichtig sein, da hier manchmal Fehler gemacht werden:

FOR i=0 TO 3:PRINT"TEXT":NEXT                        

Diese Schleife zum Beispiel wird insgesamt 4( !) mal durchlaufen, da von 0 nach 3 gezählt wird ( also 3 Ziffern plus die Null. . .) . Nicht also, wie man fälschlicherweise annehmen könnte, nur 3 mal!
Hier sehen Sie übrigens auch, daß man FOR und NEXT nicht unbedingt in eigene Programmzeilen schreiben muß, es ist nämlich auch durchaus möglich sie in EI-NER Zeile zusammenzufassen, vorrausgesetzt, der Schleifenrumpf ist nicht zu lang.
Grundsätzlich gilt: alle Befehle, Anweisungen und Funktionen, die zwischen FOR und NEXT stehen bilden alle gemeinsam den Schleifenrumpf, den Teil also, der immer wieder von der Schleife durchlaufen wird, unabhängig davon, wie die einzelnen Befehle innerhalb von Programmzeilen verteilt sind.
Doch kann man mit FOR noch viel mehr anfangen! Angenommen Sie wollten nicht immer um 1 erhöhen, sondern immer um 2, weil Sie, aus welchen Gründen auch immer, alle 2 er Zahlen, oder alle geraden Zahlen, benutzen möchten. Hierzu kann man die STEP-Anweisung benutzen, die an den FOR-Befehl angehängt wird, ohne diesen sie nicht existieren kann, sprich nicht verwendbar ist.
Geben Sie doch einfach einmal folgendes ein:

FOR I=0 to 10 STEP 2:PRINT I:NEXT                    

Die Ausgabe dieser Schleife sieht so aus:

0                                                    
2                                                    
4                                                    
6                                                    
8                                                    
10                                                   

Eigentlich nichts neues mehr für uns. Hier wurde ganz einfach von 0 bis 10 gezählt, allerdings in 2 er Schritten, wie man an der Ausgabe erkennen kann - der Inhalt von ' i' war immer um 2 erhöht. Auch hier galt: erst als NACH einem Hochzählen um den Zählwert ( oder die sogenannte Schrittweite) der obere Grenzwert überschritten wurde, wurde die Schleife verlassen.
Es mag sein, daß dieses Ihnen noch nicht ganz einleuchtet, deshalb also ein weiteres Beispiel. Wir hatten bis jetzt immer von einem kleineren Wert bis zu einem größeren gezählt. Manchmal könnte es aber auch ganz nützlich für uns sein, rückwärts zu zählen, beispielsweise von 5 bis 0 in 1 er-Schritten, oder gar in halben Zahlen, also in 0 .5 er-Schritten. Das ist absolut kein Problem mit STEP. Der Wert hinter diesem Anweisungswort muß ganz einfach negativ sein, also mit einem Minuszeichen (-) davor. Etwa so:

FOR I=5 to 0 STEP -1:PRINT I:NEXT                    

Hier haben wir dann eine " Rückwärtsschleife" . Sie zählt rückwärts von 5 bis 0 . Auch hier gilt: erst wenn der zweite Grenzwert, diesmal ist er allerdings kleiner als der erste, UNTERSCHRITTEN wurde, wird die Schleife verlassen. Diesmal also erst, wenn der Inhalt der Zählvariable kleiner ist, als der Grenzwert, zu dem gezählt werden soll. Dies ist ein kleiner Unterschied, der bei Schleifen mit negativen Zählwerten auftritt, an den man sich jedoch leicht gewöhnt, da er im Grunde ja ganz logisch ist, oder?
Das zum Thema Schleifen. Ich hoffe, Ihnen dieses Problem verständlich dargelegt zu haben. Nun möchte ich mich, quasi zur Entspannung, einem etwas leichteren Themen zuwenden, sozusagen ein paar kleine Häppchen als " Hors d' oevre" vorschicken, auf das was nächsten Monat auf sie zu kommt. . .
Beginnen wir mit einem kleinen Rechenoperator, den ich Ihnen bei unserer Rechnerei am Anfang dieses Kurses verschwiegen habe. Es handelt sich hierbei um den Exponentialoperator, der durch den ' Pfeil nach oben'('↑') ausgedrückt wird. Mit ihm können Sie die nte Potenz einer Zahl berechnen. Etwa 2 hoch 8, oder 5 zum Quadrat. Geschrieben wird das so:

PRINT 2↑8                                            
PRINT 5↑2                                            

Sie können diesem Operator natürlich genauso benutzen, wie die anderen Operatoren auch, also ebenfalls auch bei Variablenzuweisungen benutzen.
Sollten Sie übrigens darauf bedacht sein, Ihre Programme so zu programmieren, daß sie mit einem Minimum an Zeit ablaufen, dann gebe ich Ihnen den Tip, Ihre Quadrat-Potenzen ( also die Potenzen, die die 2 als Exponenten, oder als ' Hochzahl' haben) mit dem Multiplikationsoperator '*' auszudrücken. Dies rechnet der 64 er nämlich bedeutend schneller aus, als wenn Sie den Potenz-Operator verwenden würden. Also anstatt:
PRINT X↑2 schreiben Sie besser:
PRINT X* X Dieses führt zum selben Ergebnis, verbraucht allerdings bedeutend weniger Zeit. Sie selbst dürften das vielleicht nicht direkt merken, da es der Computer für uns normal Sterbliche immer noch sehr schnell berechnet, aber schreiben Sie doch vielleicht einfach einmal eine Schleife, die eine solche Potenzoperation vielleicht 1000 oder 2000 Mal durchführt, und stoppen Sie dann doch mal die Sekunden, ich denke, daß Sie einen Unterschied feststellen müßten. . .
Das nächste, was ich Ihnen nicht vorenthalten möchte, ist die " DEF-FN"- Anweisung. Mit dieser Anweisung können Sie ganze Funktionen in einem Ausdruck definieren, so daß sie diesen Ausdruck nur noch durch ein kleines Namenskürzel aufrufen müssen. Angenommen, Sie haben eine Formel, mit der Sie durch Eingabe einer Unbekannten eine gewisse Größe berechnen können. Als praktisches Beispiel will ich mich mal ein wenig an der Kreisberechnung auslassen. Nehmen wir an, Sie wollten ein Programm schreiben, das Ihnen den Kreisumfang sowie den Kreisinhalt berechnet. Die dazugehörigen Formeln lauten, wie wir wissen, wenn wir alle schön in der Schule aufgepaßt haben:

Kreisumfang:  2rπ  (= 2*r*π)                         
Kreisinhalt:  r↑2π (= r↑2*π)                         

Da wir hier in unserem Kurs leider keine Sonderzeichen haben, habe ich, um das Quadrat auszudrücken, wie unser C64 auch, den Exponentenpfeil (↑) benutzt.
Sie kennen Ihn ja mittlerweile. In Klammern sehen Sie dann die endgültige Computerschreibweise ( da ja noch die Multiplikations-Zeichen '*' eingefügt werden mußten.
Die Formel für den Kreisinhalt werden wir allerdings gleich nochmal ein wenig abändern. Da wir ja die Quadrate etwas schneller berechnen wollen, heißt es jetzt also: r* r*π( was ja dasselbe ist wie r↑2*π) .
Nun müssen diese beiden Funktionen nur noch mit DEF FN in einem Namen definiert werden. Dies geschieht folgendermaßen:

10 def fnu(r)=2*r*π                                  
20 def fni(r)=r*r*π                                  

Mit DEF zeigen Sie dem Computer also an, daß Sie hier eine Funktion definieren wollen. Dann geben Sie den Namen der Funktion an, der sich immer aus dem FN-Prefix, einem oder zwei Buchstaben und dem '( R)'- Suffix zusammensetzt. Das Prefix ist bei jeder Definition gleich, der eigentliche Name der Funktion wird durch die beiden Buchstaben in der Mitte bestimmt, bei denen Sie nach den selben Regeln arbeiten müssen wie bei den Variablennamen. Diese Regeln hatte ich Ihnen, als wir die Variablennamensgebung hatten, ja schon einmal aufgezählt. Zum Suffix sei nur noch zu sagen, daß hier in Klammern immer die Unbekannte stehen muß, die in der zu definierenden Funktionsgleichung ( oder Formel) eingesetzt werden soll.
Warum, werden Sie beim Aufruf erkennen. Ich möchte hier jedoch erst einmal wieder ein weiteres Stück unseres Programmes einfügen:

30 print chr$(14)chr$(8)                             
40 print"[CLS]Programm zur Berechnung von Kreisum-   
fang"                                                
50 print"und -inhalt."                               
60 input"[2 DOWN]Radius ";r                          
70 u=fnu(r)                                          
80 i=fni(r)                                          

Die Zeilen 30-50 drucken die Titelzeile des Programms aus. In Zeile 30 wird übrigens wieder mit CHR$(14) die Kleinschrift eingeschaltet und mit CHR$(8) die Umschaltmöglichkeit durch Drücken der SHIFTund der COMMODORE-Tasten blockiert. Wir hatten dies ja schon einmal bei unserem Zylinderberechnungsprogramm. . .
In Zeile 60 fragt das Programm jetzt nach dem Radius, der nach Eingabe eines beliebigen Wertes in der Variablen ' r' gespeichert wird.
Jetzt folgt endlich unser langerwarteter Funktionsaufruf. Sie sehen, daß in Zeile 70 das Ergebnis der Funktion erst einmal der Variablen ' u' zugeornet wird. Der Aufruf ansich gestaltet sich höchst einfach und schmerzlos. Sie schreiben ganz einfach wieder den Prefix ' FN' gefolgt vom Funktionsnamen und dem Suf- fix, mit der unbekannten Variablen in runden Klammern eingeschlossen - das wars schon. Jetzt müssen wir das Ergebnis nur noch ausdrucken, und das geschieht folgendermaßen:
90 print" Der Kreisumfang ist:" u 100 print" Der Kreisinhalt ist:" i Was ja hoffentlich keinerlei Erklärung bedarf. . .
Der Clou an den vordefinierten Funktionen ist also, daß man eine Unbekannte gleich in den Klammern am Ende angeben kann. Sie hätten die Funktion ebenso auch so aufrufen können:
print fnu(1 .5) Hier haben wir den Wert der Funktion also gleich numerisch angegeben, nicht also in einer Variablen. Der Vorteil von solchen Funktionsdefinitionen liegt auf der Hand. Angenommen, Sie haben eine bestimmte Formel, die Sie in einem Programm wahnsinnig oft benutzen müssen. Mit DEF-FN können Sie diese also immer abkürzen, und haben Ihre Funktion immer sofort parat.
Mit FN haben Sie also eine Art Variable für Formeln ( oder Funktionen), weshalb FN als ' normaler' Variablenname nicht zulässig ist. Sie können gerne einmal versuchen der Variable ' fn' einen Wert zuzuweisen, doch wird Sie der C64 dann nur mit einem lapidaren SYNTAX ERROR belohnen. . .
Außerdem sei noch hinzuzufügen, daß Sie eine Funktionsdefinition ausschließlich NUR innerhalb von Programmen durchführen können. Versuchen Sie dies im Direktmodus, so quittiert Ihnen das der Computer mit einem " ILLEGAL DIRECT ERROR", einem " UNERLAUBTEN DI-REKTANWEISUNGS FEHLER" also. Ebenso wie INPUT beispielsweise ist DEF außerhalb von Programmen unsinnig, weshalb dieser Fehler auftritt. Einmal definiert allerdings, können Sie jede Funktion aus dem Direktmodus aus aufrufen - andersherum geht es also. . .
Beschäftigen wir uns nun noch ein wenig mit der benutzerfreundlichen Programmierung. Das heißt, daß wir unsere Programme so schreiben wollen, daß sie auch jeder Computeranfänger problemlos bedienen kann. Genauergesagt möchte ich Ihnen die komfortable Programmierung von sogenannten " Menüs" näherbringen. BASIC stellt uns hierzu 2 äußerst nützliche und komfortable Befehle zur Verfügung, die auch sehr gut noch für weitere Aufgaben zu verwenden sind.
Als erstes will ich den Begiff " MENÜ" einmal klären.
Bei einem Menü handelt es sich um eine Zusammenfassung von Unterpunkten innerhalb eines Programms, die der Benutzer einzeln aufrufen kann. Sie kennen dies bestimmt schon von meinem kleinen ASCII-Druck- Programm namens " SHOWASC", das dem zweiten Teil dieses Kurses beigefügt war. Hier wurden Sie nämlich gefragt, welche Funktion des Programms Sie wünschen.
Ich zeige Ihnen hier am besten einmal das Menü von SHOWASC, damit Sie sich ein besseres Bild machen können:

-----------------------------------------------------
ASCII-Tabellen-Druck.                                
Written in 1988 by Uli Basters.                      

Bitte druecken Sie:

====================                                 
 F1  - Ausgabe der Liste auf Drucker                 
 F7  - Ausgabe der Liste auf Bildschirm              
  E  - fuer Programmende                             
-----------------------------------------------------

Sie können hier also zwischen 3 sogenannten " Menüpunkten" wählen, die Sie durch das Drücken einer bestimmten Taste erreichen können. Kommen wir hier nun zum ersten der beiden Befehle, die ich Ihnen vorstellen wollte: dem GET-Befehl.
Mit ihm können Sie einen Buchstaben von der Tastatur einlesen, der dann - in einer Stringvariable gespeichert - jederzeit abgerufen werden kann. Hier ein Auszug aus dem Programm des Menüs von oben ( ich habe es aus Gründen der besseren Verständlichkeit ein wenig abgeändert. . .) :

...                                                  
25 print"Bitte druecken Sie: "                       
26 print"===================="                       
30 print" F1  - Ausgabe der Liste auf Drucker"       
40 print" F7  - Ausgabe der Liste auf Bildschirm"    
50 print"  E  - für Programmende"                    
60 get a$:if a$=""then 60                            

In den Zeilen 25-50 wird erst einmal der Text zu unserem Menü auf dem Bildschirm ausgegeben. Wie das dann aussieht haben wir oben ja schon einmal gesehen.
In Zeile 60 haben wir jetzt unseren GET-Befehl. Wie Sie sehen, steht ihm die String-Variable ' a$' nach.
Die Taste, die also auf der Tastatur gedrückt wird, wird im ASCII-Code in dieser Stringvariablen gespeichert. Hier könnte natürlich auch jede andere Stringvariable stehen, nicht aber eine Numerische, oder eine Intgervariable.
Direkt anschließend, aber immer noch in Zeile 60, kommt ein IF-THEN- Vergleich. Es wird geprüft, ob der Inhalt der Variablen a$="" ist. Sie werden sich vielleicht fragen, was diese 2 Hochkommas ausdrücken.
Nun, ganz einfach, schreiben Sie irgendwo in BASIC für einen String, bei einer Zuweisung, oder wie hier zum Vergleich, ein "" dann steht das für NICHTS, oder auch KEIN STRING. Es wird also hier bei uns geprüft, ob ' a$' leer ist, oder ob ein String in ihr gespeichert ist. Dieser Vergleich ist notwendig, da der Computer ja eine Taste in ' a$' gespeichert haben könnte, obwohl Sie gar keine gedrückt haben. Das hängt ganz einfach mit internen Vorgängen zusammen.
Mit GET fragen Sie nämlich grundsätzlich immer die Tastatur ab, egal, ob jetzt eine Taste gedrückt ist, oder nicht - GET holt sich immer den aktuellen Tastaturstand in die ihm nachgestellte Stringvariable.
Sollte also beim Aufruf von GET keine Taste gedrückt sein, so brauchen wir gar nicht erst weiterzumachen, sondern schicken den Computer gleich wieder auf GET.
Solange bis endlich eine Eingabe gebacht wurde. Wir haben hier also praktisch eine Endlosschleife produziert, die erst dann beendet wird, wenn eine Taste gedrückt wird.
Jetzt können wir prüfen, welche Taste dies war. Dies funktioniert ganz einfach über ein paar IF-THEN- Abfragen, siehe auch die folgenden Zeilen:

70 if a$="[F1]" then 300                             
80 if a$="[F7]" then 200                             
90 if a$="e" then end                                
100 goto 60                                          

Wie die eckigen Klammern ja anzeigen, haben wir hierwieder 2 neue Sonderzeichen, die sehr leicht zu erklären sind. Sie entstehen, wenn Sie innerhalb der Gänsefüßchen die F1-( in Zeile 70) oder die F7- Taste ( in Zeile 80) drücken. Diese beiden Zeichen sind übrigens gute Beispiele für die Sonderzeichen, denn obwohl sie nicht sichtbar sind, wenn man sie ausdruckt, sind sie doch relativ wichtig, da man ohne sie die Abfrage der F-Tasten nur schwer realisieren könnte. Sie könnten hier übrigens ebenso schreiben:

70 if a$=chr$(133) then 300                          
80 if a$=chr$(136) then 200                          

Dies würde dasselbe bewirken, da die ASCII-Codes 133 und 136 ja den Tasten F1, und F7 entsprechen, die sie nebenbei auch der ASCII-Tabelle im Bedienungshandbuch des 64 ers, Anhang F, entnehmen können, oder Sie benutzen ganz einfach SHOWASC.
Es wird hier also nach Zeile 300 verzweigt, wenn der Drucker die Tabelle drucken soll, oder zu Zeile 200, wenn sie auf dem Bildschirm dargestellt werden soll.
Anschließend kommt in Zeile 90 unseres Programms noch der Vergleich, ob ' a$' nicht den Buchstaben ' e' beinhaltet. Ist dies der Fall, so wird das Programm mit END beendet.
Interessant ist noch Zeile 100 . Hier wird wieder in Zeile 60 zum GET-Befehl gesprungen, also zurück in unsere Abfrageschleife. Dies ist notwendig, da ja auch noch andere Tasten, als F1, F7 oder e, gedrückt worden sein könnten - sei es aus Versehen, oder nur weil der User das Programm einmal ärgern wollte. War dies der Fall, so hat der Computer bis in Zeile 90 verglichen und festgestellt, daß keiner der 3 ASCII-Codes in ' a$' gespeichert ist. Jetzt würde er ja im Programm ganz normal weitermachen. Da ich in ( der nun folgenden) Zeile 200 allerdings das Modul abgelegt habe, das die Ausgabe auf den Bildschirm übernimmt, müssen wir ihn hier dann abgefangen, damit er nicht unkontrolliert in eine Unterroutine reinläuft, was eben durch jenen besagten Sprung in die Zeile 60 realisiert wird.
Der zweite Befehl, den ich Ihnen noch vorstellen möchte, heißt ON, und wird in Verbindung mit GOTO und GOSUB benutzt. Er ist sozusagen eine spezielle Version des IF-Befehls. Hinter ON folgt eine Formel, die vom Computer errechnet wird. Dies ist im einfachsten Fall eine numerische Variable. Dann kommt entweder der GOTOoder der GOSUB-Befehl, gefolgt von einer Liste mit Zeilennummern, die durch Kommata getrennt werden. Praktisch sieht das etwa so aus:

20 on x goto 100,200,300,400,500                     

Jetzt wird geprüft, welcher Wert in ' x' enthalten ist. Ist x=1, dann wird die erste Zeilennummer, die in der Liste steht, angesprungen ( wie wenn sie ein GOTO 100 ausführen würden) . Ist x=2 dann wird die 2 .
Zeilennummer angesprungen, bei x=3 die 3 . und so fort. . .
Diese eine Zeile entspricht also den 5 IF-THEN- Zeilen:

10 if x=1 then 100                                   
20 if x=2 then 200                                   
30 if x=3 then 300                                   
40 if x=4 then 400                                   
50 if x=5 then 500                                   

Sollte x gleich 0, beziehungsweise negativ, oder gar größer als die angegebenen Glieder der Liste sein, so wird ganz normal im Programm fortgefahren. Wollten wir unser Programm von vorhin also umschreiben, so müßte das folgendermaßen aussehen.

60 input"Menüpunkt ";x                               
70 on x goto 200,300,400                             
80 goto 60                                           

Das sieht doch schon gleich viel kürzer aus! Allerdings darf man hier nicht vergessen, daß in Zeile 400 dann auch wirklich noch ein END-Befehl steht, da dieser ja in unserem alten Programm direkt in der IF-THEN- Abfrage kam.
Ich habe hier übrigens ganz bewußt den INPUT-Befehl benutzt, da wir ja gelernt haben, daß man bei GET nur Stringvariablen einlesen kann. Hierbei haben wir dann im Endeffek keine Möglichkeit mit ON zu arbeiten, es sein denn man greift zu einem kleinen Trick:
die Ziffern der Zahlen sind nämlich im ASCII-Code alle hintereinander angeordnet. Die 0 hat den Code 48, die 1 den Code 49 und so weiter, bis zur 9, die den Code 57 belegt. Wird bei einer GET-Abfrage also die 1 gedrückt, so enthält a$ den CHR$- Code 49 . Wenn wir jetzt von dieser Zahl einfach den Wert 48 subtrahieren, so erhalten wir das Ergebnis 1, was ja genau die Taste ist, die gedrückt wurde, nur haben wir jetzt einen Zahlwert, mit dem ON etwas anfangen kann.
Das Programm hierzu müßte dann so aussehen:

60 get a$:if a$="" then 60                           
70 on asc(a$)-48 goto 200,300,400                    
80 goto 60                                           

Hier haben Sie dann auch ein Beispiel, in dem wir eine ganze Formel benutzen, die zuerst berechnet und dann ausgewertet wird. Wir haben dabei die, uns mittlerweile schon altbekannte, ASC-Anweisung angewandt, um den CHR$- Code der in ' a$' gespeicherten Taste zu erfahren.
Wie eingangs schon erwähnt, könnten Sie hier auch den GOSUB-Befehl verwenden, nur müssen Sie dann Ihre Module auch mit RETURN wieder abschließen. Denkbar wäre auch, daß man mit Buchstaben die Tasten abfrägt, wobei man alphabetisch vorgeht. Da der ASCII-Code des Zeichens ' a' den Wert 65 hat, müßten Sie hier nur den Wert 64 subtrahieren, um brauchbare Zahlwerte für ON herauszubekommen.
Hiermit möchte ich nun für diesen Monat wieder einmal schließen und mich bis Mai verabschieden. Wir werden uns dann, wie ich diesmal schon angedeutet hatte, um etwas höchst wichtiges kümmern, was unerläßlich ist, wenn man sich ein wenig mit der Grafikund Soundprogrammierung des C64 beschäftigen möchte. Ich rede von dem sogenannten Binärsystem und dem Speicheraufbau unseres kleinen Freundes. Mehr dann nächsten Monat.
Bis dann also, Ihr Uli Basters.

     BASIC-Kurs:  "Von Adam und Eva..." (Teil 5)     
     

Herzlich Willkommen beim fünften Teil unseres Basickurses. Wie letzten Monat schon versprochen geht es diesmal um das sogenannte Binärsystem und den Speicheraufbau unseres 64 ers. Dieses Thema hat eigentlich mit BASIC im allgemeinen ganz und garnichts zu tun, doch ist es unerläßlich wenigstens einige Kenntnisse davon zu haben, wenn man sich mit der Grafikund Soundprogrammierung auf dem C64 beschäftigen möchte.
Zunächst einmal eine kleine Erläuterung zu Zahlen im allgemeinen:
Wie Sie ja wissen benutzen wir Menschen ein Zahlensystem mit dessen Hilfe wir Maße, Gewichte, Geldsummen oder ähnliches bequem ausdrücken können. Ich spreche vom sogenannten " Dezimalsystem" . Indem wir uns der Ziffern 0123456789 bedienen, können wir durch beliebiges kombinieren dieser Ziffern Zahlen von unendlicher Länge bilden. Ein Beispiel wäre da die Zahl 1989 . Sie gliedert sich in 4 Teile auf, die ich Ihnen im Folgenden einmal grafisch darstellen möchte:

                                      Die  Buchstaben
                                      T,H,Z   und   E
                                      stehen      für
                                      "Tausender",   
                                      "Hunderter",   
                                      "Zehner"    und
                                      "Einer".    Das
                                      heißt also, daß
                                      die  Zahl  1989
                                      in  eine   Zahl
                                      mit vier Kompo-
                                      nenten   aufge-
                                      spaltet wird.  

Mathematisch läßt sich das folgendermaßen ausdrücken:

1000*T +  100*H +   10*Z +    1*E = THZE (oder auch) 
10↑3*T + 10↑2*H + 10↑1*Z + 10↑0*E = THZE             

Oder in unserem Beispiel:

1000*1 +  100*9 +   10*8 +    1*9 =                  
10↑3*1 + 10↑2*9 + 10↑1*8 + 10↑0*9 =                  
  1000 +    900 +     80 +      9 = 1989             

Jeder Stelle der Zahl ist also eine Potenz von 10 zugeordnet (1=10↑0,10=10↑1,100=10↑2,1000=10↑3, usw. . .) . Daher auch der Name DEZIMALsystem -" decum" kommt aus dem lateinischen und heißt " zehn" .
Dieses Verfahren läßt sich natürlich auch bei größerstelligen Zahlen anwenden. Bei der Zahl 2313660 ist die höchste Zehnerpotenz 10↑6 . Hierbei ist übrigens noch anzumerken, daß die letzte Ziffer eine Null ist, bei der der ihr zugehörige Potenzfaktor ( hier 10↑0) sozusagen " wegmultipliziert" wird, denn 1*0=0, weshalb auch hier als Endsumme aller Produkte der Potenzen 2313660 herauskommt. Das scheint alles komplizierter als es ist - wichtig ist, daß Sie begriffen haben, daß eine Dezimalziffer nur aus der Addition von 10 er-Potenzen besteht.
Sie sehen auch, daß jedesmal nachdem wir die höchste Ziffer einer Potenz erreicht haben, nämlich die 9, die nächste Zahl als ein Vielfaches der nächsthöheren Potenz darstellen können. Haben Sie also die Zahl neun erreicht, so findet ein sogenannter " Überlauf" statt, das heißt, daß die nun folgende Zahl eine Stelle mehr bekommt, und ihre höchste 10 er Potenz mit der Ziffer 1 als Multiplikator versehen wird. Der Nachfolger von 9 ist 10 wobei letztgenannte Zahl eine zweistellige ist, erstere allerdings nur eine einstellige.
Ebenso kommen Überläufe vor, wenn wir von 19 auf 20 zählen. Hier wird der Zähler der nächsten Potenz um eins erhöht. Auch von 29 auf 30 verhält es sich so, und so fort. Bei jedem Überlauf erhält also die niedrigere Potenz die Ziffer 0 in den Zähler, während die höhere die nächst höhere Ziffer verpasst bekommt.
Beim Zählen von 99 auf 100 zum Beispiel geschieht dies sogar gleich zweimal. Zum Einen erhalten die " Einer"(10↑0) die Nullziffer und es findet ein Überlauf zu den " Zehnern"(10↑1) statt, zum Anderen bewirkt dieser wiedrum, daß die " Zehner" überlaufen und somit den Zähler 0 erhalten, wobei die " Hunderter"(10↑2) um 1 erhöht werden und nun die Ziffer 1 dort im Zähler steht.
Sehen Sie hier das Ganze ein wenig grafisch aufgemacht ( denn ein Bild sagt mehr als tausend Worte) :
Wir haben also gelernt, daß die 10 mit ihren Potenzen die Basis unseres Zahlensystems liefert, da alle Dezimalzahlen als Summe von 10 er-Potenzen dargestellt werden können. Sie werden jetzt fragen:
" Was hat das Ganze denn mit dem Binärsystem zu tun, darum geht es hier doch?" Nun, das Binärsystem folgt nämlich ( fast) genau diesem Muster, mit dem einzigen Unterschied ( daher auch die Einschränkung eben), daß wir hier nicht mit einer Basis von 10 sondern mit der von 2 arbeiten. Auch hier können Sie den Namen des Systems von ihr ableiten " Bi" steht für Zwei. Da wir ja nun alle 2 er-Potenzen verwenden, brauchen wir logischerweise auch nur zwei Ziffern, mit denen wir unsere Binärzahlen darstellen ( im Dezimalsystem hatten wir ja 10 davon - Sie sehen, es werden immer soviele Ziffern benötigt, wie die Basis angibt) . Dies sind ganz einfach die Ziffern 0 und 1 . Demnach kann man also sagen, daß eine Binärzahl so aussehen könnte:11001010 . Diese hier zum Beispiel ist achtstellig. Das hat einen besonderen Grund, wie wir später erkennen werden.
Wie sich eine solche Zahl jetzt zusammensetzt ist klar - wir müssen ganz einfach die Potenzen von 2 nebeneinander schreiben ( allerdings mit der niedrigsten ganz links und der höchsten ganz rechts) und die Produkte der Binärziffern mit den ihnen zugehörigen Potenzen miteinander addieren. Als Ergebnis erhalten wir dann unsere Binärzahl in Dezimalschreibweise.
Führen wir dies doch einmal durch:

MD8905/MD8905-KURS-5.8.hires.png

Sie sehen also: wir benutzen hier genau dasselbe Prinzip wie beim Dezimalsystem, mit dem Unterschied, daß hier die Produkte der 2 er-Potenzen addiert werden.
Doch warum das alles? Wozu können wir das Binärsystem gebrauchen, und warum sind achtstellige Binärzahlen etwas Besonderes? Leider muß ich zur Beantwortung dieser Frage wiederum etwas weiter ausholen:
Im Prinzip kann man sagen - und das wird mir jeder, der sich mit Computern gut auskennt bestätigen:
" Computer sind dumm" .
Sie können nämlich ausschließlich nur zwischen " STROM AN" und " STROM AUS" unterscheiden. Das heißt, daß sie nur erkennen können, ob auf einer ihrer vielen Leitungen ein elektrischer Strom fließt, oder nicht. Was Computer jetzt allerdings so schlau macht, daß wir Ihnen Befehle eingeben können, die sie dann ausführen können liegt einfach nur daran, daß sie immens viele socher EIN/ AUS-Leitungen besitzen und daß diese in richtiger Kombination bestimmte Wirkungen erzielen können. Ein recht einfaches Beispiel wäre etwa folgendes:
Angenommen, ein Computer hätte vier Leitungen vor sich, die er auf EIN oder AUS überprüfen könnte. Er erkennt, daß Leitung 1 EINgeschaltet ( sprich:" auf ihr fließt Strom), Leitung 2 AUSgeschaltet ( hier fließt also KEIN Strom), Leitung 3 wieder EINgeschaltet und Leitung 4 ebenfalls wieder EINgeschaltet sind. Daraus ergibt sich die Kombination:

EIN                                                  
AUS                                                  
EIN                                                  
EIN                                                  

Nun weiß unser Computerchen zusätzlich noch, daß er, wenn diese Kombination eintreten sollte, beispielsweise die Hintergrundfarbe auf Dunkelgrau umschalten soll. Diese Information ist irgendwo in seinem Aufbau gespeichert.
Sie sehen also, so einfach ( oder kompliziert) ist es, einen Computer ganz elementar zu programmieren, das heißt also ganz grundsätzlich, ohne irgendwelche Hilfsmittel ihm einen Befehl zu erteilen, indem man bestimmte Stromleitungen in ihm einoder ausschaltet. Kompliziert ist dies vielleicht deshalb, weil man hierzu alle möglichen Kombinationen mit ihrer Wirkung kennen muß. Das sind bei vier Leitungen zwar " nur"16 verschiedene, aber es könnten ja beispielsweise auch viel mehr Leitungen zum Unterscheiden zur Verfügung stehen.
Hm - Moment einmal, die Zahl 16 hatten wir doch heute schon einmal! ! ! Genau -16 ist die vierte Potenz von 2( also 2↑4), der Wert der fünften Ziffer des Binärsystems! Und genau das ist es, worauf ich hinaus möchte: die oben genannte EIN/ AUS-Kombination könnte nämlich auch genausogut folgendermaßen aussehen ( wenn man anstelle von EIN die Ziffer 1 und anstelle von AUS die Ziffer 0 schreibt) :

EIN AUS EIN EIN                                      
  1   0   1   1                                      

Und siehe da: da haben wir doch eine echte ( vorläufig vierstellige) Binärzahl! Ins Dezimalsystem umgerechnet lautet sie übrigens 11( elf) . Und tatsächlich ist es auch so, daß wenn wir unserem C64 an einer bestimmten Stelle in seinem Speicher die Zahl 11 angeben, er den Bildschirm in die Farbe Dunkelgrau umfärben wird." An einer bestimmten Stelle" hört sich vielleicht etwas merkwürdig an, doch werden wir dies jetzt noch klären.
Wollen wir uns nun mit dem Speicheraufbau unseres C64 befassen. Anschließend werden Sie feststellen, daß das Wort " Stelle" absolut passend ist.
Wie Sie vielleicht einmal gehört haben, oder in Ihrem C64 Bedienungshandbuch gelesen haben, verfügt Ihr kleiner Freund über 64( sogenannte) Kilobytes ( Abkürzung : KB) Speicher ( bei denjenigen Lesern, die die Funktionsweise des Binärsystems begriffen haben sollten, müßte eigentlich gerade eben ein Licht aufgegangen sein -64 ist die sechste Potenz von 2, also 2↑6) . Bestimmt konnten Sie bis jetzt absolut nichts damit anfangen, weshalb wir jetzt erst einmal klären wollen was ein Kilobyte, oder besser ein einzelnes Byte ist. Zuerst einmal zum Byte:
Ein Byte ist die Zusammenfassung von acht( !) sogenannten Bits. Man kann also sagen:1 Byte =8 Bits.
Doch was, um alles in der Welt, ist jetzt wieder ein Bit? Nun, ein Bit ist ganz einfach eine von jenen vielen Leitungen, wie ich sie oben schon beschrieben hatte, die einund ausschaltbar sind. Eine von diesen Leitungen, die ein Computer miteinander kombiniert, um den Befehl, den er ausführen soll zu ermitteln. Womit unsere Frage nach dem " Warum eine achtstellige Binärzahl" beantwortet wäre: da unser Bit für eine stromführende Leitung steht, die entweder EINoder AUSgeschaltet sein kann (1 oder 0), und weil acht Bit einem Byte entsprechen, kann dieses Byte mit Hilfe einer achtstelligen Binärzahl ausgedrückt werden. Man spricht hier von dem " Wert" eines Bytes. Von der Binärzahl also, die in diesem Byte enthalten ist, oder anders gesagt: von den Bits, die in diesem Byte " gesetzt"( Bit=1) oder " nicht gesetzt"( Bit=0) sind.
Würde man also sagen: dieses Byte hat den Wert 202, so würde man damit die Bitgruppe 11001010 meinen ( hier einmal die Werte unseres Beispiels von oben) .
Ein Kilobyte ist jetzt ganz einfach die Gesamtheit von 1024 Bytes. Dies verhält sich etwa ähnlich wie bei Gramm und Kilogramm. Ein Kilogramm sind 1000 Gramm, oder das 10↑3- fache von 1 . Bei Bytes rechnet man mit einer Potenz von 2, da die Bytes ja auch auf ein System aus 2 er-Potenzen aufgebaut sind, und somit die Zahlen besser " harmonieren" . Doch dies ist jetzt unwichtig, da Sie die Bedeutung dieser " Harmonie" erst verstehen müssen, wenn Sie einmal die Maschinensprache ( auch " Assembler genannt) lernen werden.
Des Weiteren sind ein Megabyte demnach also 1024 Kilobytes. Am Rande vielleicht eine kleine Umrechnungstabelle:
1 Megabyte =1024 Kilobytes =1024*1024 Bytes (1024*1024 sind übrigens 1048576, also " ein klein wenig" mehr als eine Million. . .) Jetzt wissen Sie also, daß wir insgesamt 64*1024*8(=524288) Leitungen in unserem C64 haben (64 KB eben), die alle in verschiedenster Weise einoder ausgeschaltet sein können. Zahlenmäßg gesehen ist das ja eine ganz schöne Menge, in der Realität werden wir allerdings nur eine Handvoll davon effektiv nutzen können. Man kann etwa sagen, daß gute 99 Prozent dieser 64 Kilobytes nur zur Speicherung von Befehlen benutzt wird. Das heißt also, daß sich der Computer in diesen Bereichen die Befehle, die er irgendwann einmal ausführen soll, einfach nur zwischenspeichert, damit er sie bei Bedarf dann gleich griffbereit hat, um sie abzuarbeiten. Doch dies fällt ebenfalls in den Themenbereich der Maschinensprache, wo es sogar eine sehr große Rolle spielt.
Diese 65536 Bytes (=64 KB), können jetzt alle einzeln mit ihren Nummern angesprochen werden. Bildlich könnte man sich das etwa wie eine Straße vorstellen, in der es 65536 Häuser gibt, mit ebenso vielen Hausnummern. Möchten Sie jetzt beispielsweise einen Brief an das Haus mit der Nummer 53281 schicken, so müßten Sie diesen an folgende Adresse schicken:

An                                                   
Herrn Byte                                           
Speicherstraße 53281                                 
64KB Commodore 64                                    

Der Name des Adressaten und der adressierten Stadt dient hier nur zur Untermalung, wichtig ist jedoch, daß Sie erkennen, daß Sie so einen " Brief" an das Haus mit der Nummer 53281 schicken können. Der Inhalt dieses Briefes könnte etwa folgendermaßen aussehen:
Sehr geehrter Herr Byte,

00001011                                             
Herzlichst, Ihr Programmierer.                       

Auch diesmal nur ein kleines aufmunterndes Beispiel, um den Zweck des " Verschicken eines Briefes" aufzuzeigen. Tatsächlich sagt man sogar, daß man ein Byte " adressiert", also seine " Adresse" angibt, und ihm dann einen Wert zuweist. Mit unserem Brief hätten wir also dem Byte 53281 den Wert 00001011 zugewiesen, womit wir wieder beim Binärsystem wären. Der aufmerksame Leser hat bestimmt schon längst gemerkt, daß wir hier die Binärzahl von vorhin auf dem Bildschirm stehen haben, nämlich die dezimale 11 . Diesmal allerdings achtstellig, da wir ja gelernt haben, daß man das ganze Byte adressiert, und somit auch auf jeden Fall 8 Bits verändert. Die höherwertigen 4 Bits beinhalten jetzt ganz einfach die Ziffer 0, womit ihre Produkte mit ihren jeweiligen Potenzen auch zu 0 werden, weshalb sie auch nicht zu Gewicht schlagen.
Wollen wir nun endlich den BASIC-Befehl kennenlernen, mit dem wir " Briefe verschicken" können: der POKE-Befehl.
Die Syntax von POKE ist denkbar einfach: Sie müssen hinter dem Befehlswort POKE ganz einfach nur noch die Adresse des zu verändernden Bytes angeben und anschließend, durch ein Komma voneinander getrennt, den Wert, der zugewiesen werden soll, allerdings in dezimaler Schreibweise. Daher also auch die vorangehende langwierige Erklärung des Binärsystems, denn später müssen Sie sich Ihre Bitkombinationen selbst zusammenrechenen können.
Um unser Adressierungsbeispiel gleich in die Realität umzusetzen - hier ist der Brief an Herrn Byte, wie wir ihn in BASIC schreiben mÜssten:
POKE 53281,11 Wir haben also der Speicherzelle ( das ist die deutsche Übersetzung für Byte)53281 den Dezimalwert 11 beziehungsweise den Binärwert 00001011 zugewiesen.
Probieren Sie es doch einmal aus, und beobachten Sie, was passiert. . . Na? Verblüfft? Eben genau DAS ist eingetreten, was ich Ihnen vorhin beschrieben hatte:
der Hintergrund des Bildschirms Ihres C64 hat sich vom üblichen Blau in ein tristes Dunkelgrau verfärbt.
Sie sehen also, man muß nur die richtigen STELLEN im Speicher des 64 ers verändern, um gewisse Ergebnisse zu erzielen.
Jetzt möchte ich Ihnen allerdings nicht verschweigen, daß es ebenso möglich ist, von einer Speicherzelle einen Brief zu erhalten. Das heißt also, daß Sie als Programmierer die Speichezelle dazu veranlassen können, ihren Inhalt ( oder ihren Wert) Ihnen zuzuschikken. Dies kann in BASIC mit der PEEK-Funktion realisiert werden. Die Syntax von PEEK ist ebenfalls sehr einfach: Sie müssen nach dem Befehlswort PEEK nur noch die gewünschte Byteadresse, in Klammern gesetzt, angeben, um den Inhalt dieses Bytes zu erhalten. Ich möchte darauf aufmerksam machen, daß es sich hierbei um eine FUNKTION handelt. Sie können PEEK also ohne alles kaum effektiv nutzen, es solte nämlich schon ein PRINT-Befehl, eine Variablenzuweisung, oder ein Vergleich durch IF-THEN dabei stehen, um der Funktion entsprechend einen Sinn zu geben. Eine Möglichkeit, sich den Inhalt einer Speicherzelle anzusehen, wäre über PRINT gegeben. Versuchen Sie doch einmal folgendes:
PRINT PEEK(53281) Jetzt sollten Sie eine Zahl auf dem Bildschirm stehen haben. Sie gibt die Farbe des Hintergrundes an, da das Byte 53281 ja für die Farbe des Bildschirms zuständig ist, wie wir es vorhin gelernt hatten. Es kann durchaus sein, daß Sie jetzt hier etwas anderes als 11 auf dem Bildschirm stehen haben. Das hat etwas mit der computerinternen Handhabung der Farben zu tun, doch das wollen wir an späterer Stelle genauer behandeln. Prinzipiell kann man jetzt also sagen, daß Sie mit Hilfe von PEEK und POKE ein Byte zu verschiedenen Aktionen veranlassen können. Mit PEEK lassen Sie sich von dem Byte einen Brief schicken, der seinen Wert beinhaltet und mit POKE können Sie das Spiel umkehren und dem Byte einen Brief zuschicken, der den Wert beinhaltet, den es annehmen soll. Wie wir gesehen haben, ist gerade letztere Funktion ja sehr nützlich, wenn wir verschiedene Dinge im Computer bewirken wollen, man muß nur wissen an welchen Stellen man Änderunngen vornehmen muß, um einen gewissen Effekt zu erzielen.
Womit wir wieder bei den Stellen wären. Ich möchte Ihnen hier einmal eine kleine Übersicht aller Stellen ( Bytes, Speicherzellen, Hausnummern, Adressen, oder wie Sie es auch immer nennen möchten) geben, wie Sie im C64 vorkommen. Man kann diese 65536 Bytes nämlich in gewissen Aufgabenbereichen zusammenfassen, um etwas Ordnung in die Tausenden von verschiedenen Zellen zu bringen:

MD8905/MD8905-KURS-5.22.hires.png

Ich habe hier den Speicher des C64 einmal mit Hilfe eines Balkens, der in verschiedene Teilbereiche aufgespalten ist, dargestellt. Unten sehen Sie die Speicherzelle 0, und am oberen Rand haben wir das letzte Byte, mit der Adresse 65535 . Sie werden jetzt fragen:" Warum 65535 wo wir doch die ganze Zeit von 65536 Bytes reden ?"- Nun, wir müssen hier wieder berücksichtigen, daß das Byte mit der Adresse 0 ja auch mitzählt, somit haben wir ( rein zahlenmäßig) dann 65535 Bytes plus ein 0- Byte, das macht 65535+1=65536 !
Ich möchte Ihnen hier dann gleich noch die Aufgaben der verschiedenen Speicherbereiche erläutern, wie ich sie im Bild schon angedeutet habee. Hierbei möchte ich allerdings vorerst die Bytes von 0 bis 40960 übergehen, da Sie deren Funktionsweise besser verstehen können, wenn Sie die der Folgenden schon kennen.
Beginnen wir also bei 40960 bis 49152 . Hier steht das sogenannte BASIC-ROM. Klären wir zunächst einmal, wofür ROM steht. Hierzu sollte ich vielleicht erwähnen, daß es zwei verschiedene Arten von Speicherzellen in Ihrem C64 gibt. Bestimmte Teilbereiche haben also bestimmte Eigenschaften, die ein anderer wiederum nicht hat. Die zwei Arten, von denen hier gesprochen wird, nennt man RAM und ROM. RAM steht für " Random Access Memory" und ROM für " Read Only Memory" .
Übersetzen wir dies aus dem Englischen, so haben wir:" Speicher für beliebigen Zugriff" und " Speicher, der nur gelesen werden kann." Dies heißt im Klartext, daß RAM-Speicherzellen beschrieben UND gelesen werden können, im Gegensatz zu ROM-Adressen, die NUR gelesen werden. Sie können sich dies etwa mit folgendem Bild verdeutlichen: die RAM-Adressen sind schreibfreudige Mitbürger. Sie erhalten gerne Briefe, und beantworten diese auch, sollten sie dazu aufgefordert worden sein. ROM-Adressen hingegen sind eher Kontaktscheu, sie ignorieren ihre Post, und werfen sie, wie Sie es vielleicht auch manchmal bei Werbesendungen tun, ungelesen in den Mülleimer. Sie kennen ihren Programmierer schon gut genug, weshalb sie auch nur dann an ihn ihren Inhalt senden, wenn dieser es unbedingt verlangt. Außerdem sind ROM-Adressen sehr konservative Individuen, sie haben nämlich auch gar nicht vor, ihre Einstellung ( also ihren Wert) zu ändern und bleiben auch auf Immer und Ewig bei ihrem voreingestellten Wert.
Doch jetzt einmal Spaß beiseite - der Grund, warum man ROM und RAM schuf, war einfach der, daß man einen Speicher benötigte, der auch ohne Stromzufuhr, also im ausgeschalteten Zustand des Computers, in der Lage ist, seine in ihm gespeicherten Informationen zu behalten. Da man sonst bei jedem neuen Einschalten eines Computers ein gewisses Grundprogramm jedesmal wieder von Neuen hätte eingeben müssen, wobei natürlich die Frage aufkommt, wie man dies getan hätte, da in einem leeren Computer ohne Programm auch nichts getan werden kann, um Daten aufzunehmen, da dieser immer ein Programm braucht, das ihm diese Daten einliest. Ebenso ist es bei BASIC. In dem vorhin angesprochenen Bereich des BASIC-ROMs sind die Grundprogramme gespeichert, die es uns ermöglichen, in BASIC mit unserem 64 er zu kommunizieren. Alle Befehle, die wir bisher behandelt haben, ebenso wie diese, die noch kommen werden, sind hier genauestens definiert, so daß der Computer immer genau weiß, was er zu tun hat, wenn Sie ihn Beispielsweise mit der Buchstabenfolge PRINT konfrontieren.
ROM braucht also keinen Strom, um die in ihm gespeicherten Bits zu behalten. Sie können sich dies etwa als eine Unmenge von Leitungen vorstellen, die fest und unveränderlich sind. Und nicht, wie es beim RAM der Fall ist, durch Schalter ein-, oder ausschaltbar sind. ROM-Bits STEHEN ganz einfach schon auf EIN oder AUS.
Der Vorteil am RAM ist ganz einfach, daß man seinen Inhalt sozusagen " von Hand" verändern kann und wäre dies nicht möglich, so könnte man beispielsweise die Bildschirmfarbe auch gar nicht verändern. Dafür geht diese dann allerdings auch verloren, wenn man die Stromzufuhr unterbricht.
Doch machen wir nun wieder in unserer Speicherübersicht weiter. Es folgt nun der Bereich von 49152 bis 53248 . Hier ist freier RAM-Speicher, der vom Computer nicht benutzt wird. Wir als Programmierer, können ihn uns zwar zu Nutze machen, doch das ebenfalls erst, wenn Sie sich einmal mit Assembler befassen sollten.
Der folgende Speicherbereich ist der für uns BASIC-Programmierer wichtigste, weshalb ich anschließend auch etwas genauer darauf eingehen werde. Der sogenannte I/ O-Bereich, oder Input/ Output-Bereich ( von 53248 bis 57344), enthält die Speicherzellen der verschiedenen Ein-/ Ausgabe-Bausteine ( Input/ Output = Eingabe/ Ausgabe) . Das sind jene Bausteine ( oder Computerchips) in unserem C64, die dafür verantwortlich sind, daß zum Beispiel der Ton aus dem Lautsprecher kommt, daß das Floppylaufwerk auch odrnungsgemäß seine Daten speichert, oder daß, wie oben schon gezeigt, der Bildschirm in dunkelgrauer Farbe dargestellt wird. Wir wollen uns Speziell um zwei bestimmte Chips aus diesem Bereich kümmern, sie tragen die Namen SID und VIC.
SID steht für " Sound Interface Device" was etwa soviel heißt wie " Musikerzeuger"( nicht wörtlich übersetzt, doch das hier trifft die Aufgabe von SID auf den Punkt genau) . Um ihn werden wir uns in einer der nächsten Ausgaben noch kümmern.
VIC ist die Abkürzung für " Video Interface Controller" . Wie sein Name schon verrät ( Überwacher der Videoschnittstelle, oder frei nach J. R. R. Tolkien " Der Herr der Videoschnittstelle"), ist er zuständig für Bildschirmaufbau und Grafik innerhalb unseres Computers. Er wird auch unser Hauptthema sein, um das es sich nächsten Monat drehen wird.
Nun wollen wir noch unsere Speichertabelle zu Ende abhandeln. Da wäre zunächst einmal noch der Bereich von 57344 bis zum Ende des Speichers ( also bis 65535) . Hier haben wir wieder einen ROM-Bereich vorliegen, diesmal allerdings das Betriebssystem-ROM.
Das Betriebssystem ist der wichtigste Teil eines Computers, da in ihm alle Unterprogramme enthalten sind, die zur Steuerung des Computers beim Einschalten und während der Eingabe über die Tastatur unbedingt notwenig sind. Hier liegt das eigentliche Herzstück des C64, ohne das er nur bedingt leben könnte. Wenn wir das aus unserer Sicht als werdende BASIC-Programmierer betrachten, könnte er es sogar überhaupt nicht. Hier muß ich dann abermals auf die Maschinensprache verweisen, denn bei dieser ist es durchaus möglich, den C64 OHNE Betriebssystem zu benutzen, doch ist dies auch hier nur unter - relativgro-ß em Aufwand machbar. Auch werden Sie beim Erlernen der Maschinensprache nicht umhin kommen, sich mit dem Betriebssystem eingehender zu befassen, Sie werden es nach einiger Zeit sogar sehr zu schätzen wissen.
Zum Abschluß noch die Speicherbereiche von 0 bis 40960, deren Funktionen Sie jetzt besser verstehen werden:
Da wäre ja zuerst einmal der Bereich von 0 bis 1024 .
In diesem Bereich findet sich eine Ansammlung von Bytes, die ausschließlich vom Betriebssystem und von BASIC benutzt werden, um bestimmte Werte zwischenzuspeichern. Uns als BASIC-Programmierern bleiben die meisten davon verschlossen, und wir können Sie nur in bedingtem Maße für uns nutzen, doch auch dies zu einem späteren Zeitpunkt.
Dann käme als nächstes das VIDEO-RAM, oder der Bildschirmspeicher, von 1024 bis 2048 . Auf diesen Bereich werden wir nächsten Monat auch noch genauer eingehen, da er, wie sich aufgrund des Namens vielleicht ja schon vermuten läßt, etwas mit VIC zu tun hat. Hier sei nur gesagt, daß in diesem Bereich die Zeichen, wie sie normalerweise immer auf dem Bildschirm stehen, in genau der Reihenfolge abgespeichert sind, wie Sie sie auf diesem abgebildet sehen.
Als letztes hätten wir dann noch den Bereich von 2048 bis 40960 . Zugegebenermaßen wohl der größte Speicherbereich im 64 er. Hier werden in aller Regel die Programmzeilen, so wie Sie sie eingeben gespeichert.
Der LIST-Befehl tut also nichts anderes, als die BASIC-Zeilen, die hier gespeichert sind, Ihnen auf dem Bildschirm darzustellen.
In diesem Bereich finden übrigens gleichzeitig auch alle Variablen Platz, die Sie in Ihren Programmen verwenden.
Hiermit bin ich nun wieder am Ende der Folge angelangt und hoffe, Ihnen nicht zu sehr die Gehirnwindungen mit der Thematik des Speicheraufbaus und des Binärssystems verknotet zu haben. Wie Sie ja merkten, hatten wir diesmal eigentlich kaum etwas mit BASIC zu tun, wenn man einmal von PEEK und POKE absieht.
Doch glaube ich mit diesem Artikel bei Ihnen einen Grundstein für das " wirkliche" Vertändnis von Computern gelegt zu haben, da Sie mit Hilfe der Informationen, die Sie hier und heute erlangt haben, sich viele Phänomene der Informatik sehr einfach und verständlich verdeutlichen können.
Ich darf Ihnen nun noch ein fröhliches Gehirnentknoten wünschen und verabschiede mich bis nächsten Monat, wenn es dann heißt " Von nun an wirds aber bunt - die Grafikprogrammierung als solche", Ihr Uli Basters.

     BASIC-Kurs : "Von Adam und Eva..." (Teil 6)     
     

Herzlich Willkommen zum 6 . Teil unsers BASIC-Kurses.
Nachdem mich meine Mitredakteure letzen Monat wegen Platzmangels aus meiner Sparte geschmissen haben, geht es nun wieder weiter im Text. Allerdings kann ich Ihnen eine weitere kleine Enttäuschung nicht vorenthalten. Ich hatte Ihnen im Mai zwar versprochen, daß wir uns dieses Mal mit der Grafik beschäftigen würden, doch möchte ich dies nun erst einmal aufschieben. Der Grund hierfür liegt darin, daß nach diesem Kurs hier ein Grafikkurs geplant ist. Da habe ich dann auch genügend Platz und Freiheit, Ihnen dieses Thema besser zu erläutern und näher zu bringen.
Gerade die Grafik ist beim C64 ein sehr brisantes Thema, zumal BASIC die Grafikprogrammierung in keinster Weise unterstützt, wie man das von größeren Computern ( ich sage da ja nur " AMIGA" und " AmigaBasic") gewohnt ist. Doch ganau das wird dann Thema dieses Kurses werden, weshalb ich Sie jetzt noch 3 Monate vertrösten muß. Dann wird nämlich der Basickurs beendet sein.
Nun wollen wir aber einmal mit diesem sechsten Basickurs beginnen. Ich möchte Sie nun ein wenig in die Soundprogrammierung des 64 ers einführen, die auch nicht gerade ohne ist, und für die Sie die Informationen über das Binärsystem und den Speicheraufbau des C64 vom letzten Mal genauso, wenn nicht sogar noch mehr, benötigen.
Erinnern wir uns : mit der Soundprogrammierung hat der SID, der Chip der Musik erzeugt, etwas zu tun.
Wir hatten ja gelernt, daß die Adressen mit denen man ihn programmiert im sogenannten I/ O-Bereich ( INPUT-/ OUTPUToder EIN-/ AUSGABE-Bereich) liegen, der sich von Adresse 53248 bis 57344 erstreckt." Puh!" werden Sie sagen," Das sind ja mehr als 4000 Speicherzellen ! Wie soll man sich die denn alle merken !" Doch keine Angst ich kann Sie beruhigen. Der SID belegt lediglich 28 davon. Ebenso wie alle anderen Ein-/ Ausgabe-Bausteine ( es sind derer insgesamt vier, die wir hier allerdings, außer dem SID, nicht behandeln werden), die auch nicht mehr als 50 Bytes in diesem Riesenbereich belegen. Doch Vorsicht. Sie können hier zwar die meisten Adressen mit beliebigen Werten be- schreiben, doch ist es NICHT möglich die nicht benutzten Speicherzellen zu benutzen. Sollten Sie hier einen Wert hineinschreiben, so wird gar nichts passieren, da die adressierte Speicherzelle nämlich physisch, also im Innern Ihres 64 ers, gar nicht existiert. Sie bekommen irgendwelche Werte beim Auslesen mit PEEK geliefert, und beim Schreiben mit POKE wird der zu schreibende Wert einfach, wie bei einer ROM-Speicherzelle, ignoriert.
Doch gehen wir nun einmal zu den Speicherzellen die wir benutzen DÜRFEN. Die sogenannte Basisadresse des SID liegt bei Adresse 54272 . Dies ist die erste Speicherzelle des SID. Sie ist deshalb so wichtig, weil wir sie benutzen wollen, um sogenannte " Register" adressieren zu können. Ein Register ist eine Speicherzelle des SID ( oder eines anderen I/ O-Bausteins) die man mit Hilfe der Basisadresse und der Registernummer anspricht. Hierzu vielleicht ein Beispiel. Mit dem Befehl:
POKE SI+24,15 setzt man die Lautstärke der erzeugten Töne auf" laut" . Hierbei steht die Variable SI für die Basisadresse des SID, wir haben ihr also vorher den Wert 54272 zugeordnet ! Das Register 24 des SID ist für die Lautstärke verantwortlich. Schreibt man hier 0 hinein, so wird der Ton gänzlich abgeschaltet. Mit 15 schalten Sie volle Lautstärke ein. Natürlich können Sie auch alle Werte zwischen 0 und 15 hier benutzen.
Diese sind dann eben je nach dem mehr, oder weniger laut.
Nachdem Sie nun hoffentlich über die Bedeutung eines Registers ausfgeklärt sind, möchte ich erst einmal zu den Grundlagen übergehen. Wie Sie vielleicht wissen verfügt Ihr 64 er über drei " Stimmen" . Das heißt er kann 3 verschiedene Töne gleichzeitig gerenerieren.
Deshalb gibt man einer Stimme des SID auch den etwas päßlicheren Namen " Tongenerator" . Diese sind aufgeteilt in Tongenerator 1,2 und 3 . Jeder dieser Generatoren arbeitet unabhängig von den anderen und kann eigene Töne erzeugen ohne seine Kollegen damit zu stören. Sie können jeden einzelnen von Ihnen mit einer bestimmten " Tonhöhe" und einem bestimmten " Klang" programmieren. Damit Sie dies ein wenig besser verstehen, schlage ich vor, daß wir einmal einen kleinen Ausflug in die Physik machen:
Wie Sie vielleicht wissen besteht ein Ton, so wie ihn das menschliche Ohr hört, aus nichts anderem als einem extrem schnellen Schwingen der Luft. Auch bekannt unter dem Namen " Schall" . Die Art dieses Tones, warum sich Töne also voneinander unterscheiden können, wird von zwei Komponenten bestimmt. Da wäre zum einen die Wellenform und zum anderen die Frequenz. Die Wellenform gibt an, wie die Schwingungen verlaufen. Diese lassen sich durch eine Grafiklinie darstellen, häufig sogar durch eine mathematische Funktion. Ein Beispiel wäre da sie Sinuskurve. Mit ihr lässt sich eine Sinuswelle erzeugen. Dies klingt dann etwa wie eine Oboe. Ein weicher und " perfekter" Klang, da die Wellenform ja dem perfektesten geometrischen 2- dimensionalen Körper zugrunde liegt, dem Kreis.
Jedem der 3 Tongeneratoren Ihres C64 können Sie nun eine eigene Wellenform einprogrammieren, die dann von diesem erzeugt wird. Eine Sinuskurve kriegt der SID zwar nicht ganz hin, doch reicht es immerhin zu einer Dreieckskurve, die der Sinuskurve in Punkto Hochund Tiefpunkten ja schon sehr ähnlich kommt. Sollten Sie jetzt hier nur " Bahnhof, Abfahrt und Koffer geklaut" verstehen, so möchte ich sie mit dem Folgenden noch ein wenig mehr aufklären. Jede Wellenform kann nämlich auch mit Hilfe eines Oszillators als Tonwelle sichtbar gemacht werden. Aus der Schule kennen Sie bestimmt noch diese Experimente, wo dann auf so einem kleinen runden Bildschirm eine merkwürdige Kurve erschien, wenn der Lehrer irgend einen Ton von sich gab ( oder mit Hilfe eines Tongenerators erzeugte) .
Der C64 versteht es nun,4 veschiedene solcher Kurven zu erzeugen, zwischen denen Sie dann auch wählen können, wenn Sie einem Tongenerator eine " persönliche" Note geben möchten. Diese sind die Dreieck-( ich hatte diese Kurve oben schon erwähnt), Rechteck-, und Sägezahnkurve. Dann gibt es da noch eine Wellenform die eher eine Sonderstellung einnimmt, die Rauschkurve. Man kann hier eigentlich nicht mehr von einer Wellenform reden, da das Rauschen nicht nach einer vorgegebenen Kurve erzeugt wird, sonden von verschiedenen Zufallswerten, die den Abstand zum 0- Wert angeben und einfach nur aneinandergereiht werden. So entsteht ein Eindruck des Rauschens.
Die Rechteckskurve nimmt ebenfalls eine Sonderstellung ein, was ihre Programmierung betrifft. Dies werde ich ein weinig später erläutern.
Wie man nun dem SID klarmacht, welche der 4 Möglichkeiten man auf einer Stimme spielen möchte, werde ich Ihnen gleich erklären. Zunächst einmal noch zu der 2 ten Komponente, mit der sie einen Ton beeinflussen können, der Frequenz. Davon haben Sie sicher auch schon einmal gehört. Je höher die Frequenz ist, desto schneller wird die Luft zu Schwingungen angeregt. Es kommen quasi mehr Dreiecksspitzen einer Dreieckkurve ( beispielsweise) in gleichen Zeitabständen an Ihrem Ohr an, als bei einer niedrigeren Frequenz. Dadurch werden die Hörnerven mehr gereizt und es entsteht im Gehirn der Eindruck eines höheren Tones. Dies kann bis zum Schmerz gehen, wenn der Ton besonders laut und intensiv gespielt wird, wie etwa bei einer Sägezahnkurve, oder bei manchen Rechteckkurven ( mit laut meine ich RICHTIG laut - wenn Sie auf einem Rockkonzert einmal nahe den Boxen standen als der Leadgittarist ein Solo von sich gab, dann wissen Sie was ich meine) .
Diese Frequenzen kann man nun auch jedem Tongenerator angeben, so daß dieser dann genau weiß, wie er den Ton zu gestalten hat. Um beispielsweise den Kammerton A zu spielen benötigen Sie eine Frequenz von 440 Hz ( Hertz) . Geben Sie diese dem Computer an, so wird er Ihnen genau diesen Ton vordüdeln. Das hört sich doch ganz einfach an ! Nun ja, ist es allerdings nicht unbedingt. Denn Sie können dem SID nicht einfach die Zahl 440 irgendwo hinschreiben. Dem stehen 2 Dinge im Weg. Erstens einmal benötigt der SID auch noch weitere Angaben über einen Ton, bevor er richtig " loslegen" kann und zweitens gibt es mit der Frequenzangabe auch noch einige kleine Probleme, die etwas mit der Hardware des 64 ers zu tun haben.
Zunächst möchte ich Ihnen eine Übersicht aller SID-Register geben. Anschließend können wir dann richtig anfangen. Ich muß noch hinzufügen, daß ich die Register 25-28 aus Platzgründen ausgelassen habe. Wir werden uns mit diesen sowieso nicht befassen, da deren Funktion für uns kaum von Nutzen ist. Nur als Assemblerroutinen wären diese Register effektiv von Nutzen, und dann auch nur sehr, sehr selten. Nun aber zu unsrer Tabelle :

Register  Adresse  Funktion                          
–––––––––––––––––––––––––––––––––––––––––––––––––––––
  00       54272   Frequenz für Stimme 1 - LO        
  01       54273   Frequenz für Stimme 1 - HI        
  02       54274   Pulsbreite für Stimme 1 - LO      
  03       54275   Pulsbreite für Stimme 1 - HI      
  04       54276   Ton anschlagen und Wellenform für 
                   Stimme 1                          
  05       54277   Hüllkurve ATTACK/DECAY Stimme 1   
  06       54278   Hüllkurve SUSTAIN/RELEASE Stimme 1
  07       54279   Frequenz für Stimme 2 - LO        
  08       54280   Frequenz für Stimme 2 - HI        
  09       54281   Pulsbreite für Stimme 2 - LO      
  10       54282   Pulsbreite für Stimme 2 - HI      
  11       54283   Ton anschlagen und Wellenform für 
                   Stimme 2                          
  12       54284   Hüllkurve ATTACK/DECAY Stimme 2   
  13       54285   Hüllkurve SUSTAIN/RELEASE Stimme 2
  14       54286   Frequenz für Stimme 3 - LO        
  15       54287   Frequenz für Stimme 3 - HI        
  16       54288   Pulsbreite für Stimme 3 - LO      
  17       54289   Pulsbreite für Stimme 3 - HI      
Register  Adresse  Funktion                          
–––––––––––––––––––––––––––––––––––––––––––––––––––––
  18       54290   Ton anschlagen und Wellenform für 
                   Stimme 3                          
  19       54291   Hüllkurve ATTACK/DECAY Stimme 3   
  20       54292   Hüllkurve SUSTAIN/RELEASE Stimme 3
  21       54293   Filter-Grenzfrequenz LO           
  22       54294   Filter-Grenzfrequenz HI           
  23       54295   Resonanz und Filterschalter       
  24       54296   Filtermodus und Lautstärke        

Doch nun frisch ans Werk. Wie Sie ja gesehen haben gibt es hier jeweils 7 Register für jede Stimme. Als aufmerksamer Leser sind Ihnen hierbei bestimmt für Stimme 1 die Register 00,01 und 04 aufgefallen. Mit diesen Registern nämlich können wir unsere Töne beeinflussen, so wie wir das bisher gelernt haben. In Register 00 und 01 wird die Frequenz des Tons für Stimme 1 angegeben und in Register 04 die Wellenform.
Wollen wir nun das Problem lösen, wie wir eine Frequenz, in Hertz gemessen, in diese beiden Register eingeben. Ich hatte ja schon angedeutet, daß dies nicht so einfach sein wird.
Ich hole hierzu einmal ein wenig weiter aus. Vielleicht haben Sie ja schon einmal gehört, daß der C64 mit einer bestimmten Taktfequenz " getaktet" ist, so wie das bei jedem Computer der Fall ist. Ein Mikroprozesor und überhaupt alle logischen Bausteine in einem Computer brauchen so etwas ganz einfach, damit die Arbeiten im Computer geregelt und gleichmäßig ablaufen. Als Herzstück dient hierzu ein Quarzbaustein, der eine bestimmte Taktfrequenz vorgibt. Alle Bausteine greifen sich nun den Takt von diesem Quarz ab und modulieren ihn meistens auf eine eigene Frequenz, mit der sie besser arbeiten können. Der Mikroprozessor in Ihrem C64 arbeitet zum Beispiel mit einer Taktfrequenz von 985 .2484 KHz. Dies ist genau der 18 Teil der Systemtaktfrequenz, die vom Quarz herrührt. Diese beträgt demnach 17734472 Hz. Also knapp 17 .7 MHz. Der SID benutzt nun ebenfalls diese Frequenz. Um nun aus internen Gründen des Aufbaus des SID auf den richtigen Wert zu kommen, mit dem dieser dann die echte Tonfrequenz spielt muß man vorher noch eine kleine Umrechnung vornehmen. Diese folgt der folgenden Formel :
WERT= Tonfrequenz *2'24/ Taktfrequenz Möchten Sie also den Kammerton A, mit 440 Hz, spielen, so müssen Sie erst den SID-Wert hierfür berechnen. Dies sieht dann so aus :

440Hz * 2'24 / 17734472 = 416.25                     

Lassen wir nun noch die Stellen hinter dem Komma wegfallen, so erhalten wir den Wert 416 . Genau diesen Wert müssen Sie jetzt an den SID übergeben, damit dieser einen 440 Hz-Ton erzeugt. Hierbei haben wir allerdings ebenfalls noch ein kleines Problem zu bewältigen. Wie Sie sich errinnern können wir mit dem POKE-Befehl lediglich ein Byte verändern, also 8 Bit.
Die größte Zahl, die Sie mit dem POKE-Befehl also übergeben können ist die Zahl 255(2↑8 Bits -1), die nun folgende Zahl, die 256 also, hat jetzt schon 9 Bits, da ja ein Überlauf stattfand. Ich zeige Ihnen das einmal in Form von (16 stelligen) Binärzahlen:

dezimal    binär                                     
  255      0000 0000 1111 1111                       
  256      0000 0001 0000 0000                       

Nun ist aber die Zahl 416 größer als 255, somit müssen wir zu einem kleinen Trick greifen um sie zu übermitteln. Wir schreiben sie einfach mit 16 Bit, da eine 16- Bit-Zahl maximal den Wert 65535 aufnehmen kann, was für unsere Zwecke vollkommen reicht. Dies sieht dann so aus:

416 (dez.)  =  0000 0001 1010 0000 (bin.)            

Diese 16- Bit spalten wir jetzt ganz einfach in zwei 8- Bit-Zahlen auf. Die Eine nennen wir " höherwertiges Byte", die Andere " niederwertiges Byte" einer 16- Bit-Zahl. Das sähe dann für 416 etwa folgendermaßen aus :
416=0000000110100000 Höherwertiges Byte ( die ersten 8 Bits von links) :

0000 0001 = 256 (dez.)                               
Niederwertiges Byte (die nächsten 8 Bits von links) :

10100000=160 Und siehe da, schon hätten wir unsere Zahl in zwei Bytes zerlegt, die wir nun einzeln, mit Hilfe des POKE-Befehls, an den SID übergeben können. Dieser setzt sie dann intern wieder zusammen und erzeugt dann die Frequenz 440 Hz !
Für diese beiden Frequenzbytes der Stimme 1 sind nun die Register 00 und 01 zuständig. Oben in der Registertabelle waren deren Funktionen beschrieben mit " Frequenz für Stimme 1- LO" und " Frequenz für Stimme 1- HI" . Das " LO" und " HI" steht hierbei für " LOw significant byte" und für " HIgh significant byte" oder höherund niederwertiges Byte. Sie müssen also den LO-Wert von 416, also 160, in Register 00 POKEn und den HI-Wert 1 in Register 01 . Dies sieht als kleines Programm geschreiben dann so aus :

10 SI=54272:REM BASISADRESSE SID                     
20 POKE SI+0,160                                     
30 POKE SI+1,1                                       

Und schon wäre der Kammerton A programmiert. Um dasselbe bei Stimme 2 tun zu können, müssen Sie die Register 07 und 08 benutzen, bei Stimme 3 Register 14 und 15 .
So, die Frequenz wäre gesetzt, aber hören können Sie jetzt noch nichts. Wir müssen zuerst ja noch die Wellenform angeben. Nehmen wir hierzu doch einfach einmal eine Dreieckskurve. Was ist nun zu tun, um dies dem SID klarzumachen ? Hierzu benötigen wir für Stimme 1 das Register 04( analog für Stimme 2 und 3, die Register 11 und 18) . Dieses Register vereint mehrere Funktionen in einem. Die einzelnen Bits in diesem Register haben verschiedene Aufgaben, die erfüllt werden, wenn man das entspechende Bit auf 1 setzt.
Ich möchte Ihnen die Bitbelegung hier einmal anhand einer Grafik darstellen :

MD8907/MD8907-KURS-2.16.hires.png

Die Bits 1,2 und 3 sind für uns unwichtig. Sie aktivieren zu komplexe Funktionen, als daß sie hier in den Kurs passen würden. Für uns sind eher die Bits 4-7 und Bit 0 wichtig. Wie Sie sehen steht jedes dieser Bits ( außer dem 0 .) für eine bestimmte Wellenform. Wir möchten nun eine Dreieckskurve spielen.
Also setzen wir einfach Bit 4 . Die anderen bleiben unberührt und haben somit den Wert 0 . Unser Byte sähe Binär geschrieben dann so aus :
00010000 Das enstpricht der dezimalen Zahl 16( der Wert des 4 .
Bits) . Sollten Sie diese Zahl jetzt in Register 04 schreiben, so wird allerdings immer noch nichts zu hören sein. Der SID benötigt nämlich noch 2 weitere Angaben. Zum Einen müssen wir noch die Lautstärke der vom SID gespielten Musik setzen und zum anderen braucht dieser auch noch eine sogenannte " Hüllkurve", die etwas über den Verlauf des gespielten Tons angibt. Kommen wir jedoch erst einmal zur Lautstärke.
Diese schalten Sie am besten auf volle Lautstärke.
Wir hatten dies ja oben schon einmal. Sie müssen ein- fach den Wert 15( Maximalwert) in das Lautstärkeregister 24 schreiben. Also :
POKE SI+24,15 So. Nun machen wir uns einmal an die Hüllkurve heran.
Physikalisch haben wir den Ton ja nun schon festgelegt. Wir können jetzt allerdings noch seinen Lautstärkeverlauf, WÄHREND er gespielt wird bestimmen, eben mit Hilfe der oben genannten Hüllkurve.
Diese besteht aus 4 Phasen. Diese heißen " Attack-"," Decay-", Sustain-" und " Releasephase" und werden in der eben angezeigten Reihenfolge vom SID durchgegangen. Wozu nun das ganze ?
Wie Sie ja vielleicht wissen ist nicht jeder Ton, der die gleiche Frequenz hat, allerdings von 2 verschiedenen Instrumenten gespielt wird, vom Klang her gleich. Eine Oboe zum Beispiel hört sich " weicher" an als ein Glockenspiel, obwohl die Wellenformen einander sehr ähnlich sind. Das Glockenspiel wird " härter" gespielt als die Oboe. Das heißt, daß beim Anschlagen einer Metalleiste des Glockenspiels der Ton die meisten Schwingungen erzeugt und somit am lautesten klingt. Im Gegensatz zur Oboe, bei der die hindurchgeblasene Luft erst einmal einen Ton erzeugen und quasi " in Schwingung" gebracht werden muß. Ein anderes Beispiel wäre eine Klaviersaite. Schlagen Sie eine Taste auf der Klaviatur an, so wird der Ton anfangs am lautesten sein und nach und nach abklingen.
Dies kann manchmal bis zu 50 Sekunden dauern, wobei die Oboe kaum mehr als 0 .5 Sekunden braucht. Sie sehen also, daß ein Ton einen sogenannten Lautstärkeverlauf bestitzt. Genau diesen Verlauf beschreibt eben die Hüllkurve. Wie Sie in der obigen SID-Tabelle sahen sind die Hüllkurvenregister für den ersten Tongenerator die Register 05 und 06 . In ihnen werden die Werte für die 4 Hüllkurvenphasen gespeichert. Da wir 4 Werte haben, allerdings nur 2 Register, wird dies so gehandhabt, daß jedes Register in zwei 4- Bit-Bereiche aufgeteilt wird. So, daß die vier " höherwertigen" Bits eine, und die vier " niederwertigen" Bits eine andere Phase darstellen. Diese sind folgendermaßen verteilt :

Register   Bits 4-7 (HI)   Bits 0-3 (LO)             
––––––––––––––––––––––––––––––––––––––––             
  05       Attack          Decay                     
  06       Sustain         Release                   

Somit sind Werte von 0-15 für jede Phase möglich (2↑4-1) . Wollen wir nun klären, welche Aufgaben die einzelnen Phasen haben :

1.) Die Attackphase:                                 

Mit ihr kann die Zeit angegeben werden, in der ein Ton von Lautstärke 0 auf die in Register 24 angegebene Lautstärke ansteigt, wobei bei dem Wert 0 diese am schnellsten, und beim Wert 15 am langsamsten erreicht wird. Hier eine Tabelle mit den genauen Werten :

 WERT       ZEIT (in Sekunden)                       
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾                       
  0        0.002                                     
  1        0.008                                     
  2        0.016                                     
  3        0.024                                     
  4        0.038                                     
  5        0.056                                     
  6        0.068                                     
  7        0.080                                     
  8        0.100                                     
  9        0.250                                     
 10        0.500                                     
 11        0.800                                     
 12        1.000                                     
 13        3.000                                     
 14        5.000                                     
 15        8.000                                     
2.) Die Decayphase :                                 

Diese Phase gibt an, in welcher Zeit der soeben in der Attackphase erreichte Wert der Lautstärke, auf den Lautstärkewert absinkt, der als Sustainwert angegeben wird.

3.) Sustain-spanne :                                 

Hier wird ein Wert zwischen 0 und 15 angegeben, der die Endlautstärke nach ablauf der Decay-Phase angibt.

4.) Releasephase :                                   

Wird ein Ton abgeschaltet ( dazu kommen wir gleich noch) dann wird unverzüglich die Releasephase eingeleitet. Sie gibt an in welcher Zeit der Ton von der Sustainlautstärke wieder auf 0 absinkt.
Die Zeitwerte für die Decayund Releasephase können Sie der folgenden Tabelle entnehmen :

 WERT       ZEIT (in Sekunden)                       
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾                       
  0             0.008                                
  1             0.024                                
  2             0.048                                
  3             0.072                                
  4             0.114                                
  5             0.168                                
  6             0.204                                
  7             0.240                                
  8             0.300                                
  9             0.750                                
 10             1.500                                
 11             2.400                                
 12             3.000                                
 13             9.000                                
 14            15.000                                
 15            24.000                                

Angenommen, wir wollten ein Glockenspiel mit dem SID simulieren, dann bräuchten wir einen Ton der schnell auf voller Lautstärke steht und dann auch relativ schnell wieder abklingt. Wählen wir also folgende Werte für die einzelnen Phasen :

Attack   -  00                                       
Decay    -  07                                       
Sustain  -  09                                       
Release  -  01                                       

Die 2 Bytes für die Hüllkuve müßten dann folgendermaßen aussehen :

1.) 0000  0111                                       
     A=0   S=7                                       
2.) 1001  0001                                       
     S=9   R=1                                       

Nun müssen Sie diese Bytes also nur noch ins dezimale System umrechnen und in die Register 05 und 06 poken.
Die Werte wären demnach 7 und 145 . Zugegebenermaßen ist dies eine ein wenig mühselige Arbeit, wenn man nicht gerade über einen Taschenrechner verfügt, der das Binärsystem beherrscht. Deshalb kann das auch ein wenig einfacher gehandhabt werden. Denn ebenso, wie man HIund LO-Bytes bilden kann, lassen sich auch " HIund LO-Halb- Bytes" bilden. Diese heißen dann " Nibble" . Nun müssen Sie nur noch nach einem bestimmten Schema die verschiedenen Werte miteinander zu multiplizieren ( der Umgekehrte Weg der Zerlegung in LOund HI-Byte) . Nämlich nach der Formel :
HI-Nibble *16+ LO-Nibble In unserem Fall hätten wir dann folgende Berechnungen durchzuführen :
Attackund Decay-Byte :0*16+7=7 Sustainund Release-Byte :9*16+1=145 Und schon wären wir am Ziel. Nun gilt es nur noch die Werte im SID zu setzen, also :

POKE SI+5,7                                          
POKE SI+6,145                                        

Das wäre geschafft ! Doch - oh Enttäuschung - es kommt immer noch nichts aus dem Lautsprecher ! ! ! Keine Panik, das ist ganz normal so, denn wir haben noch eine weitere Operation durchzuführen. Der SID weiß jetzt zwar welche Frequenz er zu spielen hat, was für eine Wellenform er unserem Ton geben soll, und welchen Klangverlauf dieser haben soll, damit er aber nun endlich die Hüllkurve abspielt, muß man ihm auch noch mitteilen, wann er dies zu tun hat. Wir müssen ihm also quasi ein " Startzeichen" geben, daß er die Attackphase einleiten darf. Dies geschieht mit Hilfe des 0 . Bits aus Register 04( ich hatte es vorhin schon einmal erwähnt, siehe auch Grafik) . Erst wenn dieses Bit gesetzt wird, beginnt er nämlich die Attackphase einzuleiten. Wir müssen somit also zu dem Wellenform-Wert 16 für die Dreieckskurve auch noch eine 1 addieren, damit dies der Fall ist (1 ist die Wertigkeit des 0 . Bits) . Schreiben Sie also nun folgenden Befehl :
POKE SI+4,17 Nun kommt er endlich aus dem Lautsprecher, unser lang erwarteter Ton. Lange hat es gedauert, doch schließlich und endlich haben wir es doch noch geschafft!
Wie Sie jetzt allerdings schnell merken werden, hört er gar nicht mehr auf zu spielen, sondern brummt munter weiter. Das war allerdings gar nicht der Effekt, den wir erzielen wollten. Der Ton sollte doch eigentlich wieder in der Releasephase abklingen ! Der Grund hierfür liegt darin, daß die Releasephase noch gar nicht eingeleitet wurde ! Dies geschieht nämlich erst, wenn das 0 . Bit in Register 04 wieder auf 0 gesetzt wird. Bitte, probieren Sie - diesmal kommt also nur 16 in dieses Register, da wir ja die Dreieckswellenform ja noch beibehalten möchten, also :
POKE SI+4,16 Und schon hört der Krach auf. Dies ist ein Punkt den Sie beim Soundprogrammieren genauestens beachten sollten. Die Zeit, in der der Ton auf der Sustain-Lautstärke gehalten wird, bestimmen Sie als Programmierer, nicht der SID. Sie müssen ihn erst " von Hand" wieder abschalten. Praktisch läßt sich das etwa mit einer Verzögerungsschleife realisieren.
Sie programmieren einfach eine Schleife, in der der Computer zwar mit dem Abarbeiten der Schleife beschäftigt ist, jedoch nichts tut. Es fehlt ganz einfach der Schleifenrumpf. Hier ein Beispiel :
FOR I=1 TO 100 : NEXT Sie sehen, die Schleife zählt ganz still und heimlich bis 100 . Effektiv tut der Computer jedoch nichts. So können wir das Programm mit Scheinberechnungen quasi" anhalten", damit der SID auch genug Zeit hat, die ersten 3 Phasen auch durchzuspielen. Am besten sehen Sie sich einmal das Programm " MINISOUNDDEMO" auf der Rückseite der MagicDisk einmal an. Hier habe ich alle notwendigen Befehle noch einmal zusammengerafft, damit Sie auch ein kleines praktisches Beispiel haben.
Nun will ich Ihnen noch erklären welch eine Besonderheit die Rechteckskurve auf sich hat, und wofür die Register 02 und 03 benutzt werden. In diesen beiden Registern können Sie nämlich die Pulsbreite der Rechteckskurve für Stimme 1 angeben. Wie Sie oben in der Wellenformgrafik gesehen haben, wird der Abstand, der zwischen den beiden Punkten liegt, an dem die Rechteckskurve von ihrem Tiefstpunkt zu ihrem Höchstpunkt " springt" in der sogenannten " Pulsbreite" angegeben.
Sie können in diesen beiden Registern also ganz einfach den Abstand dieser beiden Rechtecksseiten angeben. Dadurch können Sie den Klang der Rechteckskurve noch einmal drastisch verändern. Mit niedrigen Pulsbreiten gespielt hört sich diese Welle sehr " krächzend" an, fast schon wie ein " Sägezahn" . Je größer die Abstände werden, desto weicher und voller wird der Klang. Hier liegt es an Ihnen, die einzelnen Zustände einmal durchzuprobieren. Es sei nur noch gesagt, daß hier mit einem 12- Bit-Wert gearbeitet wird. Das heißt, daß die Bits 4-7 von Register 03 KEINE Auswirkung auf die Pulsbreite haben. Der maximale Pulsbreitenwert liegt somit bei 2↑12-1, also 4095 . Probieren Sie einfach einmal ein wenig herum, denn, wie heißt es so schön :" Nur die Übung macht den Meister." Wie Sie dies handhaben, sollten Sie ja mittlerweile wissen, ich hatte Ihnen die Problematik von HI-LO- Byte oben ja schon erklärt. Sie müssen hier nur darauf achten, daß Sie im Register 04 auch die Rechteckwellenform einschalten, und daß das HI-Nibble ( Bits 4-7) der Pulsbreite immer 0 ist.
Im übrigen sei noch erwähnt, daß Sie alle hier genannten Vorgänge mit Registern usw. natürlich ebenfalls an den Stimmen 2 und 3 durchführen können. Sie müssen nur in der Registertabelle nach dem entspechenden Äquivalent des Registers für die entspechende Stimme suchen. Sie werden merken, daß diese alle in der gleichen Reihenfolge für die einzelnen Stimmen angeordnet sind. Im übrigen sind die meisten Register des SID nicht auslesbar ( bis auf die der 3 . Stimme) .
Es passiert also dasselbe, wie wenn Sie auf eine der oben erwähnten I/ O-Adressen zugreifen. . .
Ich möchte mich nun bis nächsten Monat wieder verabschieden, wenn wir uns dann ein wenig mit der Datenspeicherung und der Peripherie des 64 ers beschäftigen werden. Sie werden dann auch gleich noch den noch fehlenden Befehlssatz von BASIC 2 .0 kennenlernen.
Ich bedanke mich nun für Ihre Aufmerksamkeit und wünsche ein fröhliches SID-Gedüdels, bis in einem Monat,

                                     Ihr Uli Basters.
 BASIC-Kurs:"Von Adam und Eva" (Teil 7) 
 -------------------------------------- 

Hallöchen da draußen ! Weiter gehts in unserem Basickurs. Nachdem wir nun auch schon ein bißchen Musik machen können mit unserem 64 er, wollen wir uns in diesem Monat einmal um die Dateiverwaltung und die Programmierung der Floppy kümmern. Gleichzeitig lernen Sie dann auch noch etwas über das Ansteuern eines Druckers, da diese beiden Themen nämlich sehr nahe beieinander liegen und die Programmierung von BASIC aus sogar ( fast) gleich ist. Man braucht halt nur noch ein paar Backgroundinformationen zu den einzelnen Geräten. Begeben wir uns nun also in die Außenwelt unseres C64 in die Welt der Peripherie. . .
Beginnen wir mit der Floppy. Die Befehle LOAD und SAVE brauche ich Ihnen ja bestimmt nicht mehr zu erklären. Wenn Sie die nicht kennen würden, würden Sie ja diesen Kurs gar nicht lesen können.
Zu LOAD bleibt nur zu sagen, daß es 2 Arten gibt, diesen Befehl zu benutzen:
Die eine Möglichkeit kennen Sie bestimmt. Nachdem Sie ein BASIC-Programm mit dem Befehl SAVE" PROGRAMM",8 gespeichert hatten, konnten Sie es immer wieder mit LOAD" PROGRAMM",8 in den Basicspeicher Ihres 64 ers laden. Wie ich schon im 5 . Teil dieses Kurses erwähnte, ist das der Bereich von 2048 bis 40960 . Ein BASIC-Programm wird also immer an die Adresse 2048 und folgende geladen. Wenn Sie allerdings einmal ein Maschinenprogramm haben, das an eine andere Speicheradresse geladen werden soll, so müssen Sie LOAD folgendermaßen benutzen :

LOAD"PROGRAMM",8,1                      

Wir haben also an das ",8" noch ein ",1" angehängt. Dieser Appendix teilt LOAD mit, daß nun an eine absolute Adresse geladen wird. Das heißt, an eine Adresse die in dem File schon angegeben wird.
Dies kann von Nutzen sein, wenn wir zum Beispiel Grafikdaten an eine bestimmte Adresse im Speicher laden wollen. Ich werde in dem diesem Kurs anschließenden Grafikkurs hierauf noch einmal näher eingehen.
Im übrigen gibt es auch noch einen weiteren Befehl, der mit LOAD nahe verwandt ist. Ich spreche von dem VERIFY-Befehl.
Diesen benutzen Sie ebenso wie LOAD, nämlich:

VERIFY"PROGRAMM",8                      

Dieser ist nur in Verbindung von BASIC-Programmen sinnvoll, daher auch kein ",1" am Ende.
VERIFY macht nun nichts anderes als ein Programm auf der Diskette mit dem sich im Speicher befindlichen BASIC-Programm zu vergleichen. Sie können hiermit also prüfen, ob auf der Diskette eine andere Version des Programms vorliegt. Sollte das der Fall sein, so meldet sich VERIFY mit " VERIFY ERROR ?" zurück.
Andernfalls schreibt es einfach nur ein " OK" auf den Bildschirm. Das Programm im Speicher, ebenso wie das auf der Diskette, bleiben jedoch komplett erhalten.
Es wird somit also NICHTS an den Programmen verändert!
So. Nach diesem kleinen " Vorgeplänkel" wollen wir uns nun um die " seriösen" Anwendungen in BASIC zusammen mit der Floppy kümmern. Es besteht nämlich auch die Möglichkeit, Daten, wie zum Beispiel Variablen, DIREKT in ein File zu schreiben und sie hieraus wieder auszulesen.
Dies ist sehr sinnvoll, wenn man eine Anwendung schreiben möchte, die irgendwelche Werte zwischenspeichern soll, oder wenn Sie bei einem Spiel die Highscoreliste der Nachwelt erhalten möchten.
Damit wir dieses Problem jedoch richtig angehen können, muß ich erst etwas weiter ausholen und Sie einmal über die Ein-/ Ausgabe in BASIC aufklären.
Alle Geräte, die an Ihrem 64 er hängen, haben, wie Sie vielleicht wissen, eigene Gerätenummern. Die Floppy zum Beipsiel die 8, wie man das am LOAD-Befehl sehen kann. Das ",8" gibt ihm nämlich an, daß er von der Floppy laden soll. Wollten Sie von der Datasette laden ( heutzutage nur noch von wenigen benutzt), so müßten Sie dies mit einem ",1" kenntlich machen ( also LOAD" PROGRAMM",1) . Hier einmal eine Liste aller möglichen Gerätenummern:

Nummer Gerät                            
0 Tastatur                              
1 Datasette                             
2 RS232 - Serielle Schnittstele am User-
  Port für Datenfernübertragung (DFÜ)   
3 Bildschirm                            
4 Drucker 1                             
5 Drucker 2 (am Drucker selbst einstell-
  bar)                                  
8 Diskettenlaufwerk 0 (normal)          
9,10,11 Weitere Diskettenlaufwerke      

Der C64 ist nun so ausgelegt, daß man ihm zuerst einmal sagen muß, mit welchem der oben erwähnten Geräte man arbeiten möchte. Dies geschieht in BASIC mit dem OPEN-Befehl. OPEN ist englisch und heißt " Öffne" . Es heißt nämlich auch, man " öffnet" einen sogenannten Filekanal für ein Gerät.
Damit man nun mit mehreren Geräten gleichzeitig arbeiten kann, ohne hierbei jedesmal den Kanal wieder neu öffnen zu müssen, kann man jeden Filekanal mit einer eigenen Nummer zwischen 1 und 127 versehen, die dann quasi als Kennung dient, wenn man auf einen Kanal zugreift. Tun Sie dies, so weiß unser C64 gleich, mit welchem Gerät er zu kommunizieren hat und handhabt dies dann auch entspechend, da alle Geräte ja in einer besonderen Art und Weise " bedient" sein wollen. Diese Filenummern muß man also ebenfalls dem OPEN-Befehl mit auf den Weg geben, damit er die Gerätenummer auch der richtigen ( Erkennungs-) Filenummer zuordnet. Bei einem Drucker zum Beispiel ( mit der Geräteadresse 4) sähe das dann etwa folgendermaßen aus:
OPEN 1,4 Schon hätten wir einen Filekanal für den Drucker eröffnet, an den wir nun Daten senden könnten. Hierzu wird dann eine kleine Abwandlung unseres mittlerweile altbekannten PRINT-Befehls benutzt - der PRINT#- Befehl. Das Doppelkreuz (#) hier ist sehr wichtig, da BASIC sonst die beiden Befehle ja nicht auseinanderhalten könnte - PRINT ohne "#" gibt ja ausschließlich auf den Bilschirm aus.
Daß PRINT " drucke" heißt, wissen Sie mittlerweile ja auch schon. Das Doppelkreuz ist eine im englischen allgemein bekannte Abkürzung für" Nummer" . Die komlette Übersetzung von PRINT# wäre demnach also " Drucke auf Nummer" . Diese Nummer wird nun anschließend angegeben und stellt die oben erwähnte Filenummer dar. Um nun also Daten an den Drucker zu senden müßten wir, nachdem wir den oben erwähnten OPEN-Befehl durchgeführt haben, folgendes schreiben:
PRINT#1," Das ist eine Datenausgabe" Hier haben wir einmal eine Zeichenkette, wie auch bei PRINT durch Gänsefüßchen eingeklammert, ausgegeben. Ebenso können Sie hier jedoch auch mit Variablen arbeiten, etwa so:

PRINT#1,a$                              
PRINT#1,x                               
PRINT#1,z%                              

Beim Zugriff auf die Floppy ist diese Vorgehenweise nun genau dieselbe. Wir müssen zuerst einen Kanal öffnen und können anschließend mit PRINT# Daten übergeben. Allerdings müssen wir hier wieder ein wenig unterscheiden, denn die Floppy kann nämlich in zwei Richtungen bedient werden; zum einen " Daten schreiben", hierzu benutzt man dann PRINT#, und zum anderen " Daten Lesen" .
Da brauchen wir dann einen neuen Befehl, doch hierzu später. Zuerst einmal müssen wir einen Filekanal für die Floppy öffnen. Dies ist leider nicht mehr ganz so einfach wie beim Drucker ( daher auch zuerst das Beispiel mit selbigem), denn der OPEN-Befehl verlangt für die Floppy mehr Parameter als nur Fileund Gerätenummer. Da wäre nämlich zunächst einmal noch die sogenannte " Sekundäradresse" und dann noch ein entsprechender Filename, damit das Laufwerk auch weiß, mit welchem File wir arbeiten wollen.
Kommen wir zunächst einmal zur Sekundäradresse. Diese gibt an, auf welche Art und Weise wir Daten verarbeiten möchten.
Sie wird in Form einen Zahl angegeben und bezeichnet damit vorher vereinbarte Funktionen. Die Floppy akzeptiert insgesamt 16 Sekundäradressen, die folgende Funktionen belegen:

Sekundäradresse Funktion                
0 Daten Lesen (LOAD)                    
1 Daten Schreiben (SAVE)                
2-14 Daten Lesen ODER schreiben         
15 Sek.adresse für Befehlskanal         

Für uns sind im Augenblick nur die Nummern von 2 bis 14 wichtig, die anderen werde ich Ihnen später erklären.
Zuerst muß ich Sie noch ein wenig über die verschiedenen Filearten der Floppy auflären. Es gibt derer fünf, von denen wir allerdings nur 2 benutzen werden.
Jede der verschiedenen Arten wird in der Fileliste einer Diskette, dem sogenannten Directory ( LOAD"$",8), mit einem kleinen Kürzel versehen, so daß man er- kennt, welche Fileart man vor sich hat.
Programme haben zum Beispiel immer das Kürzel " PRG" . Das kennen Sie ja bestimmt aus vielen Directories. Hier nun eine Liste aller weiteren Filearten:
1 .) PRG - PRoGramm. Diese Fileart ist eigens für Programme reserviet. Die Datenbytes, die an die Floppy gesandt werden, werden in sequentieller Reihenfolge, also ein Byte nach dem anderen, gespeichert. Das PRG-Kürzel gibt an, daß man das Programm mit LOAD in den Speicher des 64 ers laden kann. Alle Programme, die Sie mit SAVE abspeichern, erhalten ebenfalls dieses Filekürzel zur Erkennung.
2 .) SEQ - SEQuenz. Diese Fileart wird genauso wie PRG gehandhabt. Die Daten folgen also Byte für Byte auf der Diskette, mit dem einzigen Unterschied, daß Sie diese Daten NICHT mit LOAD laden können. Es ist quasi ein Erkennungszeichen für Datenfiles von Programmen, aus denen auf diese Files zugegriffen wird.
3 .) REL - RELatives File. Relative Files sind Files, in denen bestimmte Datenblöcke, sogenannte " Records", gespeichert sind. Duch Angabe einer Recordnummer wird NUR dieser Record geladen, und nicht das ganze File.
Reltive Files werden auch " Files mit Wahlfreiem Zugriff genannt" und sind sehr häufig bei Dateiverwaltungsprogrammen zu finden, da durch diese Fileart schnell auf einen bestimmten Datensatz zugegriffen werden kann, ohne gleich die ganze Datei zu durchforsten. Leider ist sie nicht sehr einfach in BASIC zu Programmieren, weshalb wir sie an dieser Stelle auch nicht behandeln werden.
4 .) DEL - DELeted. Files mit diesem Kürzel sehen Sie in der Regel NIE, da diese Fileart lediglich für floppyinterne Anwendungen reserviert ist. Sie gibt an, daß ihr File gelöscht wurde, daß also die von ihm belegten Datenblöcke auf der Diskette wieder benutzt werden können.
5 .) USR - USeR File. Der Aufbau ist derselbe wie bei PRG und SEQ. USR gibt lediglich an, daß das hierin gespeicherte Programm NUR von der Floppy ausführbar ist, also für uns uninteressant.
Wir wollen uns hier nur mit den ersten beiden Arten beschäftigen. Zunächst einmal die SEQuenz-Dateien. Wie Sie oben ja schon lesen konnten ist diese Fileart für Daten im Allgemeinen reserviert. Daß wir das mit den Filearten zuerst noch klären mußten ist deshalb wichtig, da diese Angabe beim OPEN-Befehl ebenfalls mitangegeben werden muß. Dies geschieht zusammen mit dem Filenamen. Hier einmal ein Beispiel, damit Sie wissen wie das öffnen eines Kanals für die Floppy aussieht:

 OPEN 1,8,2,"HIGHSCORE,S,W"             

Dabei ist:

1 - die Filenummer                      
8 - die Geräteadresse (Floppy)          
2 - die Sekundäradresse                 
HIGHSCORE - der eigentliche Filename    
S - die Fileart                         
W - die Betriebsart                     

Sie sehen also, zuerst kommen die uns bisher schon bekannten Parameter dran, also Filenummer und Geräteadresse.
Anschließend, mit einem Komma vom Rest getrennt, folgt die Sekundäradresse, in unserem Beispiel die 2 . Sie könnten natürlich auch alle anderen Nummern von 2 bis 14 benutzen, dies wäre kein Unterschied. Jetzt jedoch zum Filenamen - nachdem Sie auch diesen mit einem Komma vom Rest abgehoben haben folgt, in Gänsefüßchen gesetzt, der eigentliche Filename. Wie Sie jedoch sehen, werden zusammen mit dem Filenamen noch 2 weitere Parameter übergeben. Da wäre zum einen die Fileart, markiert durch den Buchstaben " S" und zum anderen die Betriebsart, hier in unserem Beispiel durch den Buchstaben " W" dargestellt.
Beide Parameter werden wieder mit Kommata vom Filenamen abgetrennt, wobei allerdings zu beachten ist, daß beide sich zusammen mit dem eigentlichen Filenamen in dem Filename-String befinden, so daß die Parameter NAME, FILEund BETRIEBSART" alle in EIN Gänsefüßchenpaar gefaßt sind.
Wie Sie vielleicht schon erraten haben, bezeichet das " S" die Fileart SEQenz.
Wir haben hier also ein sequentielles File geöffnet. Bei einem Programmfile hätten wir hier ein " P" einsetzen müssen. Nun zur Betriebsartkennung. Der Buchstabe " W" im Beispiel oben steht für " Write", zu Deutsch " Schreibe" . Der Kanal wurde also zum Schreiben geöffnet.
Die Floppy erwartet nun, daß Daten an sie gesandt werden, die sie dann auf die Diskette in das angegebene File schreibt. Für uns heißt das nun, daß wir mit Hile von PRINT# jetzt Daten auf den Kanal 1 schicken können und diese auf Diskette gespeichert werden. Senden wir doch einfach einmal etwas an die Floppy:

na$="Fritz Meier"                       
sc=100000                               
PRINT#1,"Highscoreliste"                
PRINT#1,pl$                             
PRINT#1,sc                              

Hier haben wir nun den Highscore von Fritz Meier abgespeichert, der sich auf 100000 Punkte beläuft, indem wir die verschiedenen Werte erst einmal in Variablen definierten und anschließend nacheinander ( sequentiell !) an die Floppy gesendet haben. Sie hätten natürlich die Daten auch dirket schreiben können, wobei der String na$ in Gänsefüßchen hätte stehen müssen und die Zahl ohne, so wie das bei dem String " HIGHSCRORELISTE" zu sehen ist. Wichtig ist, daß Sie jedes einzelne Datum mit einem EINZIGEN PRINT#- Befehl senden, und nicht etwa von Kommata getrennt - wie man das vielleicht nach der Parametertrennung bei OPEN denken könnte. Diese Kommatrennung ist zwar auch möglich, doch bewirkt Sie hier etwas anderes, wozu ich später kommen werde. Außerdem könnten Sie mit Kommatrennung später die Daten nicht mehr so einfach einlesen, doch hierzu ebenfalls später mehr.
Unsere Daten wären jetzt also an die Floppy geschickt und somit gespeichert.
Den Filekanal brauchen wir jetzt nicht mehr. Deshalb müssen wir ihn zuerst noch wieder schließen, bevor wir fortfahren.
Dies ist sehr sehr wichtig, da wir somit nicht nur den Computer entlasten, weil der sich jetzt auch nicht mehr den Kanal " merken" muß, der mit der Floppy zu tun hat, sondern durch ein Schließen des Kanals veranlassen wir gleichzeitig auch die Floppy das File komplett und richtig auf der Diskette anzulegen. Das heißt, daß sie jetzt auch den Eintrag in der Fileliste der Diskette machen und diesem Eintrag auch die entspechenden Daten zuweisen kann. Das Schließen eines Kanals wird in BASIC mit dem Befehl CLOSE durchgeführt. Als Parameter benötigt CLOSE lediglich die Filenummer, in unserem Fall also die 1 :
CLOSE 1 Nun haben wir also das File komplett angelegt. Schauen Sie doch einfach einmal ins Directory - hier sehen Sie nun ein weiteres File, das etwa so aussieht:
1" HIGHSCORE" SEQ Der CLOSE-Befehl muß übrigens ebenfalls beim Drucker, wie auch bei allen Geräten bei denen Sie vorher einen Filekanal mit OPEN öffneten, angewandt werden. Ich hatte dies vorhin nur nicht erwähnt, da es mir zunächst einmal um die Funktion von OPEN ging.
Um die Fortsetzung dieses Kurses zu lesen, wählen Sie bitte den zweiten Teil des Basic-Kurses an.
Jetzt wollen wir aber einmal versuchen, unsere gespeicherten Daten wieder einzulesen. Dies geschieht in etwa nach dem selben Schema. Zuerst müssen wir einen Kanal öffnen:

OPEN 1,8,2,"HIGHSCORE,S,R"              

Wie Sie sehen, sieht dieser OPEN-Befehl fast genauso aus wie der obige. Ich habe hier also dieselben Parameter benutzt, bis auf den Kennungsbuchstaben der Betriebsart. Hier haben wir jetzt ein " R" was einen weiteren Modus umschreibt, nämlich " Read" für " Lese" .
Wir haben also wieder ein sequentielles File geöffnet mit der Filenummer 1, der Geräteadresse 8, der Sekundäradresse 2 und dem Namen " HIGHSCORE", diesmal allerdings zum Lesen, denn wir wollen ja unsere gespeicherten Daten wieder zurückholen. Dies geschieht mit einem neuen Befehl, einer kleinen Abwandlung von INPUT, dem INPUT#- Befehl. Wie Sie sehen ist auch hier einfach nur ein Doppelkreuz angehängt worden. Die Eingabe ist nun ja denkbar einfach. Wir müssen nach INPUT# nur noch die Filenummer unseres Kanal angeben und anschließend, durch Komma getrennt, die Variable, der das einzulesende Datum zugewiesen werden soll, also:

INPUT#1,x$                              
INPUT#1,na$                             
INPUT#1,sc                              

In " X$" hätten wir nun den String " Highscoreliste" gespeichert und in " NA$" den vorhin gepeicherten Namen " Fritz Meier" . In " SC" steht jetzt 100000, die Punktzahl von Fritz Meier.
Sie können diese Daten nun also wieder weiterverarbeiten. Übrigens sollte ich hier vielleicht erwähnen, daß der INPUT#- Befehl, ebenso wie INPUT, NICHT im Direktmodus anwendbar ist. Sie können ihn also ausschließlich NUR in Programmen anwenden. Auch sollten Sie den dazugehörigen OPEN-Befehl in diesem Programm aufführen, und nicht etwa im Direktmodus das File öffnen und anschließend ein Programm mit den obigen INPUT#- Anweisungen starten, da RUN leider die Merktabellen, die sich der 64 er intern über alle geöffneten Filenummern anlegt, wieder löscht. Die Floppy bekommt jedoch davon nichts mit, so daß für sie der Kanal noch offen ist, für den Computer ist er allerdings geschlossen. Sie können sich vielleicht vorstellen, was für ein Chaos hierbei entstehen könnte. . . In solchen Fällen hift es dann immer, einmal kurz die Diskette aus dem Laufwerk zu holen, da die Floppy dann den Kanal ebenfalls ( zumindest intern) schließt. Die Daten können dabei allerdings verloren gehen.
Nachdem wir nun unsere Daten wieder eingelesen haben, müssen wir den Lesekanal natürlich wieder mit CLOSE schließen, also:
CLOSE 1 Nun sollten sie mit SEQ-Files ja bestens umgehen können, was laden und speichern zumindest angehen. Die Floppy kennt jetzt allerdings noch eine weitere Betriebsart. Außer " Read" und " Write" gibt es nämlich auch noch " Append" . Das ist englisch und heißt soviel wie " hinzuoder anfügen" . Mit diesem Modus können Sie also an eine schon früher erstellte Datei weitere Daten anhängen.
Angenommen, Sie wollten vielleicht einen weiteren Highscore abspeichern, dann bräuchten Sie nur einen Floppykanal in der Betriebsart " Append" zu öffnen. Für " Append" kennt die Floppy das " A"- Kürzel, also:

OPEN 1,8,2,"HIGHSCORE,S,A"              

Jetzt können Sie mit Hilfe von PRINT# weitere Daten an das alte File anhängen, nach " Fritz Meier" und 100000 könnten wir nun also auch z. B." Heinz Müller" und 99999 an die Floppy schicken. Bei einem erneuten Einlesen der Datei müßten wir dann noch einmal gesondert alle Daten von vorne bis hinten auslesen.
Kommen wir nun zur Fileart PRG. Wie ich oben ja schon erwähnte, ist diese Fileart nur für Programme reserviert.
Trotzdem kann man sie von BASIC aus ansprechen und auch Daten in PRG-Files speichern. Dies wird ebenso gehandhabt wie mit SEQ, da PRG-Files, physisch gesehen, also im Aufbau auf der Diskette, ebenso angelegt werden, wie SEQ-Files. Der Zugriff auf ein PRG-File ist somit haargenau derselbe, mit dem einzigen Unterschied, daß jetzt an den Filenamen angehängt nicht mehr ein " S" als Parameter für die Fileart, sondern ein " P" für PRG steht. Der OPEN-Befehl für ein PRG-File sähe also folgendermaßen aus:

OPEN 1,8,2,"DATEI,P,R" zum Lesen, oder  
OPEN 1,8,2,"DATEI,P,W" zum Schreiben.   

Ansonsten können Sie ebenso verfahen als hätten Sie ein SEQ-File geöffnet. Eines gibt es allerdings schon noch hierzu zu sagen. Der OPEN-Befehl hat für PRG-Files nämlich noch zwei kleine Sonderheiten eingebaut. Bei den Sekundäradressen hatte ich ja schon einmal angegeben, daß die Adressen 0 und 1 jeweils eine Sonderstellung einnehmen.
Diese lassen sich jetzt sehr einfach erklären, nachdem wir uns mit der Materie der Betriebsart eines Files schon ein wenig beschäftigt haben. Mit der Sekundäradresse 0 können Sie der Floppy nämlich schon gleich angeben, daß Sie ein READ-File ( also ein File aus dem Sie lesen) öffnen möchten.
Gleichzeitig geht diese dann auch davon aus, daß es sich hierbei um ein PRG-File handelt, Sie können damit also die Angabe der Fileund Betriebsart im Filenamen wegfallen lassen. Etwa ähnlich verhält es sich mit der Sekundäradresse 1 . Sie gibt an, daß Sie Daten schreiben möchten, ebenfalls in ein PRG-File.
Somit ergeben sich dann also folgende Vereinfachungen des OPEN-Befehls für PRG-Files:

OPEN 1,8,0,"DATEI" zum Lesen, und       
OPEN 1,8,1,"DATEI" zum Schreiben.       

Wenn Sie allerdings ein PRG-File öffnen, um beispielsweise ein richtiges BASIC-Programm daraus auszulesen, aus welchen Gründen auch immer, so werden Sie mit INPUT# nicht viel Glück haben.
INPUT# verläßt sich nämlich darauf, daß Sie vorher alle Ihre Daten mit PRINT# eingegeben haben, wobei Sie für jedes Datenelement einen eigenen PRINT#- Befehl benutzten. PRINT# arbeitet nämlich eben- so wie PRINT, wenn man keinen weiteren Parameter hinter dem Befehl angibt. Es macht einen sogenannten " Wagenrücklauf mit Zeilenvorschub" . Oder auch " Carriage Return" genannt. In der Praxis wird bei diesem Wagenrücklauf nichts anderes getan, als daß der Cursor lediglich eine Zeile tiefer, in die erste Spalte dieser Zeile befördert wird, und daß eine weitere Ausgabe auf dem Bildschirm an dieser Stelle dann ausgeführt wird.
Der Wagenrücklauf hat auch einen eigenen ASCII-Code ( er ist eines der Steuerzeichen, die eine besondere Funktion erfüllen, wie ich bei den ASCII-Zeichen erwähnte), die 13 nämlich.
Mit einem PRINT CHR$(13) erzwingen Sie also einen solchen Wagenrücklauf.
Probieren Sie das doch einfach einmal mit folgendem Programm aus:

10 PRINT"DAS IST ZEILE 1";CHR$(13)      
20 PRINT"DAS IST ZEILE 2"               

Sie sehen, zwischen den beiden Zeilen ist nun eine Leerzeile, was ja ohne CHR$(13) nicht wäre. Der PRINT#- Befehl sendet nun ebenfalls ein CHR$(13) an die Floppy, nachdem er seine Daten übertragen hat. Beispielsweise die einzelnen ASCII-Code- Bytes der Buchstaben einer String-Variable. INPUT# erkennt nun an diesem Wagenrücklauf, daß hier das Ende des Strings erreicht ist und beendet seine Eingabe. Alle Zeichen, die vor dem Carriage Return kamen werden nun der Variablen zugeordnet, die am Ende von INPUT# steht, jedoch ohne dabei das CHR$(13) mit anzuhängen. Es dient also lediglich als Trennmarke, nicht aber als Datenelement. Das hat aber auch einen entscheidenden Nachteil - sollten Sie einmal in die Verlegenheit kommen, einen Wagenrücklauf mitabzuspeichern, oder sollten Sie nicht wissen, ob der Wagenrücklauf überhaupt in einem File ( z. B. ein PRG-File mit einem BASIC-Programm) existiert, so sollten Sie die Alternative zu INPUT# benutzen, den Befehl GET# . Wie Sie sehen haben wir auch hier ein Doppelkreuz, das für Filenummer steht, das Befehlswort selbst kann man etwa mit " Hole" übersetzen. Der 64 er soll sich also ein Byte von dem Kanal mit der Filenummer, die hinter dem "#" angegeben wird, holen. Dies geschieht wie bei INPUT#, namlich folgendermaßen:
GET#1, A$ Hiermit hätten wir der Variablen " A$" jetzt ein Byte vom Filekanal 1 zugewiesen. Dieses können wir jetzt weiterverarbeiten. Entweder Sie geben es gleich mit PRINT aus, etwa so:
PRINT A$ ;
Oder Sie schauen sich an, ob wir hier überhaupt ein druckbares ASCII-Zeichen vorliegen haben, oder ob es sich hierbei nicht doch um ein Sonderzeichen handelt, indem Sie sich einfach den ASCII-Code des Bytes ausgeben lassen. Etwa so:

A=ASC(A$)                               
IF A=13 THEN PRINT "DAS IST EIN CARRIAGE
RETURN."                                
IF A=19 THEN PRINT "DAS IST DAS         
'HOME'-ZEICHEN."                        

oder einfach :
PRINT ASC( A$) Allerdings gibt es hier noch ein kleines Problem. Da wir ja ein sequentielles File auslesen und bei diesem ein Byte nach dem anderen folgt, wird mit ziemlicher Sicherheit auch irgendwann einmal das letzte Byte über den Kanal gewandert kommen und anschließend ist dann nix mehr los mit Bytes auslesen. Trotzdem aber holt sich GET# immer noch irgendwelche nicht existenten Bytes vom Kanal und übergibt diese an unser Programm, was ja nun nicht unbedingt sein soll. Hier hilft dann eine Sondervariable des 64 ers. Ich spreche von der Statusvariablen " ST" . Diesen Variablennamen dürfen Sie in Ihren Programmen übrigens NIE benutzen, da diese Variable halt für den eben genannten Zweck reserviert ist. BASIC stellt in dieser Variablen nämlich immer den sogenannten Status des Diskettenkanals bereit. Wie Sie sehen ist " ST" ja eine numerische Variable, also liefert sie einen Zahlenwert zurück.
Sollten Sie nun bei einer Abfrage von ST einmal feststellen, daß Sie den Wert 64 beinhaltet, so sind Sie am Ende eines Diskettenfiles angelangt.
Bei allen anderen Zahlen ist dies nicht der Fall. Das Durchlesen eines Files sähe also so aus:

10 OPEN 1,8,0,"PROGRAMM"                
20 GET#1,A$                             
30 PRINT A$                             
40 IF ST<>64 THEN 100                   
50 CLOSE 1                              

" ST" dürfen Sie natürlich auch benutzen, wenn Sie mit INPUT# auslesen. Dies wäre sogar nur sinnvoll und wünschenswert, wenn Sie flexibel arbeiten möchten.
Aus Platzmagel muß ich nun leider die heutige Folge dieses Kurses abschließen.
Nächsten Monat werden wir dann mit einem neuen Hauptprogramm hier in der MD aufwarten können, durch das ich wieder mehr Platz haben werde ihnen die Sprache BASIC näherzubringen. Ich werde nächsten Monat dann das Thema Floppy noch beenden und Sie über die noch fehlenden Befehle von BASIC V2 .0 aufklären. Dann müßten wir eigentlich mit allem durch sein, und Sie sollten das Grundzeug zu einem guten BASIC-Programmierer besitzen. Doch noch sind wir nicht ganz so weit, deshalb verabschiede ich mich jetzt bis nächsten Monat, Ihr

                            Uli Basters.
 Basickurs:"Von Adam und Eva..."(Teil 8)
 ---------------------------------------

Willkommen zum 8 . Teil unseres Basickurses. Ich werde Ihnen heute noch ein klein Wenig über die Floppy erzählen und die etwas kleineren Befehle und Funktionen von BASIC 2 .0 erwähnen.
Wie Sie sich vielleicht erinnern hatten wir letzten Monat etwas über Sequenzund Programmfiles gehört. Hierbei lernten wir die Befehle OPEN, CLOSE, PRINT#, INPUT# und GET# kennen. Zum Schluß erklärte ich Ihnen noch die Bedeutung der Statusvariablen ST.
Es gibt jetzt noch ein paar Dinge über ST zu sagen, die ich Ihnen letzte Woche verschwiegen hatte. Wie ich ja damals schon erwähnte, kann man durch den Wert 64 in ST feststellen, daß man am Ende eines Files angelangt ist, doch ST ist noch für 3 weitere Zwecke zu gebrauchen.
Hier eine kleine Übersicht:
Wert Bedeutung

--------------                          
 64  Fileende erreicht                  
 66  Über das Fileende herausgelesen    
  1  Fehler beim Schreiben              
128  Floppy nicht angschlossen          

Die 64 kennen wir ja. Sobald wir das letzte Byte gelesen hatten, stand diese Zahl in ST. Sollten wir jetzt, aus welchem Grund auch immer, noch ein weiteres Byte auslesen wollen, so werden wir ein falsches, da nichtexistentes Datenbyte zurückerhalten. Nach diesem Lesevorgang meldet ST den Wert 66, was heißt, das wir versucht haben, ein Byte aus einem mittlerweile schon bis zum Ende gelesenen File auszulesen. Sollte also einmal ein solcher Fehler auftreten, so werden Sie wissen, woran es liegt.
Als nächstes gibt es da noch die 1 als Wert für ST. Sollten Sie diesen Wert einmal zurückbekommen, so bedeutet das, daß beim Schreiben in eine Write-Datei ein Fehler aufgetreten ist.
Zum Beispiel, wenn die Diskette voll ist.
Das wäre dann ein " DISK FULL"- Error. In In diesem Fall ist es dann sinnvoll, den Fehlerkanal der Floppy abzufragen, was ich Ihnen gleich noch erklären werde.
Zunächst noch zu dem 4 . Fall für ST, der Wert 128 . Er gibt an, daß die Floppy, die angesprochen werden sollte, nicht angeschlossen beziehungsweise ausgeschaltet ist. Doch gibt es da noch ein kleines Problem. Sollte nämlich ein solcher Fehler einmal auftreten, so wird der 64 er das momentan laufende Programm sofort abbrechen und einen " DEVICE NOT - PRESENT"- Error auf dem Bildschirm ausgeben. Das ist ja nicht unbedingt im Sinne eines komfortablen Programms, außerdem erhalten wir somit noch nicht einmal die Gelegenheit, uns einmal den Inhalt von ST anzuschauen, da der C64 hier schneller reagiert und VOR einer eventuellen Abfrage abbricht. Doch es gibt eine Möglichkeit, diesen kleinen Nachteil zu umgehen. Wie wir ja im 5 . Teil gelernt haben, kann man mit dem POKE-Befehl Bytes im Speicher unseres C64 verändern.
Damals hatte ich den Bereich von Speicherzelle 0 bis 1024 als wenig interessant für uns erklärt, da dort hauptsächlich Speicherzellen untergebracht sind, die für interne Arbeiten im 64 er reserviert sind. Doch hier und da bieten sich in diesem Speicherbereich schon noch ein paar sinnvolle Anwendungen. In unserem Beispiel wäre da die Speicherzelle 768 .
Ändert man nämlich den Inhalt dieser Speicherzelle in den Wert 61 um, so wird jegliche Ausgabe von Fehlermeldungen ganz einfach unterdrückt. Dies ist in unserem Fall ganz interessant, zumal wir die Meldung von " DEVICE NOT PRESENT" ja gar nicht gebrauchen können.
Wir können diese Abfrage ja auch selbst über ST vornehmen. Nachdem wir dies dann jedoch taten, sollten wir unsere Fehlermeldungsausgabesperre jedoch wieder zurücknehmen, da ja auch noch ganz andere Fehler auftreten könnten, zum Beispiel ein " SYNTAX ERROR" . Das Programm würde in diesem Fall versuchen weiterzuarbeiten und das könnte verheerende Folgen haben. Rückgängig machen wir unsere Sperre mit dem Befehl " POKE768,139" .
Jetzt ist wieder alles beim Alten und Fehler brechen das Programm wieder wie gewohnt ab und drucken ihren entsprechenden Text dann auch aus. Hier noch ein kleines Beispiel zur Abfrage, ob die Floppy angeschlossen ist:

10 POKE 768,61 :REM FEHLER SPERREN      
20 OPEN 1,8,15 :REM FLOPPY ANSPRECHEN   
30 CLOSE 1     :REM KANAL WIEDER ZU     
40 POKE 768,139:REM FEHLER ZULASSEN     
50 IF ST=128 THEN PRINT "FLOPPY IST NICH
T ANGESCHLOSSEN !"                      

Nun möchte ich Ihnen noch ein wenig den Sinn und die Bedeutung des Befehlskanals der Floppy näherbringen. Letzten Monat hatte ich Ihnen ja schon erzählt, daß dieser Kanal eine Sonderstellung einnimmt, weshalb er auch eine eigene Sekundäradresse, nämlich die 15, besitzt ( siehe auch Tabelle von letztem Monat) .
Über jenen Befehlskanal kann man nun kleine Befehle an die Floppy senden, die diese zu bestimmten Operationen veranlaßt, wie zum Beispiel das Löschen eines Files, oder das Formatieren einer Disk.
Letzteres möchte ich hier einmal anhand eines Beispiels erläutern. Wie Sie ja vielleicht wissen, muß man eine Diskette, bevor man sie mit Daten beschreiben kann," formatieren", das heißt, man gibt der Floppy den Befehl die Diskette quasi zu " ordnen", da sich die Magnetspuren auf ihr, wenn sie ganz frisch als Leerdiskette aus der Fabrik kommt, noch in einem undefinierten Zustand befinden.
Man muß sie durch das " Formatieren" also in einen definierten Zustand bringen, so daß Daten auf sie geschrieben werden können. Dies ist von Computer zu Computer verschieden, der C64 beziehungsweise die Diskettenlaufwerke desselben, benutzen ein eigenes Format, MS-DOS- Rechner, sei das ein XT oder AT benutzen wiederum ein anderes, weshalb eine Diskette für jeden Rechnertyp eigens formatiert werden muß.
Bei der C64- Floppy ( normalerweise die 1541, es gibt jedoch auch noch andere, zum Beispiel die 1571, die auch für den C128 benutzbar ist) geschieht dies durch den Befehlskanal. Hierzu müssen wir diesen erst einmal öffnen. Zu diesem Zweck brauchen wir natürlich erst eine Filenummer, dann die Geräteadresse ( in unserem Fall die 8- jedoch können Sie durch die Geräteadressen von 9-11 auch andere Zusatzlaufwerke ansprechen) und schließlich und endlich die Sekundäradresse, die für den Befehlskanal immer15 ist. Filenamen oder ähnlichs brauchen wir zunächst einmal nicht, also öffnen wir den Kanal mit:
OPEN 1,8,15 Nun, da er geöffnet ist, können wir über diesen Kanal eine Vielzahl von Befehlen, mit Hilfe von PRINT#, an die Floppy schicken, die diese dann ausführen wird, wobei wir uns dann nicht mehr darum kümmern müssen. Ich hatte ja angedeutet, daß ich dies anhand eines Format-Befehls einmal demonstrieren wollte. Beim Formatieren ist noch zu beachten, daß wir der Floppy einen Diskettennamen und ein 2 stelliges Identifikationskürzel mit auf den Weg geben. Diese sogenannte " ID" ist quasi ein Erkennungszeichen für die Floppy, damit sie verschiedene Disketten voneinander unterscheiden kann. Der Diskettenname an sich darf maximal 16 Zeichen lang sein, beide Parameter werden, ähnlich wie bei OPEN durch ein Komma getrennt, an die Floppy übergeben. Hier also einmal ein PRINT#- Befehl, der die Floppy eine Diskette formatieren läßt, mit dem Namen " NEUE DISKETTE" und der ID-Kennung " MD" :

PRINT#1,"N:NEUE DISKETTE,MD"            

Unter der Vorraussetzung, daß wir den Befehlskanal vorher mit der Filenummer 1 geöffnet hatten und daß Sie auch eine Diskette eingelegt hatten, beginnt nun die Floppy, die Diskette zu formatieren.
Doch VORSICHT, vergewissern Sie sich, daß Sie auf jeden Fall eine Diskette eingelegt haben, die KEINE, beziehungsweise, für Sie UNBRAUCHBARE Daten enthält ! ! ! Jegliche Art von Daten auf dieser Diskette wird nämlich mit dem Format-Befehl UNWIDERRUFLICH gelöscht!
Nicht also, daß Sie sich versehentlich diese Ausgabe der MD löschen, wir übernehmen für eine solche Fehlbehandlung keine Haftung und auch keine Garantie!
Wenn Sie sichergehen möchten, daß eine Ihrer Disketten nicht durch einen zufälligen Irrtum gelöscht wird, so kleben Sie doch einfach einen kleinen Schreibschutzstreifen auf die Schreibschutzkerbe dieser Diskette. Dann wird nämlich bei einem vermeindlichen Format-Befehl abgebrochen. Diese Kerbe finden Sie, wenn Sie die Diskette von vorne betrachten, an der rechten Seite, ich meine den etwa 7-8 mm langen und 4 mm breiten viereckigen Einschnitt.
Sollte nun mit der eingelegten Diskette alles in Ordnung und der Schreibschutz an ihr auch nicht vorhanden sein, so werden Sie feststellen, daß die Floppy nun läuft und munter diese Diskette formatiert. Gleichzeitig blinkt auch noch der Cursor bei unserem 64 er, wenn Sie obigen PRINT#- Befehl im Direktmodus eingaben. Für uns heißt das, daß die Floppy nun eigenständig arbeitet und wir mit dem 64 er weiterarbeiten können, ohne uns an dem Formatiervorgang zu stören.
Dies ist jedoch nur so lange der Fall, bis wir einen weiteren Befehl an die Floppy senden, dann wartet der 64 er nämlich intern auf ein " OK" von der Floppy, daß diese mit dem Formatiervorgang fertig ist. Dann erst schickt er den nächsten Befehl nach. Da der CLOSE-Befehl ebenfalls die Aufmersamkeit der Floppy beansprucht ist dies bei ihm genauso der Fall. Schließen wir also den Befehlskanal jetzt wieder mit " CLOSE 1", so müssen wir warten, bis das Formatieren beendet ist. Im Programm ist das eigentlich ganz brauchbar, da es sonst vielleicht ein paar Probleme geben könnte mit der Koordinierung der Operationen von Floppy und Rechner.
Ihnen ist bestimmt oben in dem PRINT#- Befehl aufgefallen, daß ich vor den Diskettennamen und der ID noch den Prefix " N:" gesetzt hatte. Das war das Erkennungszeichen für die Floppy, daß es sich bei diesem Befehl um einen Formatbefehl handelt. Das " N" steht nämlich für " NEW", was soviel bedeutet, wie " NEUanlegen der Diskette" . Logisch, die übersetzung, nicht wahr? Auf diese Weise können auch noch andere Befehlskürzel an die Floppy gesandt werden, die dann auch andere Aufgaben erfüllen. Jeder Befehlsbuchstabe wird grundsätzlich mit einem Doppelpunkt (" :") von den Parameterangaben getrennt. Im Folgenden möchte ich Ihnen noch die 3 wichtigsten, da für uns als Basicprogrammierer am sinnvollsten, Floppybefehle erklären.

Der Scratch-Befehl "S" :                

Mit dem " S"- Befehl können Sie die Floppy dazu veranlassen ein oder mehrere Files auf der eingelegten Diskette zu löschen.
" Scratch" heißt nämlich soviel wie " kratzen", und somit geht es hier um das sinnbildliche " wegkratzen" eines Files von der Oberfläche der Diskette.
Der Scratchbefehl wird folgendermaßen benutzt :

PRINT#1,"S:FILENAME1,FILENAME2,FILENAME3
,...,FILENAME n"                        

Sie können also beliebig viele Filenamen anhängen, jeweils durch Kommata getrennt, die dann gelöscht werden. Das Ganze steht natürlich wieder in Anführungsstrichen, da dies der PRINT#- Befehl ja so verlangt. Möchten Sie nur EIN File löschen so gehen Sie analog vor, lassen Sie jedoch das Komma am Ende des Filenamens weg und schließen Sie den Befehl gleich mit einem Gänsefüßchen ab.

Der Rename-Befehl "R" :                 

Mit diesem Befehl können Sie ein schon vorhandenes File auf der Diskette mit einem neuen Namen versehen." Rename" bedeutet nämlich nichts anderes als " umbenennen" .
Dies funktioniert folgendermaßen:

PRINT#1,"R:NEUER NAME=ALTER NAME"       

Sie geben nach dem " R:"- Prefix also einfach den Namen an, den das File von nun an haben soll. Anschließend geben Sie mit Hilfe eines "="- Zeichens an, daß das File mit dem nun folgenden Namen umbenannt werden soll.

Der COPY-Befehl "C" :                   

Mit diesem Befehl können Sie 2 oder mehrere SEQuentielle Files auf der Diskette zu EINEM File, von ebenfalls sequentieller Art, zusammenkopieren. Dies geschieht so:

PRINT#1,"C:NEUER NAME=ALT1,ALT2,ALT3,...
,ALT n"                                 

Sie geben also einfach den neuen Filenamen an, den die zusammenkopierten Files haben sollen und schreiben, nachdem Sie ein "=" eingefügt haben, die Files die zusammenkommen, durch Kommata getrennt hintereinander auf. In dem neuen File werden dann die alten Files in der von Ihnen vorgegebenen Reihenfolge stehen.
Soviel zu den einzelnen Befehlen. Nun möchte ich Ihnen noch etwas über den Fehlerkanal erzählen. Wie ich oben schon erwähnt hatte, kann die Statusvariable ST ja auch den Wert 1 annehmen. Das heißt, daß ein Fehler beim Schreiben aufgetreten ist. Ich hatte da ja schon angedeutet, daß man anschließend einmal den sogenannten " Fehlerkanal" auslesen sollte, um festzustellen, welcher Fehler im Einzelnen aufgetreten ist. Dieser Fehlerkanal wird ebenfalls über den Befehlskanal der Floppy angesprochen. Fehlermeldungen sind übrigens die einzigen Daten, die man vom Befehlskanal LESEN kann, ansonsten wird nur dorthin GE-SCHRIEBEN. Aus diesem Grund weiß die Floppy direkt, daß sie, falls gelesen wird, die aktuelle Fehlermeldung senden soll. Diese besteht aus insgesamt 4 Teilen und sieht etwa folgendermaßen aus:

FNR,NAME,SPUR,SEKTOR                    

Die Abkürzungen bedeuten :

FNR    : Dies  ist die Fehlernummer. Je-
         der Floppyfehler hat  eine  be-
         stimmte Nummer, mit der man ihn
         identifizieren  kann. Eine Auf-
         listung  dieser  Fehler,  ihrer
         Nummern  und  ihrer  Bedeutung,
         finden  Sie   im   Anhang   des
         Floppyhandbuchs.               
NAME   : Dies  ist  eine  kleine Kurzbe-
         schreibung  des  Fehlers.  Wenn
         Sie zum Beispiel auf eine schon
         randvolle  Diskette  (0  BLOCKS
         FREE) zu  schreiben  versuchen,
         so kommt hier die Meldung "DISK
         FULL" von der Floppy.          
TRACK  : Die Tracknummer,  auf  der  der
         Fehler  auftrat.  Was ein Track
         ist, paßt  nicht  unbedingt  in
         den  Rahmen  dieses  Kurses und
         soll an anderer Stelle  genauer
         erklärt werden.                
SEKTOR : Die Sektornummer des Tracks auf
         dem der  Fehler  auftrat.  Auch
         dies  gehört nicht hier hinein,
         weshalb wir es  ebenfalls  aus-
         lassen werden.                 

Wie Sie sehen, haben wir hier drei numerische Werte ( FNR, TRACK, SEKTOR) und einen Stringwert ( NAME) . Um nun die Fehlermeldung auszulesen, müssen wir zunächst wie gewohnt, den Befehlskanal mit OPEN öffnen. Anschlißend müssen die einzelnen Parameter mit INPUT# ganz einfach ausgelesen werden, dies geschieht denkbar einfach, nämlich mit Hilfe dreier numerischer und einer $- variable.

INPUT#1, NR,NA$,SP,SE                   

Nun können wir die eben geholte Fehlermeldung ausdrucken :

PRINT NR;NA$;SP;SE                      

Sollten Sie zum Beispiel versucht haben, ein File zu laden, daß auf der Diskette gar nicht existiert, so haben Sie nun folgendes auf dem Bildschirm stehen:

 62 FILE NOT FOUND 0  0                 

Wir sollten übrigens auch nicht vergessen, den Fehlerkanal wieder zu schließen. Hier noch einmal das komplette Programm, das Sie übrigens auch auf der Rückseite dieser Ausgabe der MAGIC DISK 64 finden werden ( unter dem Namen " FEH-LERKANAL") :

10 OPEN 1,8,15                          
20 INPUT#1,NR,NA$,SP,SE                 
30 CLOSE 1                              
40 PRINT NR;NA$;SP;SE                   

Wenn übrigens gar kein Fehler vorliegt ( rote LED der Floppy blinkt NICHT) dann werden Sie folgende Meldung erhalten:
0 OK 00 Als Nächstes möchte ich Ihnen noch einen kleinen Befehl zeigen, der ebenfalls etwas mit der Datenausgabe zu tun hat.
Er wird hauptsächlich in Zusammenhang mit einem Drucker benutzt, kann aber auch für andere Geräte angewandt werden.
Ich spreche von dem sogenannten CMD-Befehl. Mit CMD können Sie alle Ausgaben, die sonst auf den Bildschirm gemacht werden, auf einen logischen Filekanal leiten, den Sie vorher natürlich mit OPEN geöffnet hatten.
Angenommen, Sie wollten ein Programm auf dem Drucker ausgeben, dann müßten Sie lediglich folgendes eingeben :

OPEN 1,4:CMD 1                          
LIST                                    

Wir öffnen hier also einen Filekanal mit der Filenummer 1 und der Geräteadresse 4 für den Drucker. Anschlißend geben wir dem C64 bekannt, daß alle Ausgaben von nun an auf den Kanal mit der Nummer 1 umgelenkt werden sollen. Wenn Sie nun LIST eingeben dann erscheint Ihr Programmlisting nicht auf dem Bildschirm, sondern es wird ohne Umwege gleich an den Drucker geschickt. Auf diese Weise können Sie beispielsweise in Programmen, die irgendwelche Tabellen auf dem Bildschirm ausdrucken, ganz einfach diesen Tabellendruck auch auf den Drucker umleiten, indem Sie nämlich VOR der Druckroutine für den Bildschirm einen CMD-Befehl einschieben.
Man könnte dies vielleicht sogar mit einer IF-THEN- Abfrage lösen, wobei zuerst der Benutzer nach dem Ausgabegerät gefragt wird und anschließend entschieden wird, ob ein CMD ausgeführt werden soll oder nicht.
Eine andere Anwendungsweise wäre vielleicht die Möglichkeit, ein Programm in Form von ASCII-Zeichen in einem File zu speichern, um es, zum Beispiel mit Hilfe eines Terminalprogramms, in eine Mailbox zu schicken. In diesem Fall müßten Sie nur ein sequentielles File zum Schreiben öffnen, mit CMD die Ausgabe auf dieses File umleiten und das Programm dann LISTen.
Eines wäre jedoch noch zu beachten. Damit Sie nämlich wieder aus dem CMD-Befehl herauskommen, um dann die Ausgabe wieder auf den Bildschirm zu leiten, müssen Sie einen einfachen PRINT#- Befehl nachschieben, ohne Parameter, etwa so:
PRINT#1 Wobei hier anstelle der "1" auch jede andere Zahl stehen könnte, je nachdem, welche Filenummer Sie vorher beim OPEN-Befehl benutzt hatten, auf dessen geöff- neten Kanal Sie dann die Ausgabe umleiteten.
Anschließend sollte man den Kanal auch noch schließen, also:
CLOSE 1 : REM ( je nach Filenummer) Damit hätten wir das Thema Peripherie abgeschlossen. Ich muß Ihnen nun noch etwas über Variablen erzählen. Wie wir diese handhaben und vor allem, wie wir deren Namen wählen, hatten wir ja schon im 1 . und 2 . Teil dieses Kurses geklärt.
Es gibt allerdings noch eine weitere Art Variablen zu benutzen, nämlich durch die Definition von sogenannten Variablenfeldern. Dies klingt vielleicht etwas merkwürdig, doch werden Sie gleich verstehen, was damit geimeint ist.
Ein Feld, oder eine Fläche, hat ja, wie Sie vielleicht aus dem Geometrieunterricht noch wissen, zwei Ausdehnungen.
Zum einen die Länge und zum anderen die Breite. Man sagt auch " ein Feld hat zwei Dimensionen" . Es ist also ein Objekt der Zweiten Dimension. Ebenso gibt es eine Erste Dimension, die alle Strecken beinhaltet. Diese haben nur eine einzige Ausdehnung, nämlich die Länge.
Diesen Begriff der Dimension kann man nun auch auf Variablen übertragen. Es gibt nämlich in BASIC die Möglichkeit, mehrere Variablen mit dem gleichen Namen anzulegen, die alle jedoch voneinander unterschieden werden, indem man ihnen einen sogenannten Index gibt. Das heißt, daß jeder Variable eine bestimmte Zahl nachgestellt wird, die eine ganz bestimmte Variable darstellt. Anwendungsgebiete gibt es hierfür wie Sand am Meer. Angenommen, Sie möchten ein Programm schreiben, daß alle Adressen Ihrer Bekannten und Verwandten speichert. Gehen wir einmal davon aus, daß dies maximal 100 bis 200 an der Zahl sind. Möchten Sie nun alle diese Namen in " norma- len" Variablen speichern, so würden Sie jedesmal einen neuen Variablennamen heraussuchen müssen, damit BASIC diese voneinander unterscheiden kann. Stellen Sie sich einmal das Chaos vor, daß Sie dann in einem Programm hätten.200 Variablen, von denen Sie nicht mehr genau wissen was zu wem gehört. Wenn man davon ausgeht, daß Sie vielleicht zu jedem Namen auch noch Straße, Hausnummer, Wohnort und Telefonnummer speichern wollen, dann müßte Herr Müller aus der Bahnhofstaße 37 in 8000 München und der Telefonnummer 089/12345678 etwa in folgenden Variablen verteilt werden :

AX$="Herr Mueller"                      
FR$="Bahnhofstraße"                     
KL=37                                   
OG=8000                                 
TA$="Muenchen"                          
XD$="089/12345678"                      

Sie sehen also, wir haben hier wahllos verteilte Variablen vor uns, die nichts über ihren Inhalt aussagen, da jeder nur erdenkliche Variablenname genutzt werden muß. Stellen Sie sich doch nur die meterlangen Listings von IF-Abfragen vor, die man machen müßte, um eine ganz bestimmte Adresse herauszufinden. Außerdem wüßte man noch nicht einmal welche Variablen zu einer Adresse gehören. Deshalb gibt es die Feldvariablen. Sie sollen hier eine Abhilfe schaffen. Auf diese Art und Weise können nämlich beispielsweise alle Namen in einem Variablennamen zusammengeafßt werden, oder alle Straßennamen, oder alle Städtenamen. . .
Doch wie wirds gemacht? Dazu wollen wir jetzt kommen. Zuerst müssen wir eine Variable " dimensionieren" . Im Klartext heißt das, daß wir einen Namen für das Variablenfeld und die maximale Anzahl der in ihm zu speichernden Daten, festlegen müssen.
In unserem Fall einer Adressverwaltung nehmen wir ( beispielsweise) den Variablennamen NA$ für " Name" . Die Dimensionierung wird mit einem eigenen BASIC-Befehl durchgeführt, dem DIM-Befehl. Bei diesem wird zuerst der Name des Variablenfeldes angegeben und anschließend seine maximale Ausdehnung. Wir wollen also 200 Stringvariablen im Feld NA$ speichern. Deshald also diese Anweisung:
DIM NA$(200) Schon wäre unser Feld dimensioniert. Wir haben hier ein eindimensionales Feld vor uns, dem DIM-Befehl wird zuerst der Feldname und dann die maximale Anzahl aller Datenelemente, in Klammern gesetzt, nachgestellt. In dem Feld NA$ können wir nun also 200 Variablen unterbringen.
Um jetzt ein einzelnes dieser 200 Datenelemente adressieren zu können, müssen wir seine Indexnummer, ebenfalls in Klammern gesetzt, einfach dem Feldnamen nachstellen. Diese Datenelemente eines Feldes werden übrigens genauso gehandhabt, wie die Variablenart in der sie dimensioniert wurden. Wir haben hier einen Stringvariablennamen angegeben, also haben wir auch 200 Stringvariablen vordefiniert. Demnach sind auch die Zuweisungen ausgelegt. Wie bei Strings auch geben Sie den obigen " Variablennamen" an und weisen ihm mit Hilfe des "="- Zeichens eine Zeichenkette zu. Etwa so:
NA$(0)=" HERR MUELLER" Hier haben wir dem 0 . Datenelement den String " Herr Mueller" zugewiesen. Sie erinnern sich ja : der Computer fängt immer bei 0 an zu zählen, dementsprechend ist das 0 . Datenelement der erste Eintrag in unserem Datenfeld. Doch wir müssen hier keineswegs einer numerischen Reihenfolge der Variablenzuweisung vor- gehen. Vielmehr können Sie ebenfalls auch Zuweisungen von Werten bei numerisch größeren Variablen vornehmen. Sie haben hierbei also freie Hand. Wie wärs, wenn wir " Herrn Schultze" im 134 . Datenelement unterbrächten, kein Problem:
NA$(134)=" SCHULTZE" Doch die eigentliche Stärke der Feldvariablen liegt nicht darin, daß man sie in einem Namen zusammenfassen kann, sondern vielmehr, daß man mit Hilfe einer Schleife gezielt ein Feld nach einem bestimmten Datensatz durchsuchen kann, ohne dabei großen Programmieraufwand leisten zu müssen. Angenommen wir wollten Herrn Schultze in unserem Datenfeld wiederfinden, dann wäre folgendes Programm schnell und einfach geschrieben:

100 FOR I=0 TO 200                      
110 IF NA$(I)="HERR SCHULTZE" THEN 130  
120 NEXT                                
130 PRINT"HERR  SCHULTZE STEHT IM DATENS
ATZ NR.";I                              

Wenn wir nun die anderen Daten ebenfalls so anlegen, daß wir 200 Datenelemente darin speichern können und den einzelnen Feldelementen mit dem Index 134 ebenfalls die zu Herrn Schultze gehörigen Daten zuordnen, so können wir ganz einfach mit Hilfe der Variablen I auf alle Datenelemente der Adresse von ihm zugreifen, etwa so:

200 PRINT NA$(I) :REM NAME              
210 PRINT SR$(I) :REM STRASSE           
220 PRINT NR(I)  :REM HAUSNUMMER        
230 PRINT PL(I),OR$(I) :REM PLZ UND ORT 
240 PRINT TE$(I) :REM TELEFONNUMMER     

Und schon wäre die gesamte Adresse von Herrn Schultze ausgedruckt, da wir ja vorher die einzelnen Elemente ebenfalls den Feldelementen mit der Nummer 134 zuweisen wollten. So einfach ist es dann beispielsweise einen bestimmten Datensatz zu finden. Auch beim Abspeichern haben wir keine Probleme, wir brauchen lediglich eine Schleife zu programmieren, die alle Datenelemente des Feldes von 0 bis 200 in ein WRITE-File schreibt.
Wie Sie sahen, hatten wir ein eindimensionales Feld dimensioniert. Es hatte also nur EINE Ausdehnung. Man kann dies jedoch beliebig erweitern. Wie wäre es denn mit einem zwei-, drei-, oder gar vierdimensionalen Feld? Bitte:

DIM A$(1000,10)                         
DIM B%(10,3)                            
DIM C(5,5,5)                            

Mit diesen Dimensionierungen haben wir nun also veranlaßt, daß beispielsweise ein Feld mit dem Namen A$ für 1000 Datenelemente dimensioniert wurde, von denen jedes einzelne wiederum 10 weitere Datennelemente aufnehmen kann. Diese können Sie dann folgendermaßen ansprechen:
PRINT A$(523,3) Hier hätten wir das 3 . Datenelement des 523 . Hauptelements von A$ ausgedruckt, dies kann man in beliebig vielen Dimensionen weiterführen, soweit diese sinnvoll sind. Eines sollte ich jedoch noch sagen: bei einer Dimensionierung von Variablen reserviert der C64 für jede einzelne Variable einen bestimmten Speicherbereich. Bei FLOAT-Variablen ist dies besonders Speicherintensiv. Pro Variable gehen nämlich 5 Bytes flöten, die nicht mehr für andere Variablen benutzt werden können. Hierbei ist es übrigens egal, ob diese Variable nun einen Inhalt hat oder nicht. Man muß sich also immer ausrechnen, wieviel Speicherplatz so ein Feld einnimmt, um nicht in Speichermangel zu kommen, denn dann bricht der 64 er unweigerlich mit einem " ? OUT OF MEMORY ERROR" ab. Wollten Sie beispiel ein 6- dimensionales Feld mit jeweils 4 Datenelementen dimensionieren, so könnten Sie mit dem Speicherplatz knapp werden:

DIM A(3,3,3,3,3,3)                      

Wenn Sie sich wundern, warum hier immer 3 anstatt 4 steht, wie ich ja eben sagte, so denken Sie bitte daran, daß das 0 . Datenelement ebenfalls mitzählt, also 0,1,2,3= vier Elemente. Oben bei A$ hätte ich auch schreiben sollen, daß wir dort anstatt 1000 sogar 1001 Elemente, mit 11 anstatt 10 Unterelementen dimensioniert haben, doch habe ich dies zum besseren Verständnis zu jenem Zeitpunkt weggelassen.
Wir hätten hier also 4*4*4*4*4*4=4↑6 Variablen dimensioniert, für die alle 5 Bytes Speicherplatz reserviert werden, also 4↑6*5 Bytes oder 4096*5 Bytes =20480 Bytes, das entspricht etwa 2/3 des gesamten Basicspeichers (38911 Bytes) .
Es ist also keineswegs egal, wieviele Elemente Sie dimensionieren. Suchen Sie ein Optimum heraus. Bei Stringund Integervariablen ist der Speicherplatzverbrauch etwas geringer.
Probieren Sie doch einfach einmal aus, wie viel Platz Sie haben.
Kommen wir nun noch zu drei weiteren kleinen Befehlen, die ich ihnen noch erklären muß. Da wäre zunächst einmal der DEF FN-Befehl. Dies ist eigentlich nichts weiter als eine kleine Programmierhilfe, die man zwar nicht unbedingt braucht, die jedoch ganz nützlich sein kann, wenn man strukturiert programmieren möchte. FN ist quasi ein Variablenkürzel für eine vorher definierte Funktion. Sie müssen an dieses Kürzel nur noch einen FLOAT-Variablennamen anhängen ( also einen Variablennamen OHNE "%" oder "$") . Auf diese Weise können Sie häufig benutzte Funktionen, zum Beispiel komplexere Rechenformeln vordefinieren, die Sie dann durch einen simplen und kurzen Aufruf komplett durchrechenen können. Dies ist rechenzeitund speicherplatzsparend.
Doch hier die Praxis. Zunächst wollen wir erst einmal eine Funktion vordefinieren, hierzu benutzt man das DEF-Statement:

DEF FNAX(X)=(10/X)*SIN(X)+201           

Hier haben wir der FunktioN AX die Formel (10/ X)* SIN( X)+201 zugeordnet. Das " X" in Klammern der Definition muß immer mit angehängt werden. Möchten Sie nun einmal das Ergebnis der Formel ausgedruckt haben, wenn Sie für X beispielsweise den Wert 7 einsetzen, so müssen Sie dies folgendermaßen tun:
PRINT FNAX(7) Schon erhalten Sie ein Ergebnis. Die Möglichkeit eine Funktion zu definieren eignet sich gut für Kurvendiskussionsprogramme, da Sie bei einer Funktionsberechnung natürlich auch Variablen verwenden können. So zum Beispiel die Lauf- variable einer Schleife, die eine Wertetabelle ausdruckt.
Als Nächstes hätten wir da den WAIT Befehl. Mit ihm können wir den 64 er darauf warten lassen, daß eine Speicherzelle einen anderen Wert annimmt. Als Beispiel nehme ich hierzu einmal die Speicherzelle 198, aus dem oben schon genannten Speicherbereich für interne Aufgaben unseres Computers. In dieser Spicherzelle wird nämlich vom Betriebssystem zwischengespeichert, wieviele Tasten schon vom Benutzer gedrückt wurden, ohne daß das dazugehörige Zeichen ausgedruckt wurde. Wenn Sie sich im Direktmodus befinden steht hier nie mehr als der Wert 1 drin, da der 64 er die Tastendrücke schneller druckt, als Sie sie tippen können. Doch während eines laufenden Programms kann diese Zahl auch schon einmal bis zu 10 ansteigen. Deshalb wollen wir vor der Abfrage dieser Speicherzelle besser eine 0 hineinPOKEn.
Ich möchte Ihnen nämlich nun zeigen, wie man ganz einfach ein Programm zum Anhalten bringt, so, daß es auf einen Tastendruck wartet. Hier ein Beispiel:

10 POKE 198,0:WAIT 198,1:POKE 198,0     

Hier löschen wir zuerst einmal jeglichen Inhalt der eben genannten Speicherzelle, um sicherzugehen, daß hier auch wirklich nichts drinsteht. Mit dem folgenden WAIT-Befehl warten wir auf das Ereignis, daß eine Taste gedrückt wird, daß also eine 1 vom Betriebssystem in die Speicherzelle 198 geschrieben wird. Ist dies der Fall, so fährt der 64 er mit dem Programm fort, wo wir dann gleich noch einmal die Zelle 198 löschen, damit das eben eingegebene Zeichen nicht doch noch einmal irgendwann eingelesen werden kann und irgendwelche, nicht gewollte, Funktionen im Programm verursacht.
Als drittes noch kurz der SYS-Befehl.
Dieser Befehl ist für BASIC-Programmier eigentlich wenig wichtig. Mit ihm kann man den 64 er dazu veranlassen die BASIC-Ebene zu verlassen und ein Maschinenprogramm an einer bestimmten Speicheradresse auszuführen. Der Befehl " SYS 49152" zum Beispiel, startet ein Assemblerprogramm, das in Speicherzelle 49152 beginnt. Wenn Sie übrigens mehr über Assembler bzw. Maschinensprache wissen möchten, so möchte ich an dieser Stelle darauf hinweisen, daß wir, die Redaktion der MAGIC DISK 64, planen, etwa Anfang nächsten Jahres einen Assemblerkurs auf einer eigenen Diskette quasi als Sonderausgabe, herauszubringen. Wenn es soweit sein wird, werden wir Sie dann auch auf jeden Fall noch rechtzeitig informieren. Der Kurs wird übrigens ebenfalls von mir sein, falls Sie also meine Erklärungen für einsichtlich und einfach halten, so wird diese Diskette ein Muß für alle angehenden Assemblerprogrammie- rer unter Ihnen sein.
Der letzte Teil des Basickurses sollte dies sein. Aber das Basic V2 .0 beinhaltet noch ein paar weitere Befehle. Diese sind besonders bei der Programmierung der Grafik wichtig, weswegen sie eigentlich im sich anschließenden Grafikkurs abgehandelt werden sollten.
Da aber zu befürchten ist, daß die eigentliche Beschreibung und Erklärung dieser Befehle im Rahmen eines Grafikkurses zu kurz gerät, haben wir uns entschlossen, diese letzten Befehle in einem weiteren, nun aber endgültig letzten Basickursteil abzuhandeln.
Diesen neunten Teil finden Sie in der Oktoberausgabe der Magic Disk. Im November werden wir dann aber voll in die Grafikprogrammierung einsteigen.

                         Ihr Uli Basters
 ASICKurs: "Von Adam und Eva..."(Teil 9)

Hallihallo, da sind wir wieder. Entgegen allen Gerüchten, die ich das letzte Mal aufgestellt habe, ist der Basickurs jetzt doch noch einen Teil länger. Wir haben uns dazu entschlossen, daß es doch besser ist, wenn dieser Kurs hier komplett abgeschlossen ist, so daß es keiner langwierigen Erklärungen mehr benötigt, wenn wir uns ab nächten Monat an die Grafik machen werden.
Heute kommen nun noch die ultimativ letzten Basicbefehle an die Reihe, mit denen sich auch noch einiges anfangen läßt. . .

1.) Die Stringfunktionen :              

Wie diese Überschrift schon verrät, bietet uns BASIC V2 .0 eine Fülle von Funktionen, mit denen wir auf einfachste Art und Weise Stringvariablen verändern und manipulieren können. Was kann man darunter verstehen? Nun, vielleicht ist Ihnen ja schon im letzten Teil aufgefallen, daß ich dort ein sequentielles File mit dem Befehl :

OPEN 1,8,2,NA$+",S,W"                   

zum Schreiben geöffnet hatte. Vielleicht haben Sie sich gefragt, was dieses "+"- Zeichen bewirken soll. Nunja, wie wir dann ja feststellten, diente es dazu, die beiden Stringketten ( zum einen der String in NA$ und zum anderen das ", S, W") miteinander zu verknüpfen. Stünde beispielsweise der String " FILENAME" in NA$, so hieße das für den OPEN-Befehl, daß er hier die Gesamtzeichenkette " FILENAME, S, W" vor sich hat. Der notwendige Appendix ist somit direkt an den veränderbaren oder variablen Text in NA$ angehängt worden. Genau dies ist auch als Variablenzuweisung möglich, wie es das folgende Programm demonstriert :

10 A$="STRINGS KOENNEN "                
20 B$="MIT '+' VERKETTET "              
30 C$=A$+B$+"WERDEN!"                   
Nach  Ablauf des Programms haben wir nun
also in A$ den Text  "STRINGS KOENNEN ",
in  B$ den Text "MIT ↑+↑ VERKETTET " und
in  C$  "STRINGS KOENNEN MIT '+' VERKET-
TET WERDEN!" stehen.                    

Umgekehrt, beim Zerlegen eines Strings, verhält sich dies allerdings etwas schwieriger. Sie können hier leider nicht mit dem Minuszeichen ("-") arbeiten. Dazu haben wir allerdings die Stringfunktionen LEFT$, RIGHT$ und MID$ zur Verfügung, die sogar noch viel besser arbeiten, als es mit "-" möglich wäre. Mit Ihnen kann man nämlich einen String gezielt in Stücke zerhacken, ohne dabei großen Aufwand zu haben.
Zum einen wäre da LEFT$ . Mit dieser Funktion können wir einen Teil aus einer Stringvariablen isolieren, der von LINKS nach RECHTS reicht. Hierzu übergeben wir LEFT$ ganz einfach den zu bearbeitenden String und, durch ein Komma voneinander getrennt, die Anzahl der zu übernehmenden Buchstaben an. Dies geschieht etwa folgendermaßen :

A$="BASIC IST TOLL"                     
PRINT LEFT$(A$,5)                       

Nach dieser Befehlssequenz sollten Sie dann nur die 5 Buchstaben " BASIC" auf dem Bildschirm stehen haben. Es wurden also die ersten 5 Buchstaben aus dem String A$ herausisoliert.
Ebenso verhält es sich nun mit RIGHT$, nur daß nun die Buchstaben von RECHTS nach LINKS isoliert werden, wobei sie ihre Reihenfolge jedoch beibehalten, nicht also rückwärts geschrieben sind !
Hier ein Beispiel :

A$="BASIC IST TOLL"                     
PRINT RIGHT$(A$,4)"                     

Nun erhalten Sie also die 4 letzten Buchtaben des Strings A$, den Text " TOLL" .
Wem das noch nicht genügt, der kann auf MID$ zurückgreifen. MID$ stellt quasi eine Mischung aus LEFT$( von " Links") und RIGHT$( von " Rechts") dar. Sie können hiermit, wie der Befehl schon sagt, eine Zeichenkette " aus der Mitte" eines Strings herausisolieren. Hierbei müssen wir, wie bei den beiden Verwandten von MID$ auch, erst einmal den zu Untersuchenden Stringnamen angeben, gefolgt von der Nummer des Buchstabens, von dem an wir die folgenden Buchstaben übernehmen möchten, und der Anzahl der Buchstaben, die übernommen werden sollen; alle Parameter jeweils durch Kommata getrennt.
Den Text " IST" aus unserem Beispielstring " BASIC IST TOLL" können wir also folgendermaßen isolieren :

A$="BASIC IST TOLL"                     
PRINT MID$(A$,7,3)                      

Hier werden also ab dem 7 . Buchstaben des Strings A$,3 Buchstaben herausisoliert: das Wort " IST" .
Jetzt werden Sie sicher sagen," Na schön und gut, doch wofür kann man denn so etwas brauchen ?" Zugegeben, viele Anwendungen finden die Stringfunktionen vielleicht nicht, doch kann ich Ihnen ein höchst wichtiges Problem aufzeigen, das geradezu " wie geschaffen" für unser Thema ist : die Eingaberoutine eines Textadvetures zum Beispiel.
Wenn Sie diese Art von Spielen kennen, so werden Sie sicher wissen, daß die Eingaben an das Programm meist mit Hilfe einer Kommandozeile abgewickelt werden, über die die einzelnen Befehle an das Programm gehen. Sie wissen sicher auch, daß solche Befehle in aller Regel aus Verben und Objekten bestehen, wie zum Beispiel " NIMM BUCH" . Hier haben wir also ein Verb, das angibt WAS getan werden soll und ein Objekt MIT DEM wir etwas tun wollen. Nun gilt es also diesen Kommandostring in seine einzelnen Unterworte aufzusplitten, damit wir keine Probleme bei der Erkennung der Worte bekommen. Wir müssen also in unserem String nach Leerzeichen suchen, die die Worte ja voneinander trennen, und bis zu dieser Stelle ein Wort isolieren. Damit unser Beispiel nicht komplizierter wird, als es in diesem Rahmen sein soll, setzen wir einmal vorraus, daß nur 2 Worte in der Eingabe vorkommen, daß also der Anfang eines Strings, bis zum Leerzeichen, ein Wort bildet, und alles, was danach folgt, ein weiteres. Erschwerend kommt noch hinzu, daß wir ja nicht wissen WIE LANG der gesamte Eingabestring ist. Doch dieses Problem können wir mit Hilfe einer weiteren Stringfunktion lösen, der LEN-Funktion. Diese funktioniert denkbar einfach, wir müssen nämlich lediglich den Namen des zu untersuchenden Strings, in Klammern gesetzt, nach dem Befehlswort LEN angeben. Etwa so:

10 A$="OEFFNE TRUHE"                    
20 A=LEN(A$)                            

Danach steht in A der Wert 12, denn soviele Buchstaben enthält die Variable A$ . Nun können wir uns um die Analyse des Strings kümmern. Zunächst einmal eine Schleife, mit deren Hilfe wir feststellen wollen, an welcher Stelle in unserem String sich das Leerzeichen befindet. Hierzu bedienen wir uns dann MID$ . Er holt sich jeweils nur EINEN Buchstaben aus unserem String, damit wir prüfen können welches Zeichen wir vor uns haben :

30 FOR I=1 TO A                         
40 X$=MID$(A$,I,1) :REM NUR EIN ZEICHEN 
50 IF X$<>" "THEN NEXT                  

Die Schleife holt sich hier also nur solange Zeichen aus dem String, wie diese ungleich dem Leerzeichen ("") sind.
Ist dies nicht mehr der Fall, so sind wir an dem Punkt angelangt, wo die Worte getrennt werden. In der Laufvariable I ist nun die Stelle des Leerzeichens in unserem String gespeichert. Wir brauchen uns die einzelnen Komponenten nur noch mit Hilfe von LEFT$ und RIGHT$ in eigenen Variablen zuweisen. Hierbei ist noch zu beachten, daß wir beim ersten Wort auch das Leerzeichen am Ende mitbekommen würden, würden wir I so benutzen. Da dies jedoch nur behindernd ist brauchen wir also lediglich alle Buchstaben bis I-1 herauszuisolieren. Bei dem zweiten Wort müssen wir dann auch erst noch berechnen, wieviele Stellen wir von Rechts gebrauchen können, das tun wir mit Hilfe der Formel A-I. Das ganze sieht dann folgendermaßen aus :

60 W1$=LEFT$(A$,I-1)                    
70 W2$=RIGHT$(A$,A-I)                   
80 PRINT"DAS ERSTE WORT IST  : ";W1$    
90 PRINT"DAS ZWEITE WORT IST : ";W2$    

Wir haben also nun ein kleines Anwendungsbeispiel für die bisherigen Stringfunktionen durchgeführt. Nebenbei haben wir da dann auch noch LEN kennengelernt. BASIC kennt aber noch 4 weitere Stringfunktionen. Zwei davon kennen wir bereits, CHR$ und ASC, weshalb ich nicht mehr auf diese eingehen werde, doch es gibt noch zwei weitere.
Zum einen wäre da STR$ . STR$ liefert ganz einfach den String einer numerischen Variablen, so wie sie mit PRINT ausgedruckt worden wäre. So können Sie zum Beispiel auf einfache Art und Weise eine INTEGERoder FLOAT-Variable einer Stringvariablen zuweisen, wobei der String dann halt die ASCII-Werte der einzelnen Ziffern enthält. Zum Rechnen können Sie diesen String natürlich nicht mehr verwenden, jedoch kann diese Funktion manchmal ganz von nutzen sein. Hier einmal ein Beispiel :

A=1989                                  
X$=STR$(A):REM IDENTISCH MIT 'X$="1989"'

Hiermit hätten wir also der Stringvariablen X$ den String "1989" zugewiesen und können diesen nun weiterverarbeiten.
Beispielsweise gibt es da eine Formel zur Berechnung des Wochentages anhand des reinen Datums die mit Parametern wie " Jahrhundert" oder " Jahrzehnt" arbeitet.
Hierzu bietet es sich dann an mit LEFT$ und RIGHT$ eben jene Parameter zu isolieren und mit der nun folgenden Stringfunktion wieder in eine Zahl zurückzuwandeln.
Die Funktion von der ich rede heißt VAL und tut genau das umgekehrte wie STR$ .
Angenommen, wir hätten das Jahrhundert aus "1989" mittlerweile herausisoliert und fein säuberlich in der Variablen JH$ gespeichert. Dann könnten wir den String "19" mit folgendem Befehl ganz einfach zur Zahl 19 machen:
JH= VAL( JH$) Das wars schon. Sie können nun wie gewohnt mit JH rechnen, denn dort haben wir nun tatsächlich den numerischen Wert 19 stehen, und nicht etwa die Zeichenkette "19" .
Soviel zum Thema Stringfunktionen, machen wir nun weiter mit den ominösen Befehlen, die eigentlich erst im Grafikkurs gekommen wären, ich werde Sie Ihnen hier jedoch anhand eines anderen Beispiels erläutern:

2.) Datenhandling im Programm :         

Bestimmt haben Sie schon einmal ein Basicprogramm aus einer Zeitschrift abgetippt, die NICHT über den Vorteil der Magic Disk 64 verfügte, daß die Programme zum Heft alle auf einer Diskette mitgeliefert werden. Dabei mußten Sie mit ziemlicher Sicherheit ( denn dies kommt häufig vor) auch lange Kolonnen von Zeilen abtippen, in denen am Anfang das Befehlswort DATA stand, gefolgt von vielen Zahlen, alle durch Kommata voneinander getrennt. Wie dieser Befehl schon sagt, werden hier DAT( A) enwerte abgelegt. Auf ein Programm selbst hat er eigentlich wenig Einfluß - er wird ganz einfach von BASIC überlesen. Nur in Zusammenhang mit einem weiteren Basicbefehl hat DATA überhaupt einen Sinn, ich spreche von dem READ-Befehl. Im übrigen könnte dieser ohne DATA auch wenig anrichten, die beiden hängen also fest zusammen und voneinander ab. READ ist( wie immer) englisch und heißt " LESE" .
Wir können den Computer also hiermit anweisen ein Datenelement zu LESEN - und woher nimmt er sich dieses Datenelement? Natürlich von einem DATA-Statement! READ liest nun also das erste Datenelement hinter der ersten DATA-Anweisung im Programm in eine Variable ein, die wir ihm schlicht und einfach nachstellen.
Ich gebe zu, daß es langsam vielleicht etwas langweilig erscheint immer wieder das Beispiel eines Textadventures durchzukauen, doch paßt dieses Beispiel hier genau hin und erklärt hoffentlich eindeutig, wozu READ und DATA notwendig sind.
Also angenommen, Sie wollten ein Textadventure schreiben, das mehrere Verben und mehrere Objekte ( wie das ja, schon oben beschrieben, zu JEDEM Textadventure gehört) verstehen soll. Zuerst haben wir einmal die Eingabe vom Spieler in seine Einzelteile zerlegt und in W1$ das Verb und in W2$ das Objekt gespeichert. Nun geht es darum zuerst einmal das eingegebene Verb zu analysieren und mit dem Programmwortschatz zu vergleichen. Hierzu benutzen wir ein Variablenfeld ( Sie erinnern sich an das letzte Mal. . .) in dem alle Verben gespeichert werden sollen. Damit das bei einem Programm, das vielleicht 100 Verben verstehen soll nicht in Arbeit ausartet, wollen wir die einzelnen Verbdaten mit Hilfe einer Schleife den Variablen zuordnen. Hierzu legen wir alle Verben in DATA-Zeilen ab und lesen sie, eins nach dem anderen, ein und weisen sie somit einer Variablen in unserem Feld zu. READ liest also immer das nächste Element aus einem DATA-Statement aus, solange bis es nichts mehr zu lesen gibt. Das sollten Sie wissen, damit READ nicht zuviele Daten einzulesen versucht. Hier einmal ein Beispiel, bei dem ich 7 Verben in dem Variablenfeld VE$( X) speichern möchte. Wie die Schleife schon zeigt, werden hier auch nur 7 Datenelemente gelesen,(6 Elemente plus das 0 . Element) .

10 DIM VE$(6)                           
20 FOR I=0 TO 6:READ VE$(I):NEXT        
30 DATA NIMM,GIB,OEFFNE,SCHLIESSE,SCHLAG
E,DRUECKE,RUFE                          

Somit hätten wir uns also das mühsehlige Auflisten von Variablenzuweisungen gespart. Sie müssen doch zugeben, daß folgendes etwas umständlicher wäre :

10 VE$(0)="NIMM"                        
20 VE$(1)="GIB"                         
30 VE$(2)="OEFFNE"                      
40 VE$(3)="SCHLIESSE"                   
und so fort...                          

Doch nicht genug, in DATA-Statements kann man nicht nur Strings ablegen, sondern auch INTEGERoder FLOAT-Werte und das dann noch bunt gemischt:

100 DATA 100,3.14,HALLO,2.689,BASIC,12  

Alles worauf wir dann beim Lesen achten müssen, ist, daß die einzelnen Elemente auch den entsprchenden Variablentypen zugeordnet werden. Es ist Ihnen ja mit Sicherheit klar, daß wir nicht einfach so einen Text einer INTEGER-Variablen zuweisen können oder ähnliches.
Allerdings gibt es noch zwei Besonderheiten, die man in Zusammenhang mit DATA erwähnen muß. Sie werden nämlich ganz schöne Probleme bekommen, sollten Sie einmal versuchen, ein Komma (",") in Ihren Strings zu verwenden, die bei DATA abgelegt sind. Wie wir wissen dient das Komma ja zur Trennung der einzelnen Elemente, was für den Computer heißt, daß wir ihm da zwei einzelne Elemente, anstatt nur einem gegeben haben. Machen Sie also niemals folgenden Fehler:

100 DATA HALLO,IHR!                     

Hier haben wir nämlich die beiden Strings " HALLO" und " IHR" abgelegt, anstatt dem eigentlich gewollten Text " HAL-LO, IHR!" In diesem Fall müssen wir den abzulegenden String dann ganz einfach in Anführungszeichen setzen, damit er richtig erkannt wird, also :

100 DATA "HALLO,IHR!"                   

Und schon bekommen wir auch das, was wir wollen. Es bleibt noch zu erwähnen, daß dies derselbe Fall bei dem Doppelpunkt (" :") und bei Leerzeichen ("") der Fall ist. Sollten Sie also einmal in einem Stringelement ein Komma, einen Doppelpunkt oder ein Leerzeichen enthalten haben, so müssen Sie dieses Element UN-BEDINGT in Gänsefüßchen setzen. Bei Strings, wo dies nicht zutrifft können Sie sie auch weglassen ( müssen aber nicht) .
Das zweite, was noch zu sagen wäre, ist, daß man manche Datenelemente auch abkürzen kann. Das spart zum einen Speicherplatz und zum anderen läuft das Programm dann später auch schneller ab. Wenn man nach einem Komma, das ja zur Trennung der einzelnen Datenelemente dient, ein weiteres Komma nachstellt, also praktisch KEIN Datenelement angibt, so interpretiert unser 64 er diesen Datensatz als den Wert 0 . Hier ein kleines Beispiel:

100 DATA 200,,,10,,,                    

Diese Zeile entspicht haargenau dem folgenden Ausdruck und bewirkt auch genau dasselbe:

100 DATA 200,0,0,10,0,0,0               

Der Unterschied ist, daß wir weniger Tipparbeit hatten und somit Speicherplatz gespart haben, UND daß die erste DATA-Zeile auch noch schneller abgear- beitet werden kann - mit einem Wort, nur Vorteile.
Als Nächstes sollte ich vielleicht noch erwähnen, daß READ grundsätzlich immer das ERSTE Datenelement aus dem ERSTEN DATA-Statement zuerst liest. Es ist dabei egal, WO sie Ihre DATAs im Programm unterbringen, READ liest rigoros alles durch, solange bis es keine Daten mehr finden kann. Hierauf sollten Sie immer achten, denn sonst kann es zu einem " OUT OF DATA ERROR" kommen. Sie sollten auch wissen, daß READ sich quasi " merkt" bis zu welchem Datenelement es schon gelesen hat. Dieser Merkspeicher ändert sich solange nicht, bis Sie das Programm wieder mit RUN starten. Es wird hierbei also der Merkspeicher wieder auf das allererste Datenelement zurückgesetzt, so daß Sie die Daten wieder von vorne lesen können.
Für diese Funktion gibt es übrigens sogar einen eigenen BASIC-Befehl. Er heißt RESTORE, was soviel heißt wie " zurücksetzen" . Er tut haargenau dasselbe was auch unter anderem bei RUN passiert ( nämlich das Zurücksetzen des DATA-Merkspeichers), nur daß Sie ihn mitten im Programm aufrufen können, ohne hierbei das Ganze von vorne starten zu müssen. RESTORE braucht übrigens keine Parameter.

 3.) Die kleinen, aber feinen,   Sonder-
funktionen.                             

Im letzten Abschnitt dieses Artikels möchte ich mich noch ein wenig um ein paar kleine Sonderfunktionen kümmern, die BASIC so bietet. Diese kann man nicht einfach unter einem Überbegriff zusammenfassen, denn jede Funktion erledigt jeweils eine in sich abgeschlossene Aufgabe. Fangen wir einmal mit einer der Wichtigsten dieser Funktionen an, der RND-Funktion :
RND steht für RaNDom, was soviel heißt wie Zufall. Mit dieser Funktion können wir uns Zufallszahlen liefern lassen, wie sie in einer Fülle von Spielprogrammen ihre Verwendung finden. Erst einmal zur Arbeitsweise von RND. Mit dem Ausdruck RND( X) liefert Ihnen der C64 einen Zufallswert zwischn 0 und eins, wobei der Wert von X keine Rolle spielt ( X ist eine Variable) . Da man aber meist wenig mit solchen Dezimalbrüchen zwischen 0 und 1 anfangen kann, gibt es auch eine besondere Formel, mit denen man sich auch ganze Zahlen ( also OHNE Kommastellen) in einem vordefinierten Wertebereich abrufen kann. Diese Formel lautet folgendermaßen:
ZU= INT( RND(1)* Y)+ X Wobei X für die untere, und Y für die obere Zahlengrenze steht. Wollten wir also ein kleines Lottoprogramm schreiben, a la "6 aus 49", so müßte unser Ausdruck folgendermaßen lauten :

ZU=INT(RND(1)*49)+1                     

Ich habe hier einmal die Werte von X und Y schon direkt eingesetzt. Natürlich könnten Sie auch unsere allgemeine Formel benutzen und vorher in X und Y bestimmte Werte festlegen.
Es sei jedoch noch zu erwähnen, daß die Zufallszahlen, die RND liefert nicht unbedingt " zufällig" sind. Der 64 er ist eben ein Computer und bei diesen geht alles immer korrekt und logisch zu. Die Zufallszahlen, die RND liefert werden deshalb immer auch nach einem bestimmten Schema berechnet, so daß es Ihnen gut passieren kann, daß Sie, wenn Sie den Rechner gerade frisch eingeschaltet haben immer dieselben Zufallszahlen erhalten. Probieren Sie das doch einmal aus.
Lassen Sie sich einmal ein paar Zufallszahlen, direkt nach dem Einschalten des 64 ers ausgeben, schalten Sie dann wieder AUS und EIN, und rufen Sie wieder mit RND ein paar Zahlen ab. Sie werden feststellen, daß diese haargenau dieselben sind, die wir vorher auch hatten. Das kann höchst negative Auswirkungen auf ein Spiel haben, zumal Sie bei dem Lottobeispiel von oben immer dieselben Ziehungen hätten.
Um dieses Problem zu umgehen gibt es einen kleinen Trick. Der 64 er verwaltet nämlich auch eine kleine interne Uhr.
Diese Uhr benutzt zwei vordefinierte Variablen, ähnlich wie bei ST. Diese Variablennamen dürfen Sie nie für eigene Zwecke benutzen, da sie vom System vordefinierte Werte enthalten. Zum einen wäre da die interne Uhr TI$ . TI$ ist eine Stringvariable, wie man zweifellos erkennen kann. In ihr steht eine immer abrufbereite, interne Uhr zur Verfügung.
Wenn Sie also PRINT TI$ eingeben, so wird der C64 Ihnen die Zeit, seitdem Sie ihren Rechner eingeschaltet haben anzeigen, in dem Format HHMMSS, wobei HH für Stunde steht, MM für Minute und SS für Sekunde. Möchten Sie diese Uhr nun auf einen eigenen Wert setzen, weil Sie zum Beispiel die aktuelle Tageszeit in einem Programm verwenden wollen, so kann man dies mit einer einfachen Variablendefinition bewerkstelligen. Angenommen es ist 10 Uhr 42 und 15 Sekunden, dann reicht folgende Definition vollkommen aus:
TI$="104215" Anschließed steht diese Zeit in der internen Uhr gespeichert, die die Sekunden von diesem Zeitpunkt an mitzählt.
Die zweite Variable, die etwas mit der Uhr zu tun hat, und die wir auch benötigen, um mit RND " richtige" Zufallszahlen zu erhalten, heißt TI. Wie Sie sehen eine numerische Variable. TI wird nun alle 1/60- Sekunde vom C64 hochgezählt.
Das wiederholt sich solange bis Sie TI$ wieder neu setzen. TI selbst können Sie nicht verändern. Man kann diese Variable gut in Programmen benutzt werden, die ziemlich genau arbeiten sollen, jedoch sei gesagt, daß BASIC wahrscheinlich zu langsam ist, als daß solche Veränderungen von BASIC schnell genug festgestellt werden könnten. Sie können ja einmal ein bißchen mit TI herumexperimentieren. . .
Es sei ebenfalls noch erwähnt, daß die interne Uhr TI$ sehr, sehr, ungenau ist.
Es ist gut möglich, daß sie innerhalb von 24 Stunden um eine halbe Stunde ( !) von der wirklichen Zeit abweichen kann.
Auch wenn Sie irgendwelche Operationen mit Ihrem Diskettenlaufwerk machen, kann die Uhr gebremst werden. Bei Diskettenoperationen wird sie nämlich gänzlich abgeschaltet, so daß die Zeit, in der die Floppy tätig war erst gar nicht gezählt wurde. Solche Abweichungen können sich sehr schnell summieren, so daß die Uhr am Ende total falsch geht. Also Vorsicht bei der Benutzung von TI$ . . .
(" richtige" Uhren kann man eigntlich nur in Assembler programmieren, doch ich glaube, daß wir auch schon einmal auf einer Magic Disk dieses Problem eingehender Behandelt haben) Nun noch zu der Sache mit den Zufallszahlen. TI spielt dabei eine große Rolle. Um praktisch die internen Zufallszahlen " zu mischen" benutzt man nämlich einfach folgenden Ausdruck:
X= RND(- TI) Was wir hier als Ergebnis in X erhalten kann ignoriert werden. Wichtig ist, daß wir nun die Zufallszahlen durcheinandergeworfen haben, so daß wir ab jetzt sehr gut mit unserer Allgemeinformel Zufallswerte abrufen können, die jetzt auch verschieden voneinander sind.
In unserer allgemeinen Formel für Zufallszahlen zwischen X und Y ist Ihnen bestimmt der merkwürdige Ausdruck INT aufgefallen. INT stellt ebenfalls eine besondere Funktion dar, dieser Befehl schneidet nämlich ganz einfach bei einer Dezimalzahl den Nachkommastellen ab. Das heißt, daß beispielsweise die Zahl 2 .54873 zu einer einfachen 2 reduziert wird. Die mit INT erhaltenen Zahlen sind also immer gleich oder kleiner als die Ursprungszahl. Bei negativen Zahlen bedeutet das, das immer auf die nächst kleinere Zahl abgeschnitten wird, demnach ist INT(-2 .54873) gleich -3, weil -3 ja kleiner ist als -2 !
Ansonsten hätten wir da noch FRE( X) .
FRE( X) gibt einem den noch verfügbaren Basicspeicher an, wobei es egal ist, welchen Wert X enthält. Allerdings ist diese Funktion etwas fehlerhaft. Es ist quasi unter C64- Kennern ein alter Fehler, der schon von Anfang an im Betriebssystem enthalten war, und meines Wissens niemals geändert wurde. Es benötigt nämlich einer besonderen Formel, um den tatsächlichen freien Speicherplatz zu ermitteln. Geben Sie nämlich nur FRE(0) ein, so wird Ihnen Ihr 64 er eine negative Zahl ausspucken, mit der wir im Endeffekt ja garnichts richtig anfangen können. Um die wahre Anzahl der freien Bytes zu erhalten, müssen Sie mit der folgenden Formel arbeiten :

PRINT 65538+FRE(0)                      

Nun haben Sie den richtigen Wert.
Damit sind wir nun endgültig am Ende unseres Basickurses angelangt. Ich verabschiede mich zunächst von Ihnen und hoffe, Ihnen die Programmierung Ihres C64 einigermaßen verständlich veranschaulicht zu haben.

                        Ihr Uli Basters 

Valid HTML 4.0 Transitional Valid CSS!