Vom Papier zur Datenbank

Das Erstellen von Programmen In den vergangenen drei Kursteilen wurden Datenbankbefehle im interaktiven Modus eingegeben. Heute folgt die Programmierung. Umfangreiche Befehlsketten können abgespeichert und per Programm ausgeführt werden. Die beiden Datenbanksysteme erlauben das Verfassen überaus anspruchsvoller und bedienungsfreundlicher Endbenutzeranwendungen.

SET TALK OFF 
mtaste = ''
DO WHILE intaste = ' '
    CLEAR (bei dBMAN bitte ERASE schreiben)
    @ 10,12 SAY 'Dies ist ein Test'
    @ 12,14 SAY 'Bitte drücken Sie eine Taste'
    @ 12,43 GET mtaste PICTURE '!'
    READ
    IF mtaste = 'A'
        @ 14,12 SAY 'Dies war Taste A’
    ELSE
        @ 14,12 SAY 'Dies war nicht Taste A'
    ENDIF 
    DO CASE
        CASE mtaste = 'B'
            @ 16,12 SAY 'Es war Taste B'
        CASE mtaste = 'C'
            @ 16,12 SAY 'Es war Taste C'
        OTHERWISE
            @ 16,12 SAY 'Es war Taste '+mtaste 
    ENDCASE 
ENDDO
@ 20,12 SAY 'Damit wird die Schleifenbedingung logisch falsch'
WAIT
RETURN

Bild 1: Übungsprogramm

Besonderheiten der Programmiersprachenkomponente

Die "eingebaute” Programmiersprache ist sehr leistungsfähig und kann mit anderen (BASIC, Pascal) sehr wohl konkurrieren bzw. übertrifft sie in Bezug auf die Verwaltung von Daten. Im Gegensatz zu diesen Programmiersprachen müssen die Programme hier aber streng strukturiert sein. Was bedeutet das?

Erstens: Es sind keine Sprunganweisungen möglich. Da die Programme ohne Zeilennummern (z.B. GFA-BASIC) geschrieben werden und das Benutzen von Labels nicht vorgesehen ist, kann innerhalb eines einzelnen Programms nicht hin- und hergesprungen werden. Der \om BASIC her bekannte “Spaghetti-Code” wird völlig vermieden. Sprünge >ind lediglich in bzw. aus Unter-nrogramme(n) möglich. Eine unbedingte Verzweigung auf bestimmte Programmzeilen ist nicht möglich. Mit der Anwendung der Unterprogrammtechnik entstehen hierarchische Abhängigkeiten zwischen den einzelnen Modulen.

Zweitens: Programme bzw. Unterprogramme dürfen nur einen Ein- und Ausgang haben, wobei der Start immer die erste Zeile ist und das Ende die letzte Zeile des Programms sein muß. Dies ist keine Forderung der Programmiersprache sondern eine Regel der strukturierten Programmierung.

Drittens: Die komplette Steuerung von Wiederholungsstrukturen erfolgt ausschließlich mit kopfgesteuerten Schleifen, d.h. die Abbruchbedingung befindet sich am Anfang.

Weiterhin ist wie in GFA-BASIC nur eine Anweisung pro Zeile erlaubt.

Diese Einschränkungen erscheinen zunächst als Hindernis. Gerade das Verbot von Sprüngen bedeutet für BASIC-Um-steiger eine große Umgewöhnung. Mich selbst plagte einst das Problem, ein vorhandenes BASIC-Programm in dBASE III umzustricken (ich habe es dennoch geschafft !). Deshalb will ich auch die Vorteile nennen:

a) Übersichtliche und einfache Programmstrukturen
b) Reduzierung der Dokumentation (selbstsprechende Programme)
c) schnelle Änderungsmöglichkeiten
d) leichtere Einarbeitung fremder Programmierer
e) Reduzierung von Fehlern
f) weniger Aufwand beim Testen

How To Do?

Nun soll es aber endlich losgehen! Um von dem interativen Modus in den Editor (jawohl, der ist eingebaut) zu gelangen, schreibt man in die Kommandozeile MODIFY COMMAND programm (Programm) ist ein von Ihnen frei wählbarer Name der Programmdatei (denkt an TOS). In ihr wird der Code auf der Disk abgespeichert; die Extension des Files lautet automatisch .cmd. Das Programm wird in ASCII-Notation gesichert und kann bei Bedarf durch Anklicken im Desktop gelistet oder gedruckt werden. (Anmerkung: die Endung der Indexdatenbanken bei ST-BASE lautet .nmx und nicht .ndx.).

Nach diesem Aufruf befindet Sie sich in einem Full-Screen-Editor und das Tippen kann beginnen. Eingegebene Befehle werden jetzt nicht sofort ausgeführt, sondern erst nach Aufruf der Kommando-Datei. Als Übungsbeispiel nehmen Sie bitte das Programm aus Bild 1. Es sind Anweisungen enthalten, die ich weiter unten beschreiben will. Machen Sie sich so bitte mit den besonderen Eigenschaften Ihres Editors vertraut.

Mit CTRL-S kommt man aus dem Ediermodus (dBMAN) zurück (bei ST-BASE: Pull-Down-Menü oder ESC-Taste und RETURN) zum Kommando-Interpreter. Der eben geschriebene Quellcode wird automatisch auf die Disk gesichert. Starten Sie dann das Programm und sehen Sie mit erstaunten Augen, was passiert. Dazu müssen Sie natürlich den Namen des Programms angeben.

DO programm 

DO ist in etwa mit RUN (BASIC) vergleichbar. Bei BASIC ist das Programm bereits im Speicher; in unserem Beispiel muß der Quellcode noch von der Diskette geladen werden. Falls Änderungen erforderlich werden (Tippfehler seid gegrüßt), müssen Sie nochmals mit “MODIFY COMMAND ...” die ursprüngliche Datei laden und die Korrekturen vornehmen. Der fehlerhafte Text wird erneut geladen und steht zur Edierung bereit.

Ausgewählte Anweisungen

Das Übungsbeispiel ist mit einer Fülle neuer Befehle geladen. Natürlich können auch alle bereits bekannten datenbankspezifischen Befehle (LIST, APPEND ...) auch innerhalb eines Programms mitbenutzt werden, die ich in diesem Fall weggelassen habe.

Nun zur Beschreibung des Programms im einzelnen.

Die einzig mögliche Schleife ist schnell erklärt. “DO WHILE bedingung” wiederholt die folgenden Befehle (bis zum ENDDO), solange die Bedingung wahr ist. Es wird der Logikzustand der Bedingung bei Einstieg in die Schleife abgefragt. Trifft der Interpreter auf “ENDDO", wird erneut die Bedingung untersucht und bei Wahrheit nochmals ausgeführt. Endlosschleifen kann man also einfach mit “DO WHILE ,T.” einleiten, weil das “T” für TRUE steht (siehe 3.Teil). Diese Schleifenbedingung ist so immer gültig. Es muß nicht eine Vergleichsbedingung (mit Gleichheitszeichen) sein wie in meinem Beispiel. Es kann auch der Logikzustand von logischen Variablen (z.B. DO WHILE.NOT.EOF()) zur Steuerung benutzt werden. Verändert man in der Schleife nicht die Bedingung, entsteht ein “Loop”, aus dem man nur mit der ESCAPE-Taste herauskommt. Vorsicht! SET ESCAPE OFF schaltet die Funktion dieser Taste aus. Deshalb darf der Schalter erst dann aus sein, wenn das Programm fehlerfrei ist. Sie sollten sich angewöhnen, alle Befehle, die zwischen DO WHILE und ENDDO stehen, einzurücken. So erkennt man schneller das Ausmaß der Wiederholungsstruktur. Zu jedem “DO WHILE...” muß ein passendes “ENDDO” vorhanden sein, sonst spielt das Programm verrückt. Der Vollständigkeit halber weise ich auf den EXIT-Befehl hin, der den sofortigen Ausstieg aus der Schleife bewirkt, ohne die Bedingung zu prüfen. Der Programmablauf geht dann nach dem zugehörigen ENDDO weiter. Da dieser Befehl die mühevoll gepflegte klare Struktur eines Programms zerstört, bitte ich darum, EXIT nicht in Einsatz zu bringen. Durch geschickte Programmierung ist der Befehl sowieso überflüssig zu machen. Ich verstehe nicht, weshalb er in den Sprachschatz mit aufgenommen wurde.

CLEAR bzw. ERASE löscht den Bildschirm. Die SAY-Anweisung gibt formatierten Text an der entsprechenden Position (oben links ist Koordinate 0,0) aus. Die beiden Zahlen geben die Zeile und Spalte an. So können der Inhalt von Variablen und Dateifeldern gezeigt oder Überschriften erzeugt werden. Die Zahlen müssen nicht absolut sein. Die relative Adressierung ist auch zugelassen (z.B. zeile = 10, spalte = 5, @ zeile,spalte SAY ...). Von dem bekannten “?” (print) möchte ich abraten, weil mit ihm keine formatierte Ausgabe möglich ist. Die Umleitung der Ausgabe übernimmt der interne Schalter SET DEVICE TO PRINTER. Damit können formatierte Listings erstellt werden, denn die Koordinaten beziehen sich beim Drucker auf absolute Druckpositionen. Ohne großen Aufwand ist so das Bedrucken von z.B. Endlosüberweisungsträgern möglich. Standardmäßige Einheit (Device) ist der Bildschirm (SCREEN).

Mit GET... READ können Eingaben von der Tastaturaus erfolgen. “GET” bereitet die folgende Variable auf die Eingabe vor, die auf jeden Fall in ihrem Typ schon definiert sein sollte. Das anschließende “READ" liest die Daten dann in die Variable ein. Die wahlfreie Erweiterung “PICTURE" gibt dabei das Eingabeformat vor, z.B. wandelt das Ausrufezeichen die Eingaben automatisch in Großbuchstaben um; Zahlen werden gar nicht erst zugelassen. Weitere PICTURE-Angaben:

PICTURE '999.99' : fünfstellige Zahl mit 2 Nachkommastellen

PICTURE ‘AAAAAA’ : sechs Alphazeichen, keine Zahlen

PICTURE ’XXXXXX' : alphanum. Eingabe, 6 Stellen

PICTURE 'AAA-AA 9999’ : Auto-Nummernschild.

Für jedes einzugebende Zeichen muß bei der Verwendung von PICTURE ein Formatzeichen vorhanden sein! Bei mehreren gleichzeitig “offenen” GETs beendet ein einziger READ die Eingabe.

Damit ist also ohne großen Aufwand der Aufbau von Plausibilitätskontrollen möglich. Schon bei der Eingabe von Daten kann verhindert werden, daß z.B. in ein numerisches Feld Alphazeichen eingegeben werden (Resource Contruction Set ade!). Die verwendete Variable (hier: mtaste) kann auch ein Feld einer Datei sein, um die Daten gleich in die Datenbank zu schreiben. Es wäre alternativ denkbar, die Eingabe zunächst in eine interne Variable zu speichern, und dann (z.B. nach einer Prüfung oder Umrechnung) mittels des REPLACE in das Feld eines Satzes zu befördern.

Es stehen weitere Befehle für Eingaben zur Verfügung. Mit ACCEPT können auch Daten von der Tastatur übernommen werden. Ich selbst benutze diese Anweisung jedoch nie, weil die PIC-TURE-Option hierbei nicht angewandt werden kann.

In meinem Übungsbeispiel folgt nach der Tastaturabfrage (sie wird in der Variablen “mtaste” gespeichert) eine bedingte Verzweigung. Ist der logische Zustand der Bedingung nach “IF” wahr, wird die nächste Zeile bis zum ELSE ausgeführt. Bei Unwahrheit werden die Zeilen zwischen “ELSE” und "ENDIF" durchlaufen. Um die Transparenz des Programmlistings zu erhalten, sind diese Anweisungen ebenfalls um zwei Leerstellen eingerückt. Sie müssen doch zugeben, daß die Lesbarkeit mit dieser simplen Technik erheblich gesteigert wird. Der optionale “ELSE”-Zweig kann weggelassen werden.

Sind mehrere Abfragen nötig, kann der IF-Befehl leicht überfordert und unübersichtlich werden. Deshalb ermöglicht die “DO CASE”-Anweisung eine Mehrfach-Fallunterscheidung. Die entsprechenden Zeilen nach einem “CASE” werden dann ausgeführt, wenn die vorherige Bedingung ein wahres Ergebnis liefert. Trifft keiner der Fälle ein, so führt der Interpreter die Befehlsfolge nach “OTHER-WISE” aus. Ist dieses “Andernfalls” nicht erforderlich, kann die Zeile entfallen. Abgeschlossen wird die “DO CASE”-Anweisung mit ENDCASE.

Ich meine, für die (hoffentlich) englischsprechenden Programmierer dürften diese Befehle nicht zu schwer sein. Der Quellcode liest sich einfacher als englischsprachige Literatur. Die Sprachelemente sind von derartiger Transparenz, daß eine weitere Beschreibung nicht nötig ist. Man kann das Programm problemlos ins Deutsche übersetzen (viel Spaß). Die drei Anweisungen (Wiederholung, Alternative, mehrfache Alternative) sind die einzigen Möglichkeiten, die Steuerung innerhalb eines Programms zu beeinflussen. Weitere Sprachelemente sind nicht vorhanden bzw. nötig.

Mir persönlich fehlt ein wenig die fußgesteuerte Schleife, in der die Abbruchbedingung am Schleifenende steht (wie in PASCAL, REPEAT...UNTIL...).

Zur symbolhaften Darstellung des Programmablaufs bietet sich die Notation nach Nassi-Shneiderman an. In der DIN 66261 sind die Sinnbilder aufgezeigt; der altbekannte PAP(Programm-Ablauf-Plan) ist für strukturierte Programme weniger geeignet. Ich will hier keine Einführung in das Zeichnen von Struktogrammen geben, sondern nur darauf hin-weisen, wie optimal sich diese Darstellungsart mit der Programmiersprache ergänzt. Zur Verdeutlichung habe ich das Struktogramm zu dem Übungsprogramm gezeichnet.

Unterprogramme

Eine weitere Forderung an strukturierte Programme ist, daß ein einzelnes Programm nicht zu lang (= Verlust der Übersichtlichkeit) sein sollte. Als Faustregel gilt: maximal zwei Schreibmaschinenseiten pro Programm. Kurze Module sind nicht nur leichter zu korrigieren und zu testen; das Blättern im Editor ist bei langen Quellcodes ein ernstzunehmendes Hindernis.

Mit Hilfe der Unterprogrammtechnik können umfangreiche Programme verkürzt werden. Ständig wiederkehrende Teile werden in ein Unterprogramm ausgelagert und bei Bedarf aufgerufen. Bild 2 zeigt den Einsatz dieser Technik. Das Einstiegsmenü der Anwendung (MENU.CMD) ruft je nach Wunsch Module auf, die die verschiedensten Funktionen übernehmen.

* Programm: MENU.CMD
mtaste = ' '
SELECT 1 (bzw. SELECT FJ)
USE datei INDEX index1 
DO WHILE mtaste <> '0'
    CLEAR (bzw. ERASE)
    @ 5,30 SAY 'Hauptmenü'
    @ 10,30 SAY '1 - Erfassen'
    @ 12,30 SAY '2 - Ändern'
    @ 14,30 SAY '3 - Anzeigen'
    @ 16,30 SAY '4 - Löschen'
    @ 19,30 SAY '0 - Programm-Ende'
    @ 22,30 SAY 'Bitte Ihre Wahl —>'
    @ 22,50 GET mtaste PICTURE '9'
    READ 
        DO CASE
    CASE mtaste = '1'
        DO erfass 
    CASE mtaste = '2'
        DO aender 
    CASE mtaste = '3'
        DO anzeig 
    CASE mtaste = '4'
        DO loesch 
    ENDCASE 
ENDDO 
RETURN

* Unterprogramm ERFASS.CMD CLEAR (bzw. ERASE)
@ 5,30 SAY 'Erfassen neuer Daten'
APPEND BLANK
@ 10,30 SAY 'Name ' GET fname PICTURE 'XXXXXXXXXXXXXXXXXXXX'
@ 11,30 SAY 1 PLZ ' GET fplz PICTURE '9999'
@ 12,30 SAY 'Ort ' GET fort PICTURE 'XXXXXXXXXXXXXXXXXXXX'
@ 13,30 SAY 'Datum ' GET fdatum PICTURE '99.99.99'
@ 14,30 SAY 'Größe ' GET fgroesse PICTURE '99.99'
READ
REPLACE falter WITH YEAR(DATE())-YEAR(fdatum)
RETURN

* Unterprogramm ANZEIG.CMD CLEAR (bzw. ERASE) mname = ' '
@ 5,30 SAY 'Anzeigen von Daten'
@ 20,30 SAY 'Wer soll gezeigt werden ?'
@ 21,30 GET mname PICTURE 'XXXXXXXXXXXXXXXXXXXX'
READ
GO TOP
SEEK mname
IF .NOT. EOF()
    @ 10,30 SAY 'Name '+fname 
    @ 11,30 SAY 'PLZ '+STR(fplz,4)
    @ 12,30 SAY 'Ort '+fort 
    @ 13,30 SAY 'Alter '+STR(falter,2)
    @ 14,30 SAY 'Datum '+dtoc(fdatum)
    @ 15,30 SAY 'Größe '+STR(fgroesse,4,2)
ELSE
    @ 10,30 SAY 'Daten konnten nicht gefunden werden' 
ENDIF 
WAIT 
RETURN

Bild 2: Grundsätzlicher Aufbau von Anwendungsprogrammen (Die einzelnen Module sind seperat abzuspeichern!)

Das Beispiel zeigt gut die entstehende Hierarchie. Oben befindet sich das Einstiegsprogramm; die Unterprogramme sind jeweils eine Stufe tiefer und vom Hauptprogramm abhängig. Ein Unterprogramm wird wie bekannt aufgerufen mit

DO uprog

Es muß natürlich bereits auf der Diskette vorhanden sein (UPROG.CMD); es wird nämlich nachgeladen. Nach seiner Abarbeitung wird es mit RETURN verlassen, und die Steuerung des Ablaufes geht in dem aufrufenden Programm in der nächsten Zeile weiter.

Struktogramm

Es ist wichtig, auch das Hauptprogramm mit RETURN abzuschließen, um bei Programmende wieder sauber in den Kommando-Modus zu gelangen. Dieser Befehl verläßt immer eine niedrigere Hierarchie und kehrt eine Stufe höher zurück. Bitte gewöhnt Sie sich an, in jedem Programm nur EINMAL RETURN zu benutzen und das am Ende!! So ist sofort das logische und physikalische Ende eines Moduls zu erkennen.

Das Grundprinzip aller Anwendungen

In Bild 2 habe ich ein “Gerippe” aufgezeigt. So in etwa sehen alle Anwendungen aus, die mit Hilfe eines Datenbanksystems geschrieben werden. Die vier Hauptfunktionen “Erfassen, Anzeigen, Löschen und Ändern” benötigt man in fast allen datenverarbeitenden Programmen (z.B. Plattenverwaltung, Adreßdatei). Für Eure spezielle Anwendung ist es nur noch vonnöten, dieses Gerippe mit entsprechendem “Fleisch” zu füllen. Die Funktionen "Ändern” und “Löschen” habe ich bewußt weggelassen; es steht Ihnen frei, sie selbst zu schreiben. Die Datei und Indextabelle stammen aus dem dritten Teil. Ich habe nach “meinen” Konventionen die Namen der Datenfelder mit einem vorangestellten “F” versehen. Übrigens, das Sternchen zu Beginn eines Unterprogramms ist eine Kommentarzeile; sie beeinflußt nicht den Programmablauf.

Prozeduren

Gerade bei Diskettenbetrieb stört es ungemein, daß die Unterprogramme nach deren Aufruf erst von der Disk geladen werden, um zur Ausführung zu gelangen. Das Datenbanksystem hält nämlich immer nur ein Modul gleichzeitig im Speicher. Am Ende eines Unterprogramms sind wieder Ladeoperationen nötig.

Abhilfe schafft der Einsatz von Prozeduren. Sie werden dann eingesetzt, wenn das Programm komplett fertig geschrieben und getestet ist und für die Übergabe an den Anwender bereitsteht. Die Arbeitsschritte sind in etwa mit der Tätigkeit eines Linkers (=Klebers) zu vergleichen:

a) In jedes Modul (außer dem Hauptprogramm! ) wird in die erste Zeile folgender Text geschrieben:

PROCEDURE name

(name) ist der Name der Kommandodatei, mit der sie auf gerufen wird, ohne die Endung .cmd (z.B. PROCEDURE ERFASS).

b) In das Hauptprogramm werden folgende Anweisungen am Anfang aufgenommen:

CLEAR ALL
SET PROCEDURE TO haupt 
DO haupt
CLOSE PROCEDURE 
RETURN
PROCEDURE haupt

(haupt) ist der hier einzutragende Name des Hauptprogramms, mit welchem der Einstieg in die eigentliche Anwendung erfolgt.

c) Sind die Unterprogramme und das Hauptprogramm dergestalt modifiziert, müssen mit einem separaten Editor (z.B. Tempus) alle Teile zu einem großen File “zusammengeklebt” werden. Das Einstiegsprogramm muß ganz oben stehen. Diese Datei wird mit einem frei wählbaren Namen (z.B. procedur.cmd) auf Disk gesichert. Der Aufruf erfolgt dann vom Datenbanksystem wie gewohnt

DO procedur

Die komplette Prozedur wird geladen und im Speicher gehalten. Bei Aufrufen von Unterprogrammen treten keine Verzögerung mehr auf, weil sie nicht mehr nachgeladen werden müssen. Die Arbeitsgeschwindigkeit nimmt zu. Ein Prozedur-File kann nachträglich natürlich weiterhin wie jede andere Kommandodatei ediert werden, nur leider ist sie sehr umfangreich geworden.

Das Ende naht!

Zum Abschluß die Auflösung der Aufgabe des dritten Teils. Es war gefragt nach der richtigen INDEX-An Weisung zum Sortieren eines Datumsfeldes, um eine Geburtstagsliste zu drucken. Sie lautet:

INDEX ON STR(YEAR(datum),2)+STR(MONTH(datum),2) TO index4 

So wird die Datei aufsteigend nach Monaten und innerhalb eines Monats aufsteigend nach Tagen sortiert.

Damit wäre der Programmierkurs über relationale Datenbanken abgeschlossen. Ich hoffe. Ihnen das Handwerkszeug mitgegeben zu haben, um brauchbare Endbenutzeranwendungen zu schreiben (nicht nur für Sie selbst, sondern auch für Fremde). Mit der Zeit werden Sie sicherlich eigene Programmiertechniken entwickeln, um die Programme überaus komfortabel zu gestalten.

Paul Fischer

Quelle:

DIN 66261:

Sinnbilder für Struktogramme nach Nassi-Shneiderman, November 1985 zu beziehen bei:

Beuth Verlag GmbH
Burggrafenstr. 4-10
1000 Berlin 30



Aus: ST-Computer 07 / 1988, Seite 159

Links

Copyright-Bestimmungen: siehe Über diese Seite