Teil 13 „SLOW & FAST“

Der C-Kurs
Antworten
Benutzeravatar
bodo
User
Beiträge: 321
Registriert: 14.02.2007, 17:21
Kontaktdaten:

Teil 13 „SLOW & FAST“

Beitrag von bodo » 13.11.2010, 13:02

C für BASIC-Programmierer

Arbeiten mit dem z88dk Cross-Compiler

von Jens Sommerfeld und Bodo Wenzel

Teil 13

Im Kapitel gleicher Nummer führt uns Vickers in die Geheimnisse von „SLOW & FAST“ ein. Um es gleich vorwegzunehmen: ich habe es nicht geschafft, innerhalb eines C-Programms zwischen den Modi hin- und herzuschalten. Wer von euch das hinbekommt, kann seine Methode ja im Forum veröffentlichen. Hinweis: die beiden Funktionen heißen zx_fast() und zx_slow().

Stattdessen bekommt ihr einige Sonderfunktionen geboten, die von den z88dk-Machern extra für den ZX81 vorgesehen wurden. Auf HRG geht ein späterer Teil ein.

Manipulation des gesamten Bildschirms

Beginnen wir mit zwei Funktionen, die den gesamten Bildschirm anfassen. Den ganzen Bildschirm? Nein, ein kleines Dorf... ähm... falscher Text... Also, es sind nur 22 der 24 Zeilen, obwohl die Ausgaben über C alle 24 Zeilen benutzen.

Code: Alles auswählen

#include <stdio.h>
#include <zx81.h>

int main(void) {
    char eingabe;

    puts("HALLO, WELT.");
    gets(&eingabe); /* Bitte nur NEWLINE eingeben! */
    invtxt();
    gets(&eingabe); /* Bitte nur NEWLINE eingeben! */
    mirrortxt();

    return 0;
}
Dieses kleine Beispiel schreibt zuerst den bekannten Text auf den Schirm. Nach NEWLINE wird der Ausgabeschirm invertiert. Nach einem weiteren NEWLINE wird der Ausgabeschirm horizontal gespiegelt. Wer auch immer das braucht...

Umwandlungen zwischen ASCII und ZX81-Zeichensatz

Wie ihr schon gelernt habt, gibt es in C zwei Zeichensätze: zum einen den für den Quelltext, der ist bei uns ASCII; zum anderen den für das laufende Programm, der ist bei uns der ZX81-Zeichensatz. Die Umwandlung zwischen den ASCII-Zeichen, die ein C-Programm einliest oder ausgibt, und den ZX81-Zeichen können wir während des laufenden Programms umschalten.

Das folgende Beispielprogramm zeigt in der ersten Hälfte das Aus- und wieder Einschalten des Zeichensatzkonverters. Bei ausgeschaltetem Konverter müssen natürlich die entsprechenden ZX81-Kodes benutzt werden, daher habe ich dort Zahlen laut der Kodierungstabelle in Anhang A des ZX81-BASIC-Handbuchs verwendet.

In der zweiten Hälfte werden einzelne Zeichen zwischen den Zeichensätzen umgerechnet. Vor allem die Assemblerfreaks, die Treiber für Disketten oder MMCs schreiben, kennen solche Umrechnungen bereits.

Code: Alles auswählen

#include <stdio.h>
#include <zx81.h>

int main(void) {
    puts("HALLO.");
    zx_asciimode(0);
    printf("%c%c%c%c%c%c\n", 45, 38, 49, 49, 52, 27);
    zx_asciimode(1);
    puts("HALLO.");

    printf("%x %d\n", 'H', ascii_zx('H'));
    printf("%x %d\n", zx_ascii(38), 38);
    printf("%x %d\n", 'L', ascii_zx('L'));
    printf("%x %d\n", zx_ascii(52), 52);

    return 0;
}
Kontakt zum BASIC-Programm

Ja, ihr habt richtig gelesen: das C-Programm kann mit dem BASIC-Programm interagieren. Zunächst etwas Einfaches:

Code: Alles auswählen

#include <stdio.h>
#include <zx81.h>

int main(void) {
    printf("BYTES BASIC = %d\n", zx_basic_length());
    printf("BYTES VARIABLEN = %d\n", zx_var_length());

    return 0;
}
Die beiden Funktionen geben uns die Länge des BASIC-Programms bzw. des Variablenbereichs an. Zum Ausprobieren könnt ihr ja noch mehr BASIC-Zeilen eingeben und/oder BASIC-Variablen anlegen, um verschiedene Ausgaben zu erhalten.

Wesentlich spannender finde ich die Möglichkeit, einzelne BASIC-Zeilen ausführen zu können (nach Compilieren und Laden solltet ihr ein paar einfache Zeilen mit Zeilennummern zwischen 100 und 200 eingeben):

Code: Alles auswählen

#include <stdio.h>
#include <zx81.h>

int main(void) {
    int l;

    for (l = 100; l <= 200; l += 10) {
        printf("ZEILE %d : %d\n", l, zx_line(l));
    }

    return 0;
}
Offenbar wird der Fehlercode der BASIC-Ausführung als int von zx_line() zurückgegeben. Falls die gewünschte Zeilennummer nicht gefunden wird, sucht der BASIC-Interpreter wie gewohnt nach der nächstgrößeren Zeilennummer. Es wird auch nur jeweils eine Zeile ausgeführt. Die Versuche, Unterprogramme mit GOSUB aufzurufen, waren leider nicht von Erfolg gekrönt. Auch hier könnt ihr eure Erfolgsstories im Forum bekanntgeben...

Kommen wir zum Austausch von Werten zwischen BASIC und C. Dummerweise kann das z88dk bisher „nur“ Strings hin- und herkopieren, und dabei muss beim Holen eines BASIC-Strings nach C auch noch das letzte Zeichen extra gelöscht werden, das macht die markierte Zeile. Das sieht aus wie ein Fehler im z88dk, vielleicht wird das in einer der nächsten Versionen ja korrigiert. Für andere Rechner als den Zeddy stellt das z88dk auch Funktionen zum Austausch von numerischen Variablen zur Verfügung, nur so als Perspektive.

Code: Alles auswählen

#include <stdio.h>
#include <string.h>
#include <zx81.h>

int main(void) {
    char v[20];

    printf("GET %d ", zx_getstr('A', v));
    v[strlen(v) - 1] = '\0'; /* <--- letztes Zeichen löschen */
    printf("= \"%s\"\n", v);
    zx_setstr('B', v);

    return 0;
}
Nach dem Compilieren und Laden des Programms müsst ihr eine Variable A$ mit einem String kürzer als 20 Zeichen anlegen, egal ob direkt (dann nicht mit RUN starten!) oder als Programmzeile vor dem Aufruf des C-Programms. Falls diese Variable beim Lauf des C-Programms nicht existiert, kann euch sonst der Rechner abstürzen...

Schön wär's...

C stammt ja aus einer Zeit, in der jeder Computerbenutzer noch eine Kommandozeile anzuwenden wusste. Daher können einem normalen C-Programm auch Argumente über die Kommandozeile mitgegeben werden. Leider geht dies beim z88dk nicht, obwohl es ja eine schöne Möglichkeit wäre. Trotzdem möchte ich euch die Methode für den Fall zeigen, dass ihr einmal für andere Rechner C-Programme schreibt.
argc_argv.gif
argc_argv.gif (5.45 KiB) 3098 mal betrachtet
Unsere Hauptfunktion erhält dazu zwei Parameter, die traditionell argc (argument count) und argv (argument vector) heißen. Der erste gibt an, wieviele Argumente vorhanden sind; der zweite ist ein Zeiger (Zeiger werden wir später behandeln... Die Assemblerprogrammierer kennen Zeiger schon: es sind ganz normale Adressen!) auf ein Array von Zeigern auf die Zeichenketten der Argumente, siehe Bild. Die erste Zeichenkette ist dabei der eingegebene Name des aufgerufenen Programms.

Das Auseinandernehmen der Kommandozeile in die einzelnen Argumente besorgt dabei die C-Bibliothek. Um Argumente mit Leerzeichen zu übergeben, müsst ihr diese in Anführungszeichen setzen, wie bei “C D“ im Bild. Das folgende Beispielprogramm lässt sich zwar compilieren, dokumentiert aber, dass das z88dk die beiden Parameter mit unsinnigen Werten gefüllt hat:

Code: Alles auswählen

#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("%d ARGUMENTE\n", argc);
    while (argc > 0) {
        printf("\"%s\"\n", *argv);
        argv++;
        argc--;
    }

    return 0;
}
Als normales PC-Programm arbeitet es aber wie erwartet, das zeigte ein Test mit dem GNU-Compiler.

So, das war es für diesen Teil, das nächste Mal geht es um eigene Funktionen!
B0D0: Real programmers do it in hex.

Antworten