Basic-Erweiterungen

PRINT USING mit der USR-Funktion

Haben Sie sich auch schon über die unformatierte Zahlenausgabe Ihres C 64 geärgert? Dann nehmen Sie in Zukunft die folgende USR-Funktion, um für Ihren C 64 ein PRINT USING zu erhalten.

Wie allgemein bekannt und vielfach bemängelt, bietet das Commodore-Basic keinen PRINT USING-Befehl. Doch gerade bei kommerziellen Problemen kann auf eine Druckaufbereitung von Zahlen nicht verzichtet werden. Eine Rechnung, in der nicht einmal die Dezimalpunkte untereinander stehen, ist eben unübersichtlich und keine Reklame. Für die Druckaufbereitung gibt es verschiedene Lösungen.

Die beste Lösung ist ein Maschinenprogramm. Interessierte Maschinenprogrammierer finden den Quellcode zu dieser Routine in Listing 1. Doch zunächst stellt sich die Frage, wie ein Maschinenprogramm für die Druckaufbereitung aufgerufen werden soll. Offensichtlich ist die USR-Funktion am geeignetsten, da sie sowohl in einer PRINT- als auch in einer PRINT#- oder einer LET-Anweisung verwendet werden kann. Der Aufruf der Funktion erfolgt durch USR(X),L,NK. Dabei ist X die Zahl, die aufbereitet werden soll, L die Gesamtfeldlänge der aufbereiteten Zahl einschließlich Vorzeichen und Dezimalkomma und NK die Anzahl der darzustellenden Nachkommastellen. Die USR-Funktion wandelt zunächst die Zahl X in einen ASCII-String um und berechnet die Stringlänge und die Anzahl der Nachkommastellen. Wenn bei der Wandlung von X der Interpreter die Exponentialform wählt, dann wird die Exponentialdarstellung zunächst in die Fließkommadarstellung umgewandelt. Danach werden die Nachkommastellen aufbereitet. Fehlende Nachkommastellen werden durch angehängte Nullen ergänzt. Müssen Nachkommastellen abgeschnitten werden, dann wird die Zahl gerundet, wenn die erste abgeschnittene Dezimalstelle größer oder gleich 5 ist. Wenn die Anzahl der gewünschten Nachkommastellen null ist, dann wird die Zahl als ganze Zahl (Integer) ohne Dezimalkomma aufbereitet. Wegen der kaufmännischen Anwendung wird der Dezimalpunkt durch ein Dezimalkomma ersetzt. Nach der Aufbereitung der Nachkommastellen wird durch Voranstellen von Leerzeichen der String auf die erforderliche Länge gebracht. Ist der String nach der Aufbereitung der Nachkommastellen schon länger als gewünscht, dann wird er nicht mehr verändert, sondern in voller Länge ausgegeben, um einen Datenverlust zu verhindern.

Das hier vorgestellte Maschinenprogramm verwendet nur relative Sprünge — außer bei den Aufrufen der Betriebssystemroutinen. Daher kann sich jeder Anwender das Programm ohne Änderungen in den Speicherbereich laden, der ihm am geeignetsten erscheint. Als Stringpuffer wird der Bereich ab $100 benutzt. DashatzurFolge, daß die GETSTR-Routine diesen String nicht in den Stringbereich kopiert. Der Stringbereich wird also nicht unnötig belastet. Eine Wertzuweisung A$=USR(X),L,NK ist dadurch aber auch nicht möglich, da die nächste Stringfunktion den Bereich ab $100 wieder überschreibt. Wenn druckaufbereitete Werte einer Variablen zugewiesen werden sollen, dann muß die Anweisung A$= " " +USR(X),L,NK oder A$=(USR(X),L,NK)+" " lauten, da dann das Ergebnis der Stringverknüpfung in den Stringbereich kopiert wird und der Variablen A$ dauerhaft zugewiesen ist.

Vor dem ersten Aufruf der USR-Funktion muß jetzt noch in Adresse 785 (Low-Byte) und 786 (High-Byte) die Startadresse der USR-Funktion hinterlegt werden. Listing 2 zeigt das Basic-Ladeprogramm für die USR-Funktion. Die Ladeadresse können Sie selbst bestimmen. Das Ladeprogramm setzt die Startadresse der USR-Funktion in den Speicherstellen 785 und 786 entsprechend. Zur Verdeutlichung der Anwendung der USR-Funktion enthält das Ladeprogramm verschiedene Druckaufbereitungen der Zahl r. Das Ergebnis des Beispiels ist in Bild 1 wiedergegeben.

(Dr. Michael Irskens/ah)
Bild 1. Beispiele für verschiedene Druckaufbereitungen
1000                ; f o r m a t r o u t i n e
1010                ; -------------------------
1020                ;
1030                ;            dr.m.irskens
1040                ;            leveser allee 13
1050                ;            3061 hespe
1060                ;
1070                ;
1080 space          equ 32    ; ' '
1090 komma          equ 44    ; ','
1100 e              equ 69    ; 'e'
1110 punkt          equ 46    ; '.'
1120 null           equ 48    ; '0'
1130 minus          equ 45    ; '-'
1140 ckcom          equ $aefd ; prueft auf komma
1150 getstr         equ $b487 ; string aus stringpuffer in stringbereich
1160 numtest        equ $ad8d ; ergebnis auf numerisch pruefen
1170 facstr         equ $bddd ; fac in string wandeln
1180 getbyt         equ $b79e ; byte holen
1190 string         equ $100  ; string-puffer
1200 temp           equ $02   ; temporaerer speicher
1210 nk             equ $57   ; fliesskomma-akku#3
1220 flen           equ $58
1230                *equ $c000 ;startadresse
1240 fo10           jsr numtest ;auf numerisch pruefen
1250                jsr facstr ;umwandeln numerisch->alpha
1260                jsr ckcom  ;auf komma pruefen
1270                jsr getbyt ;feldlaenge holen
1280                stx flen
1290                jsr ckcom  ;auf komma pruefen
1300                jsr getbyt ;nachkommastellenzahl holen
1310                stx nk
1320                pla        ; ruecksprungadresse vom stack entfernen,
1330                pla        ; damit kein numtest durchgefuehrt wird
1340                ;
1350                ; pruefen auf darstellung im e-format
1360                ; x-register equ stringlaenge
1370                ; y-register equ anzahl vorkommastellen
1380                ; y-register equ 0, wenn keine nachkommastellen gefunden
1390 fo19           ldx #$ff
1400                ldy #0
1410 fo20           inx
1420                lda string,x ;zeichen aus puffer laden
1430                beq fo30   ;0->stringende
1440                cmp #e     ;vergleich auf 'e'
1450                beq fo201  ;e-format umwandeln
1460                cmp #punkt  ;vergleich auf '.'
1470                bne fo20
1480                txa
1490                tay         ;anzahl vorkommastellen in y-register
1500                bne fo20
1510                ;
1520                ; umwandeln e-format
1530                ;
1540 fo201          lda string+2
1550                cmp #punkt
1560                bne fo22
1570                ;
1580                ; dezimalpunkt entfernen
1590                ;
1600                dex
1610                ldy #1
1620 fo21           iny
1630                lda string+1,y
1640                sta string,y
1650                bne fo21
1660                ;
1670                ; stellenverschiebung errechnen
1680                ;
1690 fo22           lda string+2,x ; zehnerstelle exponent
1700                and #$0f   ; ziffer errechnen
1710                asl a      ; *2
1720                sta temp
1730                asl a      ; *4
1740                asl a      ; *8
1750                adc temp   ; 8* + 2* equ 10*
1760                adc string+3,x; +einerstelle ascii
1770                sbc #47    ; ascii 0 abziehen
1780                ldy string+1,x ; vorzeichen exponent
1790                cpy #minus
1800                beq fo24
1810                adc #3
1820                stx temp
1830                sbc temp
1840                tay
1850                lda #null
1860 fo23           sta string,x ; string mit nullen erweitern fuer + exponent
1870                inx
1880                dey
1890                bne fo23
1900                lda #0
1910                sta string,x ; neues stringende
1920                beq fo19
1930                ;
1940                ; exponent<0: vornullen ergaenzen
1950                ; string um a-reg.+1 stellen verschieben
1960 fo24           sta temp
1970                lda #0
1980                sta string,x ; "e" durch 0 ersetzen
1990                txa
2000                clc
2010                adc temp
2020                tay
2030 fo25           lda string,x
2040                beq fo26   ; stringende uebertragen
2050                cmp #$30   ; vergleich auf ziffer
2060                bcs fo26   ; ziffer
2070                lda #null
2080                bne f027
2090 fo26           dex
2100 fo27           sta string,y
2110                dey
2120                bne fo25
2130                lda #punkt
2140                sta string+1
2150                bne fo19
2160                ;
2170                ; dezimalpunkt durch komma ersetzen
2180                ; y-register: anzahl vorkommazeichen
2190                ;
2200 fo30           tya
2210                beq fo50   ;nachkommastellen ergaenzen
2220                lda nk
2230                bne fo45  ; nachkommastellen
2240                tya
2250                tax
2260                lda string+1,x
2270                bne fo901 ; keine nachkommastellen, aber runden
2280 fo45           lda #komma ; '.' gefunden
2290                sta string,y ;durch ',' ersetzen
2300                bne fo71
2310 fo50           cpy nk     ;nachkommastellen ergaenzen
2320                beq fo100
2330                lda #komma
2340                sta string,x
2350                inx
2360                bne fo79
2370 fo71           sty temp   ;anzahl nachkommastellen errechnen
2380                sec
2390                txa
2400                sbc temp
2410                sec
2420                sbc #1    ;1 abziehen fuer dezimalpunkt
2430                cmp nk    ;vergleichen mit sollanzahl
2440                beq fo100 ;anzahl gleich
2450                bcs fo90  ;anzahl > soll
2460                tay       ;anzahl < soll
2470 fo79           lda #null
2480 fo80           sta string,x ;string mit nullen ergaenzen
2490                inx
2500                iny
2510                cpy nk
2520                bne fo80
2530 fo85           lda #0
2540                sta string,x
2550                ;
2560                ; nachkommastellen aufbereitet
2570                ; gesamtfeldlaenge korrigieren
2580                ;
2590                ; x-reg feldlaenge aktuell
2600                ; flen gesamtlaenge soll
2610 fo100          lda string+1
2620                cmp #$30
2630                bcs fo109    ; 1.zeichen ist eine ziffer
2640                inx
2650                txa
2660                tay
2670 fo105          lda string-1,y
2680                sta string,y
2690                dey
2700                bne fo105
2710                lda #null  ; null vor komma ergaenzen
2720                sta string+1
2730 fo109          cpx flen
2740                bcs fo130 ;feldueberlauf oder feldlaenge gleich
2750                ldy flen
2760 fo110          lda string,x;string verschieben
2770                sta string,y
2780                dey
2790                dex
2800                bpl fo110
2810                lda #space ;leerzeichen
2820 fo120          sta string,y ;rest mit leerzeichen fuellen
2830                dey
2840                bpl fo120
2850 fo130          lda #<string ;startadresse string laden in a/y
2860                ldy #>string
2870                jmp getstr
2880 fo90           sec
2890                sbc nk
2900                sta temp  ;anzahl ueberfluessiger nachkommastellen
2910                txa
2920                sec
2930                sbc temp  ;neue stringlaenge
2940                tax
2950                ;
2960                ; beim abschneiden von nachkommastellen runden
2970                ;
2980                lda string,x
2990 fo901          cmp #$35
3000                bcc fo85
3010                txa
3020                tay         ; index letztes zeichen
3030 fo91           dey
3040                beq fo92  ; string eine 1 voranstellen
3050                lda string,y
3060                cmp #$30   ; vergl < "0"
3070                bcc fo91
3080                clc
3090                adc #1     ; ziffer um eins erhoehen
3100                cmp #$3a   ; ueberlauf abfragen
3110                sta string,y ; veraendertes zeichen speichern
3120                bne fo85   ; kein uebertrag
3130                lda #null  ; null laden
3140                sta string,y
3150                bne fo91   ; naechste ziffer erhoehen
3160 fo92           txa        ; string um eine stelle verschieben fuer "1"
3170                tay
3180 fo94           lda string,y
3190                sta string+1,y
3200                dey
3210                bne fo94
3220                lda #$31   ; "1" laden
3230                sta string+1
3240                inx      ; feldlaenge erhoehen
3250                bne fo85
            
            
Listing 1. PRINT USING-Quellprogramm
10 rem ************************************************************************
11 rem *                 f o r m a t r o u t i n e                            *
12 rem ************************************************************************
13 rem * copyright:                                                           *
14 rem *  dr.m.irskens                                                        *
15 rem *  leveser allee 13                                                    *
16 rem *  3061 hespe                                                          *
17 rem ************************************************************************
18 rem *                                                                      *
19 rem * aufruf:                                                              *
20 rem *  usr(x),fl,nk                                                        *
21 rem *    x  = zu formatierender numerischer wert                           *
22 rem *    fl = feldlaenge der formatierten zahl                             *
23 rem *    nk = anzahl nachkommastellen der formatierten zahl                *
24 rem *  das ergebnis der usr-funktion ist der formatierte string. dieser    *
25 rem *  kann einer stringvariablen zugewiesen oder ausgedruckt werden.      *
26 rem * beispiele:                                                           *
27 rem *  a$=(usr(xy),10,2)+""                                                *
28 rem *  print usr(xy),10,2;" dm"                                            *
29 rem *                                                                      *
30 rem * besonderheiten:                                                      *
31 rem *  wenn nachkommastellen durch das formatieren abgeschnitten werden,   *
32 rem *  so wird die zahl gerundet.                                          *
33 rem *  zahlendarstellungen im e-format werden ebenfalls verarbeitet.       *
34 rem *  wenn die zahl in der angegebenen feldlaenge nicht dargestellt       *
35 rem *  werden kann, dann wird die zahl in der notwendigen feldlaenge dar-  *
36 rem *  gestellt, um einen zifferverlust zu vermeiden.                      *
37 rem *                                                                      *
38 rem * vor aufruf der funktion muessen folgende befehle einmalig durchge-   *
39 rem * fuehrt werden:                                                       *
40 rem *   poke 785,0   : low-byte der startadresse                           *
41 rem *   poke 786,192 : high-byte der startadresse = 49152                  *
42 rem *                                                                      *
43 rem * die routine ist voll verschieblich und kann daher an jeder stelle im *
44 rem * speicher liegen. die adressen der usr-funktion sind dann entsprechend*
45 rem * anzupassen.                                                          *
46 rem *                                                                      *
47 rem ************************************************************************
100 s=0:input "startadresse";b
110 for i=b to b+335
120 read a
130 s=s+a:poke i,a
140 next i
150 if s<>36986 then print "{rvon} fehler in den datazeilen {rvof}":stop
160 poke 785,b-256*int(b/256):poke 786,b/256
170 print " alles ok. "
199 rem testbeispiele
200 for e=0 to 9
210 f=~*10^e
220 a$=(usr(f),11,0)+""
230 print a$;usr(f),13,1;usr(f),14,2
240 next e
250 end
299 rem datazeilen
300 data32,141,173,32,221,189,32,253,174,32,158,183,134,88,32,253,174,32
301 data158,183,134,87,104,104,162,255,160,0,232,189,0,1,240,117,201,69,240
302 data8,201,46,208,242,138,168,208,238,173,2,1,201,46,208,12,202,160,1
303 data200,185,1,1,153,0,1,208,247,189,2,1,41,15,10,133,2,10,10,101,2,125
304 data3,1,233,47,188,1,1,192,45,240,23,105,3,134,2,229,2,168,169,48,157
305 data0,1,232,136,208,249,169,0,157,0,1,240,168,133,2,169,0,157,0,1,138
306 data24,101,2,168,189,0,1,240,8,201,48,176,4,169,48,208,1,202,153,0,1
307 data136,208,236,169,46,141,1,1,208,129,152,240,18,165,87,208,7,152,170
308 data189,1,1,208,119,169,44,153,0,1,208,12,196,87,240,40,169,44,157,0
309 data1,232,208,16,132,2,56,138,229,2,56,233,1,197,87,240,19,176,72,168
310 data169,48,157,0,1,232,200,196,87,208,247,169,0,157,0,1,173,1,1,201,48
311 data176,17,232,138,168,185,255,0,153,0,1,136,208,247,169,48,141,1,1,228
312 data88,176,20,164,88,189,0,1,153,0,1,136,202,16,246,169,32,153,0,1,136
313 data16,250,169,0,160,1,76,135,180,56,229,87,133,2,138,56,229,2,170,189
314 data0,1,201,53,144,179,138,168,136,240,24,185,0,1,201,48,144,246,24,105
315 data1,201,58,153,0,1,208,157,169,48,153,0,1,208,229,138,168,185,0,1,153
316 data1,1,136,208,247,169,49,141,1,1,232,208,131
Listing 2. PRINT USING-Basic-Lader. Bitte beachten Sie die Eingabehinweise auf Seite 6
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →