Basic-Erweiterungen

Record-Befehl für den C 64

Dieses Programm erleichtet Ihnen den Umgang mit relativen Files.

Bei relativen Files kann auf jeden Satz des Files direkt zugegriffen werden, ohne die vorherigen Sätze lesen zu müssen. Außerdem kann ein eröffnetes File nach Belieben beschrieben und gelesen werden, es ist also zum Beispiel möglich, Satz 12 zu beschreiben, auch wenn bereits höhere Sätze existieren. Ein relatives File wird durch folgenden OPEN-Befehl eingerichtet:

OPEN lfn,ga,sa,”filename,l,”+chr$(sl). Dabei bedeutet:
lfn = logische Filenummer.
ga = Geräteadresse (normalerweise 8)
sa = Sekundäradresse (mindestens 2, höchstens 14)
sl = maximale Satzlänge des relativen Files (mindestens 1, höchstens 254). Diese Angabe ist entscheidend für den späteren Diskettenplatzverbrauch des Files, da auch Sätze, die nicht mit voller Satzlänge beschrieben werden, den gesamten durch sl reservierten Platz verbrauchen. Ist ein relatives File erst einmal eingerichtet, so kann die Satzlänge nicht mehr verändert werden. Es genügt dann der folgende OPEN-Befehl:
OPEN lfn,ga,sa,”filename”

Selbstverständlich muß ein relatives File auch mit CLOSE lfn geschlossen werden. Auf die einzelnen Sätze eines relativen Files wird normal mit PRINT #lfn, INPUT#lfn oder GET#lfn zugegriffen, allerdings muß vor jedem Zugriff auf den gewünschten Satz positioniert werden. Dies übernimmt die vorliegende Basic-Erweiterung.

Durch RECORD#lfn,sn,(,p) wird auf den Satz mit der Nummer sn positioniert, wird zusätzlich noch p angegeben, so wird innerhalb des Satzes das p-te Zeichen angewählt. Der neue Befehl muß von THEN durch einen Doppelpunkt abgetrennt werden. Es können folgende Basic-Fehlermeldungen auftreten:
?SYNTAX ERROR: Schreibfehler im Befehl oder die Erweiterung war nicht eingeschaltet.
?ILLEGAL QUANTITY ERROR: Ein Argument lag außerhalb des erlaubten Bereichs.
?FILE NOT OPEN ERROR: Das File mit der logischen Filenummer lfn war nicht eröffnet.
?ILLEGAL DEVICE NUMBER ERROR: Dem File mit der Nummer lfn ist ein Gerät mit einer Adresse kleiner als 8 oder größer als 15 zugeordnet.
Es können außerdem folgende Floppy-Fehlermeldungen auftreten (Sie müssen durch den Fehlerkanal ausgelesen werden):
50,RECORD NOT PRESENT: Der Satz, auf den positioniert wurde, existiert nicht. Diese Meldung kann ignoriert werden, wenn der Satz beschrieben werden soll, denn durch das Beschreiben wird er eingerichtet. (Und alle nicht existierende Sätze mit kleinerer Nummer ebenfalls.) Aus Geschwindigkeitsgründen empfiehlt es sich, bei der Einrichtung eines Files den höchsten Satz zuerst zu beschreiben.
51,OVERFLOW IN RECORD: Die maximale Satzlänge sl wurde beim Schreiben überschritten. Zu beachten ist, daß das Carriage Return am Ende des Satzes mitzählt.
52,FILE TOO LARGE: Die Diskette ist voll, der letzte Schreibzugriff kann nicht durchgeführt werden.

Aufbau des Programms

Der Basic-Interpreter besitzt einen Zeiger (Adresse $0308, im Listing »decod« genannt), der auf die Routine zur Befehlsinterpretation zeigt. Dieser Vektor wird nach dem Aufruf der Erweiterung zuerst gemerkt und danach auf eine eigene Routine zur Befehlsinterpretation gesetzt. Vor dem Merken wird noch geprüft, ob der Vektor schon auf die eigene Routine zeigt. Damit wird verhindert, daß der Computer bei einem versehentlichen Doppelaufruf abstürzt. Die eigene Routine rettet zunächst den Zeiger, der auf das augenblickliche Zeichen im Basic-Text zeigt, und ruft dann die CHRGET-Routine (Befehlscodierung siehe Bild 1, Symboltabelle Bild 2) auf. Diese Routine holt das nächste Zeichen aus dem Basic-Text. Sie überliest automatisch Leerzeichen. Wenn das Ende einer Zeile oder ein Doppelpunkt erreicht wird, so wird die Z-Flag des Prozessors gesetzt. Ein Problem ergibtsich dadurch, daß in »RECORD#« der Simons Basic-Befehl »REC« vorkommt. Er wird bei Verwendung von Simons Basic also in eine interne Darstellung beginnend mit $64 umgewandelt. Das Programm testet daher, ob $64 vorliegt und verzweigt bei positiver Antwort. In beiden Fällen wird nun getestet, ob der Befehl »RECORD#«vorliegt. Unter dem Namen tab 1 (beziehungsweise tab 2 für Simons Basic) steht (rückwärts) die interne Darstellung des Befehls »RECORD«. Dabei ist zu beachten, daß »OR« wiederum nicht im ASCII-Code abgelegt ist, sondern als Token. Wird nur eine Abweichung gefunden, so wird der gemerkte CHRGET-Zeiger zurückgeholt und zur normalen Interpreterroutine gesprungen, anderenfalls tritt eine eigene Routine in Funktion (sie beginnt beim Label OK). Sie holt die Satznummer und, wenn angegeben, die Position im Satz aus dem Basic-Text und sendet die Informationen an die Floppy über die Sekundäradresse 15 (Kommandokanal). Die Floppy erwartet die Werte in folgender Form: »p« als Zeichen, das positioniert werden soll; die Sekundäradresse, mit der das relative File eröffnet wurde; die Satznummer in der Reihenfolge niederwertiges — höherwertiges Byte und, falls angegeben, die Position im Satz. Es werden folgende Routinen des Interpreters und des Betriebssystems verwendet:

getbyt Holt einen beliebigen Ausdruck in das x-Register.
search Sucht nach der logischen Filenummer in x.
parset Holt logische Filenummer, Geräteadresse und Sekundäradresse in die Speicherzellen $b8,$ba und $b9
listen Teilt dem angesprochenen Gerät mit, daß es Daten empfangen soll.
seclis Sendet die Sekundäradresse zum angesprochenen Gerät.
iecout Sendet den Wert im Akkumulator zum angesprochenen Gerät.
chkcom Prüft auf Komma im Basic-Text.
getrec Holt einen numerischen Ausdruck in den Fließkomma-Akkumulator.
fac16 Wandelt den Wert im Fließkomma-Akkumulator in eine 16-Bit-Zahl und speichert sie in $14 und $15.
comget = chkcom + getbyte.
unlist Beendet die Übertragung an die Floppy.

Das Programm wurde mit dem Assembler »ASSI« übersetzt, eine Übernahme auf andere Assembler dürfte nicht schwierig sein. Der Basic-Lader (Listing 1, Source-Code: Listing 2) legt das Programm ab der Adresse 49152 ($C000) ab, schaltet die Erweiterung ein und löscht sich dann selbst, er muß also vorher auf Diskette abgespeichert werden. Die Erweiterung wird durch SYS49152 ein- und durch SYS49155 ausgeschaltet. STOP/RESTORE schaltet die Erweiterung nicht ab.

(Bernward Bretthauer/rg)
* = 49152
chrget = $73 ; holt nächstes Zeichen
chrgot = $79 ; holt letztes Zeichen
chrvek = $7a ; Chrgetzeiger
decod = $0308 ; Vektor für Befehlsdec.
error = $4a37 ; Fehlermeldung ausgeben
schleife = $a7ae ; Interpreterschleife
getrec = $b083 ; Recordnummer holen
chkcom = $aefd ; prüft auf Komma
getbyt = $b79b ; holt Byte in x
comget = $b711 ; chkcom + getbyt
fac16 = $b77c ; FAC nach 16-Bit wandeln
search = $f30f ; sucht logische Filenr.
parset = $f30c ; setzt Fileparameter
listen = $ffb1 ; LISTEN senden
seclis = $ff93 ; Sekundärad. nach LISTEN
iecou t = $ffa8 ; Ausgabe auf IEC-bus
unlist = $ffae ; UNLISTEN senden
integ = $14 ; Integer Wert
filenr = $b8 ; logische Filenummer
secadr = $b9 ; Sekundäradresse
ga = $ba ; Gerätenummer
Bild 1. Befehlscodierung
0073 chrget
0079 chrgot
007a chrvek
0308 decod
a437 error
a7ae schleife
ad8a getrec
aefd chkcom
b79e getbyt
b7f1 comget
b7f7 fac16
f30f search
f31f parset
ffb1 listen
ff93 seclis
ffa8 iecout
ffae unlist
0014 integ
00b8 filenr
00b9 secadr
00ba ga
c019 endoff
c01a vekt
c01c flag
c01d on
c02c l1
c036 l2
c041 tab1
c047 tab2
c04b record
c05a 13
c067 simon
c06c 13s
c079 out
c082 ok
c091 14
c09f illdev
c0a4 15
c0da ende
Bild 2. Symbol-Tabelle
20 fori=49152to49375:reada:pokei,a:s=s+a:nexti
30 if s<>25982thenprint"pruefsummenfehler":stop
40 sys49152:new
100 data76,29,192,173,28,192,240,17,173,26,192,141,8,3,173,27,192,141,9,3
101 data169,0,141,28,192,96,228,167,0,169,255,141,28,192,173,8,3,201,75,240
102 data3,141,26,192,173,9,3,201,192,240,3,141,27,192,169,75,141,8,3,169
103 data192,141,9,3,96,35,68,176,67,69,82,35,68,176,8,165,122,72,165,123
104 data72,32,115,0,201,100,240,15,160,6,217,64,192,208,26,32,115,0,136,208
105 data245,240,27,32,115,0,160,4,217,70,192,208,8,32,115,0,136,208,245,240
106 data9,104,133,123,104,133,122,108,26,192,104,104,32,158,183,32,15,243
107 data240,5,162,3,76,55,164,32,31,243,165,185,41,15,72,165,186,201,16,144
108 data5,162,9,76,55,164,201,8,144,247,32,177,255,169,111,133,185,32,147
109 data255,169,80,32,168,255,32,253,174,32,138,173,32,247,183,104,32,168
110 data255,165,20,32,168,255,165,21,32,168,255,32,121,0,240,7,32,241,183
111 data138,32,168,255,32,174,255,76,174,167
Listing 1. Basic-Lader »Record-Befehle«. Bitte beachten Sie die Eingabehinweise auf Seite 6.
     * = 49152 ;Startadresse

       jmp on       ;zum Einbinden       c000 4c 1d c0

;******* Erweiterung abschalten *******
       lda flag     ;schon abgeschaltet? c003 ad 1c c0
       beq endoff                        c006 f0 11
       lda vekt     ;Vektor wieder her-  c008 ad 1a c0
       sta decod    ;stellen             c00b 8d 08 03
       lda vekt+1                        c00e ad 1b c0
       sta decod+1                       c011 8d 09 03
       lda #0       ;Flag fuer Abge-     c014 a9 00
       sta flag     ;schaltet setzen     c016 8d 1c c0
endoff rts                               c019 60
vekt   .word $a7e4                       c01a e4 a7
flag   .byte $00                         c01c 00

;******* Erweiterung einschalten ******
on     lda #$ff     ;Flag fuer Einge-    c01d a9 ff
       sta flag     ;schaltet setzen     c01f 8d 1c c0
       lda decod                         c022 ad 08 03
       cmp #<record                      c025 c9 4b
       beq l1                            c027 f0 03
       sta vekt                          c029 8d 1a c0
l1     lda decod+1                       c02c ad 09 03
       cmp #>record                      c02f c9 c0
       beq l2                            c031 f0 03
       sta vekt+1                        c033 8d 1b c0
l2     lda #<record                      c036 a9 4b
       sta decod                         c038 8d 08 03
       lda #>record                      c03b a9 c0
       sta decod+1                       c03d 8d 09 03

       rts                               c040 60
;****** Interpreterdarstellung von ****
;****** RECORD#                    ****
tab1   .byte $23,$44,$b0,$43,$45,$52     c041 23 44 b0 43 45 52
tab2   .byte $23,$44,$b0,$08             c047 23 44 b0 08

;****** Test auf RECORD#           ****
record
       lda chrvek      ;Chrgetzeiger     c04b a5 7a
       pha             ;retten           c04d 48
       lda chrvek+1                      c04e a5 7b
       pha                               c050 48
       jsr chrget                        c051 20 73 00
       cmp #$64        ;Simon´s Basic    c054 c9 64
       beq simon       ;TOKEN            c056 f0 0f
       ldy #6                            c058 a0 06
l3     cmp tab1-1,y                      c05a d9 40 c0
       bne out                           c05d d0 1a
       jsr chrget                        c05f 20 73 00
       dey                               c062 88
       bne l3                            c063 d0 f5
       beq ok                            c065 f0 1b
simon  jsr chrget                        c067 20 73 00
       ldy #4                            c06a a0 04
l3s    cmp tab2-1,y                      c06c d9 46 c0
       bne out                           c06f d0 08
       jsr chrget                        c071 20 73 00
       dey                               c074 88
       bne l3s                           c075 d0 f5
       beq ok                            c077 f0 09
;****** Weiter mit normalem Basic  ****
out    pla                               c079 68
       sta chrvek+1                      c07a 85 7b
       pla                               c07c 68
       sta chrvek                        c07d 85 7a
       jmp (vekt)                        c07f 6c 1a c0
;****** eigentlicher RECORD#-Befehl ***
ok     pla         ;Zeiger von Stack     c082 68
       pla                               c083 68
       jsr getbyt  ;holt Byte nach x     c084 20 9e b7
       jsr search  ;sucht log. Filenr.   c087 20 0f f3
       beq l4      ;gefunden             c08a f0 05
       ldx #3      ;file not open        c08c a2 03
       jmp error   ;ausgeben             c08e 4c 37 a4
l4     jsr parset  ;Fileparameter setzen c091 20 1a f0
       lda secadr  ;Sekundaeradresse     c094 a5 b9
       and #$0f                          c096 29 0f
       pha         ; = Kanalnummer       c098 48
       lda ga                            c099 a5 ba
       cmp #16                           c09b c9 10
       bcc l5      ;ga < 16              c09d 90 05
illdev ldx #9      ;illegal device nr.   c09f a2 09
       jmp error                         c0a1 4c 37 a4
l5     cmp #8                            c0a4 c9 08
       bcc illdev  ;ga < 8               c0a6 90 f7
       jsr listen                        c0a8 20 b1 ff
       lda #$6f    ;15 and $60           c0ab a9 6f
       sta secadr                        c0ad 85 b9
       jsr seclis                        c0af 20 93 ff
       lda #'p     ;positionieren        c0b2 a9 50
       jsr iecout  ;senden               c0b4 20 a8 ff
       jsr chkcom                        c0b7 20 fd ae
       jsr getrec  ;Recordnummer holen   c0ba 20 44 b9
       jsr fac16   ;FAC nach 16-Bit      c0bd 20 f7 b7
       pla         ;Kanalnummer          c0c0 68
       jsr iecout                        c0c1 20 a8 ff
       lda integ   ;Recordnr. lo         c0c4 a5 14
       jsr iecout                        c0c6 20 a8 ff
       lda integ+1 ;Recordnr. hi         c0c9 a5 15
       jsr iecout                        c0cb 20 a8 ff
       jsr chrgot  ;letztes Zeichen      c0ce 20 79 00
       beq ende    ;kein dritter Param.? c0d1 f0 07
       jsr comget  ;Komma und Parameter  c0d3 20 7d b7
       txa                               c0d6 8a
       jsr iecout  ;Position in Record   c0d7 20 a8 ff
ende   jsr unlist                        c0da 20 ae a7
       jmp schleife;zur Interpreterschl. c0dd 4c ae a7
Listing 2. Source-Code von »Record-Befehl«
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →