Im Magazin „CT" wurde im Heft 2 1986 der folgende Artikel abgedruckt.
Erzeugung von Inline-Dateien für Turbo Pascal 3.0.
|
|
Turbo-Inliner
Einbinden von Assembler-Files in Pascal-Programme
Ulrich Fuchs
Turbo-Pascal ist nicht nur schnell und komfortabel, sondern eignet sich mit seinen vielen sinnvollen Erweiterungen für fast alle Aufgaben, mit denen man als Programmierer zu tun bekommen kann.
Trotzdem wird es hin und wieder erforderlich, auf Assembler zurückzugreifen, sei es um Speicherplatz oder um Zeit zu sparen.
Leider hilft Turbo-Pascal kaum bei der Einbindung von Assembler-Code in Pascal-Texte.
Er muß in bereits assemblierter Form als Inline-Anweisung mit einer bestimmten Syntax eingegeben werden.
Dabei lassen sich ganz normale PRN-Files des verbreiteten MACRO80-Assemblers auch automatisch in den verlangten Inline-Code umformen - natürlich per Turbo-Pascal-Programm.
Unglücklicherweise besitzt das ansonsten so komfortable Turbo-Pascal keinen Assembler (man ist aber auch nie zufrieden).
Was das praktisch bedeutet, läßt sich nur dann ermessen, wenn man schon einmal längere Assembler-Passagen in Turbo-Pascal benutzt hat.
Hinter dem 'sehr bequemen Weg Maschinencode direkt in den Programmtext einzufügen' (so steht's im Handbuch) verbirgt sich ein eher umständliches Verfahren.
Seinen Quelltext muß man nämlich zunächst irgendwie assemblieren und dann mit dem Editor Byte für Byte in das Pascal-Programm übertragen.
Außerdem muß das Byte von einem '$'-Zeichen angeführt und durch einen Schrägstrich vom nächsten Byte getrennt werden.
Wenn man das Ganze auch ein paar Tage später noch verstehen möchte, tut man gut daran, auch noch den Quelltext inklusive der begleitenden Kommentare mit einzutippen, natürlich als Pascal-Kommentar.
Ein mechanisches, langweiliges und vor allem fehlerträchtiges Verfahren.
Eine Arbeit, die einem besser ein Computer abnehmen sollte!
Genau das macht das vorliegende Turbo-Pascal-Programm MAKEINL
.
Es untersucht das PRN-File des MACRO80-Assemblers (M80) und erzeugt daraus ein Inline-File.
Dieses Inline-File kann dann ohne weiteres mittels Include-Anweisung oder mit dem Editorbefehl 'Block-Read' in den Pascal-Quelltext eingebunden werden.
Einerseits lassen sich so Inlines für Turbo-Pascal mit einem sehr leistungsfähigen Assembler schreiben, so daß man auch vor längeren Assembler-Texten nicht zurückzuschrecken braucht, andererseits kann man das Resultat danach praktisch ohne Mehrarbeit in den Turbo-Text einbinden.
Der Assembler-Quelltext (Mnemonics und Labels) inklusive der meist notwendigen Kommentare wird dabei gleich mit ins Inline-File übernommen.
Grundsätzlich ist das Verfahren auch mit anderen Assemblern möglich, allerdings sind dann Änderungen erforderlich, je nachdem, wie stark das Format des jeweiligen Listing-Files vom Format des M80 abweicht.
Das Programm arbeitet folgendermaßen.
Zeilenweise
Die Prozedur Form_Newline
spielt eine wichtige Rolle in MAKEINL
.
Sie untersucht jede Zeile der PRN-Datei auf bestimmte Zeichen hin, die an fest vorgegebenen Positionen erwartet werden.
Das ist möglich, da der Assembler im PRN-Text ein festes Druckformat benutzt.
Kurz zusammengefaßt sieht das so aus:
Zunächst wird geprüft, ob absoluter Code (ASEG-Modus) erzeugt wurde.
Ist das der Fall, wird mit einer Fehlermeldung abgebrochen, da solcher Code nicht in Turbo-Kompilate eingebunden werden kann.
Danach prüft das Programm, ob in einer Zeile der String 'EXT
' als Hinweis auf externe Variablen zu finden ist.
Innerhalb einer Inline-Anweisung dürfen nämlich die in der jeweiligen Prozedur oder Funktion bekannten Variablennamen eingesetzt werden.
Der Turbo-Compiler ersetzt bei der Kompilation diese Variablennamen durch die Adressen, unter denen sie im Datenbereich abgespeichert werden.
Die Variablennamen können im M80-Quelltext benutzt werden, wenn sie mit
EXT
oder
EXTRN
zu externen Variablen erklärt werden (siehe Beispiel).
|
Dieser Assembler-Quelltext wird vom MACRO80 verarbeitet, der daraus ein REL-File und PRN-File erzeugen kann. |
|
Bestimmte Informationen stehen immer in bestimmten Spaltenpositionen des PRN-Files.
MAKEINL ist auf dieses feste Druckformat des M80 abgestimmt. |
|
Dies ist das Inline-File, das MAKEINL aus dem Beispiel erzeugt.
Es kann sofort per Include-Anweisung oder mit dem Block-Read-Kommando des Turbo-Editors in Pascal-Programme eingebaut werden. |
Wurde eine
EXT
-Deklaration gefunden, so wird die so deklarierte Variable in eine verkettete Liste eingefügt, damit der Variablenname später an der richtigen Stelle in das Inline eingesetzt werden kann.
Variablennamen dürfen im Prinzip 20 Zeichen lang sein, es ist jedoch nicht sinnvoll, Variablennamen zu verwenden, die länger als acht Zeichen sind, du mit dem Platz auf dem Bildschirm gespart werden muß, wenn die Inline-Zeile noch komplett in eine Bildschirmzeile passen soll.
Zeilen, die mit einem Semikolon beginnen, werden als Kommentare betrachtet, mit den Kommentarklammern versehen und ansonsten unverändert in das Inline-File übernommen.
Wurde am Anfang der Zeile kein Semikolon gefunden und ist vielmehr das siebente Zeichen der Zeile ein einfacher Anführungsstrich oder ein Ausrufungszeichen, dann enthält die Zeile gemäß M80-Format Maschinen-Code.
Eine solche Zeile muß genauer untersucht werden.
Dazu wird zunächst der relative Programmzählerstand ermittelt, der sich aus den ersten vier Zeichen der Zeile ergibt.
Die in Turbo bereits vorhandene Prozedur VAL
weist der Variablen ProgCounter
den entsprechenden Wert zu.
Für die folgenden Untersuchungen einer Zeile ist es nun wichtig zu wissen, ob der Befehl ein Ein- oder Zweibyte-Befehl ist, da sich das eventuell nachfolgende Adreßfeld natürlich durch ein zusätzliches eingefügtes Byte verschiebt.
Als Zweibyte-Befehl wird ein Befehl erkannt, der mit DD
, ED
oder FD
beginnt.
In diesem Fall wird das erste Befehlsbyte des Befehls zunächst abgetrennt, damit sich die Zeile normal weiterbearbeiten läßt, und erst zum Schluß wieder angefügt.
Fallweise
Bei der Bearbeitung einer normalen Zeile können folgende Fälle auftreten:
1. Der Name einer externen Variablen muß in die Liste eingefügt werden.
2. Es muß eine Sprungadresse im Inline-Format berechnet werden.
3. Innerhalb des Inlines muß Speicherplatz reserviert werden.
Der erste Fall ist im M80-Listing einfach daran zu erkennen, daß ersatzweise statt der Variablen-Adresse 0000*
eingesetzt wird.
Form_Newline
hat also nur die Zeile auf einen '*' hin zu untersuchen.
Wird der Stern als rechtes Zeichen der verkürzten Zeile gefunden, muß die Prozedur Insert_Symbol in Aktion treten.
Sie setzt einen Suchzeiger auf das zuletzt in die Liste eingetragene Listenelement und durchsucht die Liste rückwärts, bis sie den Variablennamen gefunden hat.
Insert_Symbol
setzt dann diesen Variablennamen in die Inline-Zeile ein.
Ist der Variablenname nicht in der verketteten Liste enthalten, werden statt dessen acht Fragezeichen eingesetzt.
Eine Sprungadresse ist genau dann zu berechnen, wenn das achte Zeichen der verkürzten Zeile der einfache Anführungsstrich oder das Ausrufungszeichen ist.
In Inlines müssen Sprünge relativ zum Programmzähler angegeben werden.
Calculate_Address
berechnet aus dem Stand des relativen Programmzählers und dem Sprungziel die Anzahl der Bytes, die zum Programmzähler addiert beziehungsweise davon subtrahiert werden müssen.
Bei der Kompilation ersetzt Turbo diese Angabe durch eine vierstellige absolute Adresse.
Wenn der String DFS
oder DS
gefunden wird, so muß Speicherplatz innerhalb des Inlines reserviert werden.
Dazu wird zunächst nur das Flag Mustdef
gesetzt, ansonsten aber die Zeile normal weiterbearbeitet.
Erst wenn die nächste Zeile gelesen und Form_Newline
ein weiteres Mal aufgerufen wurde, fügt die Prozedur Define_Space
die notwendige Anzahl von Nullen ein, weil diese Anzahl, also der zu reservierende Speicherplatz, jetzt erst aus den relativen Adressen der neuen und der zuletzt bearbeiteten Zeile ermittelt werden kann.
Normalerweise
Liegt keiner dieser Spezialfälle vor, brauchen nur die bereits angesprochenen '$'-Zeichen und Schrägstriche eingefügt zu werden.
Da der M80 der Lesbarkeit wegen Adressen 'richtig herum' schreibt, werden sie dabei gleich ins übliche reverse Byteformat (Lo/Hi-Byte) getauscht.
Ist dann alles richtig zusammengebastelt, wird die Inline-Zeile in eine Datei mit dem Default-Typnamen INL geschrieben.
Zeilen, die weder Kommentar- noch Code-Zeilen sind, werden übersprungen.
Findet das Programm das Schlüsselwort 'Macros:
' am Anfang einer sonst leeren Zeile, ist klar, daß der für Inline-Files relevante Teil des PRN-Files abgearbeitet wurde, und das Boolesche Flag Ready
wird gesetzt.
Das Programm schreibt nun noch ein NOP
an das Ende des Inline-Files und schließt es mit der erforderlichen Klammer und dem Semikolon.
Das ist einfacher, als den schon angefügten Schrägstrich wieder zu entfernen und kostet lediglich ein Byte.
Am Anfang des Inline-Files müssen natürlich das reservierte Wort INLINE
und eine öffnende Klammer stehen.
Auch daran hat MAKEINL
gedacht.
Hinweise
MAKEINL
kann mit Argument aufgerufen werden.
Dafür sorgt die Prozedur Get_Name
, die bei einem Erstaufruf des Programms ab der Speicherstelle 80h nach dem Argument sucht und es der Prozedur Select_Name zur Analyse übergibt.
Dadurch ist die Wahl einiger Optionen durch die Angabe des File-Namens möglich.
Die aufgeführten Beispiele erklären die zur Verfügung stehenden Möglichkeiten.
MAKEINL
meldet sich mit dem Stern, wenn es ohne Argument aufgerufen wird.
Es kann dann eine Anweisung entsprechend angegebenen Syntax gegeben werden.
Die in Klammern angegebenen Anweisungsteile sind optional.
Wird nur der File-Name ohne Dateiklasse angegeben, so wird als Typ .PRN angenommen (Default-Typ).
Das generierte File wird unter FILENAME.INL
abgelegt.
A>MAKEINL TOUPPER
Startet MAKEINL
, sucht nach TOUPPER.PRN
, generiert daraus den INLINE-Text und legt ihn dann als TOUPPER.INL
auf der gleichen Diskette ab.
A>MAKEINL A:TOUPPER.TXT/B:
Startet MAKEINL
, sucht nach TOUPPER.TXT
auf Laufwerk A, generiert TOUPPER.INL
und legt das File auf Laufwerk B ab.
*C:TOUPPER/B:UPTEXT
MAKEINL
sucht nach TOUPPER.PRN
auf Laufwerk C und generiert daraus UPTEXT.INL
auf dem Laufwerk B.
A>makeinl toupper/toupper.txt
Sucht nach TOUPPER.PRN
und generiert TOUPPER.TXT
auf dem Bezugslaufwerk.
A>MAKEINL TOUPPER/LST:
Sucht nach TOUPPER.PRN
und gibt das INLINE-File sofort auf dem Drucker aus.
Eine Diskettendatei wird nicht angelegt.
Mit /AUX:
würde die serielle Schnittstelle angesprochen.
Mit der Return-Taste wird das Programm verlassen, und mit Ctrl/X läßt sich die Erzeugung des INL-Files vorzeitig unterbrechen.
Wenn alles geklappt hat, braucht man das INL-File nur noch mit der Include-Anweisung oder mit den Editor-Kommandos in den Quelltext einzubinden.
|
Die Prozedur Form_Newline analysiert eine Zeile des M80-PRN-Files und generiert eine Zeile Inline-Code. |
[DRIVE:] FILENANE [.TYP] [/] [DRIVE:] [NEUNAME] [.INL]
|
Dies ist die Kommandostruktur, die MAKEINL versteht.
Die Teile in den eckigen Klammern sind optional, müssen also nicht immer mit angegeben werden, können aber. |
|
[Original-Listing],
mit dem es einige Probleme gab, deswegen hier ein
[modifiziertes Listing] |
MAKEINL ist ein Programm zur automatischen Erzeugung von Inline-Code aus dem PRN-File des MACRO80-Assemblers für Turbo-Pascal.
Es läuft mit allen Compiler-Versionen unter CP/M 80.
|
Eingescanned von
Werner Cirsovius
März 2003
© Heise Verlag