APPLICATIONSDIVERS ★ RSX CROSS-REFERENCE (HAPPY COMPUTER) ★

RSX Cross-Reference (Happy Computer)Applications Divers
★ Ce texte vous est présenté dans sa version originale ★ 
 ★ This text is presented to you in its original version ★ 
 ★ Este texto se presenta en su versión original ★ 
 ★ Dieser Text wird in seiner Originalfassung präsentiert ★ 

Welcher Wert steht wo?

In einem Programm alle benutzten Variablen zu kennen, ihre Position zu finden und bei Änderungen keine zu vergessen, das ist auch für geübte Programmierer ein risikoreiches Unterfangen. Hilfe bietet dieses Cross-Reference-Programm, das die Namen heraussucht und auf die dazugehörigen Zeilen verweist.

Cross-Reference-Routinen, die in Basic geschrieben sind, haben zwei erheblich störende Nachteile: Zum einen sind sie sehr langsam und zum zweiten muß das zu untersuchende Programm in Form einer ASCII-Datei vorliegen. Normalerweise werden Basic-Befehlsworte als »Token« verkürzt gespeichert. In einer ASCII-Datei würden die vier Werte 47, 4F, 54 und 4F (alle hexa dezimal) dem GOTO entsprechen. Mit dem Schneider-Computer ist es zwar einfach aus einem Basic-Programm eine ASCII-Datei zu machen (einfach mit dem Zusatz »A« speichern). Der dazugehörige Specher- und Ladevorgang ist aber umständlich. Aus diesem Grunde ist »Cref« vollständig in Maschinencode geschrieben. Auch 20 KByte lange Programme werden somit in Sekundenschnelle bearbeitet und ausgewertet.

Der Basic-Interpreter Ihres Schneiders stellt beim Bearbeiten eines Programms eine Tabelle der benutzten Variablen auf, um bei späteren Wertzuweisungen (oder Bildschirmausgaben) ohne langes Suchen die richtige Variable mit ihrem aktuellen Wert zu finden.

Grundidee von »Cref« ist es, diese Tabelle durch Aufruf geeigneter Interpreter-Routinen aufbauen zu lassen ohne das Programm zu starten. Dadurch werden vorzeitige Wertzu-weisungen verhindert. Für jeden einzelnen Namen aus der Tabelle wird das Programm nach entsprechenden Referenzen durchsucht. Somit spart man sich den Aufbau einer speziellen sortierten Referenzliste. Der Speicherbedarf reduziert sich dadurch erheblich, so daß auch große Programme ohne Probleme bearbeitet werden können.

»Cref« hegt im Speicherplatz A000 hex und ist damit auch auf den Betrieb des Diskettenlaufwerks von Schneider abgestimmt. Besitzer eines anderen Laufwerks, eines CPC 664 oder eines CPC 6128, müssen unbedingt die von »Cref« benutzten System-Routinen und Vektoren anpassen.

Token statt Befehle

Zum besseren Verständnis der Routine sind einige Kenntnisse über die Ablage von Basic-Zeilen beim Schneider nötig. Betrachten wir hierzu Listing 1. In Bild 1 finden Sie das gleiche Programm so wie es der Computer nach dem Befehl LOAD gespeichert hat. Es fällt sofort auf, daß die Zeilen nicht im ASCII-Code vorliegen, sondern »mundgerecht« für den Interpreter aufbereitet sind. Anstelle der Basic-Befehle tauchen die sogenannten Tokens auf. Dabei handelt es sich um nichts anderes als eine (allerdings sehr trickreich) verkürzte Schreibweise für den Befehl. Da ein Token maximal zwei Byte lang ist, wird er vom Interpreter schneller erkannt und bearbeitet. Weitersieht man sofort, daß Integer-Zahlen in eine zwei Byte lange hexadezimale Zahl umgewandelt werden und daß die Zeilennummer im 3. und 4. Byte der Zeile (hexadezimal) vorliegt. Die ersten zwei Byte einer Zeile geben die Länge der vom Interpreter umgewandelten Zeile an. Diese ist meist nicht identisch mit der Länge der ursprünglichen Zeile. Die Namen der Variablen entsprechen bis auf die letzte Stelle der normalen ASCII-Schreibweise. Zum Wert des letzten Zeichens wird immer 80 hex addiert, also das siebte Bit gesetzt. Die Schreibweise in Groß- und Kleinbuchstaben wird beibehalten, obwohl der Computer beim späteren Bearbeiten keinen Unterschied macht (»variable« ist für ihn beispielsweise das gleiche wie »VARIABLE« oder »vAriaBlE«),

Von der Syntax her ist es jetzt leicht verständlich, wie der Interpreter eine Zeile bearbeitet. Nach der Zeilennummer steht ja entweder ein Befehl (also ein Token) oder aber eine Variable — von Blanks und Fehlem einmal abgesehen. Um den Variablennamen zu bekommen, werden alle Zeichen gelesen, bis hin zu dem Wert bei dem Bit 7 in einem Byte gesetzt ist. Ganz so einfach ist es dann aber doch nicht. Vor jedem Variablennamen stehen nämlich noch drei weitere Bytes. Untersuchen wir das erste. Bei »alpha« aus dem Beispiel hat es den Wert 0Dhex, bei »index%« den Wert 02hex, bei »mes$« den Wert 03hex und Sie vermuten richtig, daß hierdurch der Typ der Variablen festgelegt ist. Also bedeutet:

  • 0Dhex eine Variable ohne Typenkennung
  • 04hex eine Real-Variable
  • 03hex eine String-Variable
  • 02hex eine Integer-Variable

Die beiden Bytes vor dem Variablennamen haben so lange den Wert Null, bis das Programm gestartet wird. Nach »RUN« ändert sich hier nämlich etwas, wie man in Bild 2 sieht, Die Änderung hängt mit dem Aufbau der Variablentabelle durch den Interpreter zusammen. Für unser Beispiel ist diese in Bild 3 wiedergegeben, Die Variablen werden also in einer Tabelle mit ihren aktuellen Werten — falls es hier Zahlen sind — abgelegt. Für Integerzahlen sind dabei 2 Byte, bei Realzahlen S Byte reserviert, String-Variable belegen in der Tabelle 3 Byte: das erste gibt die Länge des Strings an, die beiden nächsten die Adresse, wo die Zeichenkette zu finden ist. »mes$« beispielsweise hat die Länge 4 und die Zeichenkette steht bei 01CA hex. Zu beachten ist ferner, daß in der Variablentabelle auch die Typenkennung — jeweils um eins vermindert — mit abgelegt ist,

Im RAM des CPC steht bei AE85hex der Zeiger auf diese Variablentabelle (in unserem Fall ist dies 0258hex). Die zwei Byte vor »alpha« in der ersten Zeile von Bild 2 als hexadezimale Zahl interpretiert, ergeben 09hex. Diesen Wert addieren wir zum Tabellenanfang (0258hex) und erhalten die Zahl 0261hex. Ziehen wir 1 ab, so haben wir die Adresse, an der der aktuelle Wert der Variablen in der Variablentabelle steht (0261hex —1). Damit ist das Geheimnis der zwei Byte vor einem Variablennamen gelöst: Hier steht die Zahl (Offset), die, zum Tabellenanfang addiert, die Adresse für den aktuellen Wert einer Variablen ergibt. Falls dieser Offset Null ist, »weiß« der Interpreter, daß die Variable noch nicht in der Tabelle angelegt ist. Damit ist auch die Wirkung des »CLEAR«-Befehls beim CPC klar. Es wird nämlich einfach der Offset vor jeder Variablen innerhalb einer Interpreterzeile gelöscht. Diese Tatsache wollen wir für »Cref« ausnutzen.

Untersuchen wir den Aufbau der Variablentabelle, so stellen wir fest, daß sie nicht sortiert abgelegt wird. Betrachten wir also wieder die zwei Byte vor dem Variablennamen in der Tabelle (Bild 3). Bei fast allen Variablen steht der Wert Null. 0E hex (bei X) addiert zum Tabellenanfang 0258hex ergibt 0266hex und bei 0267hex steht X1. Die Vermutung, daß 0Ehex als Offset zu verstehen ist, ist richtig. Mit den zwei Byte vor dem Variablennamen in der Tabelle baut der Interpreter für die Namen mit gleichem Anfangsbuchstaben eine verkettete Liste auf. In den Adressen ADD0hex bis AE03hex legt er den Offset für den ersten Eintrag eines Variablennamens entsprechend dem Anfangsbuchstaben ab. Taucht beim Bearbeiten eines Programms nun eine andere Variable mit dem gleichen Anfangsbuchstaben auf, so trägt er deren Namen am Ende der Variablentabelle ein. Dann wird anhand der Einträge in den Adressen bei ADD0hex bis AE03hex überprüft, ob es schon eine Variable mit diesem Anfangsbuchstaben gibt. Falls nicht, wird der Offset des zuletzt eingetragenen Namens entsprechend dem Anfangsbuchstaben in einer Adresse zwischen ADD0hex und AE03hex abgelegt. Falls ja, trägt er den Offset des vorher eingetragenen Namens in den zwei Byte vor dem letzten Eintrag ein und legt den Offset der zuletzt eingetragenen Variablen zwischen ADD0hex und AE03hex neu ab. In der Variablentabelle entsteht so eine Kette für Variable mit gemeinsamen Anfangsbuchstaben, Deren erstes Element findet man über den Offset aus der dem Anfangsbuchstaben entsprechenden Adresse zwischen ADD0hex und AE03hex. Das letzte Element dieser Kette ist durch den Offset Null gekennzeichnet.

Daß die Variablen »alpha« und »array« nicht verkettet sind (bei beiden ist der Offset in der Variablentabelle nach Bild 3 Null), liegt daran, daß »alpha« eine skalare Variable ist, »array« dagegen eine indizierte. Für skalare und indizierte Variablen werden nämlich zwei verschiedene Tabellen erstellt. Den Aufbau der Array-Tabelle (für indizierte Variablen) brauchen wir aber nicht näher untersuchen, da bei »Cref« skalare und indizierte Variable gleich behandelt werden.

Wo stehen die Sprungadressen?

Zu einer vernünftigen Cross-Referenz-Liste gehört auch die Ausgabe von Sprungadressen. Wie werden diese nun vom Interpreter des Schneiders abgelegt? Schauen wir uns dazu erst Bild 1 an. Bei »GOTO 10« (Zeile 90) und »THEN 100« (Zeile 70) werden die Zeilennummern hexadezimal abgelegt. Zuvor wird noch die Kennung 1Ehex eingetragen. Nach »RUN« ändert sich diese Kennung zu 1Dhex (Bild 2) und die Zeilennummer ist verschwunden. Der Interpreter wandelt nämlich die Zeilennummern in Adressen der Zeile um (ein Grund für die Geschwindigkeit des CPC-Basics). Erkennt der Interpreter die Kennung 1Ehex, so sucht er die Anfangs-adresse der entsprechenden Zeile, ersetzt die Nummer durch die gefundene Adresse und ändert die Kennung in 1Dhex. Beim nächsten Mal hat er dann die Sprungadresse direkt zur Verfügung.

Wir haben nun genug »Interpreter-Rüstzeug« und können mit der Programmbeschreibung von »Cref« beginnen. Der erste Programmteil ab A000hex) dient dem Einbinden von »Cref« als RSX-Befehlserweiterung. Nach Laden des Binärfiles (ab A000hex) — vorher das zu untersuchende Basic-Programm mit »MEMORY &9FFF« schützen — und »CALL &A000« kann die Routine mit »|CREF« aufgerufen werden.

Da wir mit »Cref« auf Routinen des Interpreters zugreifen, muß zuerst das entsprechende ROM freigegeben werden. Der Ausgabekanal wird auf den Drucker gegeben bevor in der Routine GVAR die Ausgabe der Referenzen für die Variablen vorbereitet wird. Hierzu muß zunächst die Variablentabelle gelöscht werden. Von PSTART (AE81hex) wird die Adresse des Programmanfangs in das Register HL geladen. Die Routine NXTLNE liest die Zeilenlänge in das Register BC und speichert in ZNR die Zeilennummer. Ist die Länge einer Zeile Null, so ist das Programmende erreicht. Ansonsten wird die Interpreter-Routine NXTELM aufgerufen, die in das Register A ein Token zurückgibt und HL entsprechend erhöht. Je nach Inhalt von A wird dann in der Zeile weiter nach einem Token gesucht, die nächste Zeile geholt oder überprüft ob eine Variable vorliegt. Letzteres erledigen die Routinen VARTST und TSTTYP. Handelt es sich um eine Variable, so wird mit TABEXT durch Aufruf entsprechender Routinen deren Name in die Tabelle eingetragen.

Auf einen wichtigen Punkt sei in diesem Zusammenhang noch hingewiesen. Wie schon erwähnt, verwaltet der Interpreter des CPC für skalare und indizierte Variablen zwei verschiedene Tabellen. Um nicht beide hintereinander bearbeiten zu müssen und den Programmieraufwand in Grenzen zu halten, werden durch den Aufruf von TABEXT die Variablennamen nur in die Tabelle für skalare Variablen eingetragen. Wir haben also keinen Unterschied zwischen skalaren und indizierten Variablen (vergleiche hierzu Bild 4, das die Variablentabelle für unser Beispiel nach Aufruf von »Cref« wiedergibt). Im Gegensatz zu Bild 3 sind hier die Variablen »array« und »alpha« verkettet. Dies wirkt sich aber nur bei Programmen aus, in denen beispielsweise »a$«, »a%« und »a!« gleichzeitig verwendet werden.

Eine weitere Einschränkung ist bei der Bearbeitung von benutzereigenen Funktionen zu machen. Die mit DEF FN definierten Funktionen werden mit dem Token E4hex gekennzeichnet, ansonsten aber wie Variablen behandelt. Da »Cref« das
Token E4hex nicht berücksichtigt, erscheinen die Funktionen in der Referenzliste als Variablennamen.

Nachdem in GVAR das Programmende erkannt wurde, folgt der Aufruf der Routine REFVAR. Diese besteht aus einer Schleife, in der für jeden Buchstaben des Alphabets (der entsprechende ASCII-Wert steht in Register C) folgende Routinen aufgerufen werden:

  • BUFINI: setzt den Zeiger BUFPTR auf den Anfang des Buffers,
  • FINDVA: überprüft, ob für den jeweiligen Buchstaben in der Variablentabelle ein Eintrag vorliegt,
  • MRKEND: markiert das Ende des Buffers,
  • VAROUT: gibt die entsprechende Referenzliste aus.

Um in der Variablentabelle einen Eintrag zu überprüfen, wird die Routine TABADR benutzt, Diese gibt in Register HL eine Adresse zurück, anderen Stelle ein zur Berechnung der Variablenadresse notwendiger Offset steht. Ist der Offset Null, so liegt kein Eintrag unter diesem Buchstaben vor. Sonst ergibt der Offset zum Inhalt von VARSTA addiert, gerade die Adresse der Variablen, die zuletzt unter dem entsprechenden Anfangsbuchstaben in der Tabelle eingetragen wurde. Vor dieser Adresse steht der Offset des vorherigen Eintrags. Die so erhaltene Adresse des Variablennamens wird dann sortiert in den Buffer eingetragen. Da hierbei indirekt sortiert wird, also nur die zwei Byte großen Zeiger auf die Variablen gespeichert werden, reicht selbst bei einem 30 KByte großen Basic-Programm der Speicher des CPC voll aus.

Beim Ausdruck der Referenzen wird zuerst über die jetzt sortiert vorliegende Zeigertabelle der Variablenname ausgegeben. Für diesen Namen bereitet dann die Routine REFOUT alles vor, um das Programm Zeile für Zeile nach eben dieser Variablen zu durchsuchen. Hierbei wird die Routine INLINE aufgerufen, die überprüft, ob in einer Zeile der gesuchte Name ausgeführt ist und gegebenenfalls die Zeilennummer ausgibt.

Nach Ausdruck der Referenzen wird durch die Routine GLNR die Referenzliste für die Zeilennum-mem erstellt. Hierbei hilft wieder die Interpreter-Routine NXTELM, nach deren Aufruf jetzt die Token 1Ehex und 1Dhex bearbeitet werden. Liegt eine Zeilennummer vor (1Ehex), so wird sie direkt durch ZNRSTO eingetragen. Bei einer Zeilenadresse wird zuerst die entsprechende Zeilennummer gesucht. Nachdem in ZNRSTO die Zeilennummer mit der entsprechenden Referenzzeile in den Buffer eingetragen wurde, wird diese Nummer mit derjenigen der vorherigen Eintragung verglichen. Ist die Zeilennummer des letzten Eintrags kleiner, so werden die Eintragungen vertauscht. Dies wird dann so lange durchgeführt, bis die Liste richtig sortiert ist.

Vor Aufruf der »Cref«-Routine muß zuerst die Zeilenbreite des Druckers durch WIDTH gesetzt werden. Der Interpreter nimmt immer den Wert 132, der bei den meisten Druckern zu hoch ist. Nach Ausgabe des Variablennamens werden ab Position 24 die Referenzzeilen ausgedruckt. Die Länge der Variablennamen sollte nicht größer als 20 sein, da sonst das Bild unschön wird. Mit der Escape-Taste kann der Ausdruck jederzeit unterbrochen werden.

Horst Udo Hanenberg, HC

★ PUBLISHER: Happy Computer
★ YEAR: 1986
★ CONFIG: 64K + AMSDOS
★ LANGUAGE:
★ LiCENCE: LISTING
★ COLLECTION: HAPPY COMPUTER-SCHNEIDER SONDERHEFT
★ AUTHOR: Horst Udo Hanenberg
 

★ AMSTRAD CPC ★ DOWNLOAD ★

Type-in/Listings:
» RSX-Cross-Reference    (Happy  Computer-Sonderheft)    GERMANDATE: 2021-03-19
DL: 160
TYPE: ZIP
SiZE: 5Ko
NOTE: 40 Cyls
.HFE: Χ

» RSX-Cross-Reference    (Happy  Computer-Sonderheft)    LISTING    GERMANDATE: 2021-03-19
DL: 181
TYPE: PDF
SiZE: 3033Ko
NOTE: 10 pages/PDFlib v1.6

★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
» Applications » Crossreferenz (Schneider Aktiv)
» Applications » Cross-Referenz Variablen (Schneider Magazin)
» Applications » Cross-Reference (Compute Mit)
» Applications » Interactive Cross-Referencing
Je participe au site:
» Vous avez des infos personnel ?
» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop/c
Page créée en 532 millisecondes et consultée 779 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.