PofoWiki

Die ultimative Informationsquelle zum ATARI Portfolio

Benutzer-Werkzeuge

Webseiten-Werkzeuge


software:diy:andere:gofolio

Dokumentation zu Gofolio Version 2.2 (2004)

INHALTSVERZEICHNIS

  1.0 Copyright
    1.1 Vorbemerkung
  2.0 Einleitung
    2.1 Eigenschaften
    2.2 Compilieren und Ausführen von Programmen
  3.0 Der Aufbau von  Gofolio-Programmen
    3.1 Beispiel-Programm
    3.2 Bezeichner in Gofolio
      3.2.1 Preprocessor-Anweisungen
    3.3 Variablen
    3.4 Darstellung von Zahlenkonstanten
    3.5 Arrays
    3.6 Strings
    3.7 Dateien
    3.8 Funktionen
      3.8.1 Die Deklaration von Funktionen
      3.8.2 Parameterübergabe
    3.9 Zusammenfassung zum Aufbau von Gofolio-Programmen
  4.0 Operatoren in Gofolio
    4.1 Additive Operatoren
    4.2 Multiplikative Operatoren
    4.3 Relationale Operatoren
    4.4 Der Zuweisungs-Operator :=
  5.0 Beschreibung der Gofolio-Funktionen in alphabetischer Reihenfolge
  6.0 Fehlermeldungen des Compilers (GF.EXE)
  7.0 Versionsinformationen
  8.0 Tips
    8.1 Maschinenprogramme unter Gofolio 
    8.2 Unterprogramme zur Stringbearbeitung
    8.3 Geschwindigkeitsoptimierung

GOFOLIO ist Freeware. D.h., sie können mit GOFOLIO kostenlos arbeiten und es beliebig weitergeben. Haben Sie Fragen oder Anregungen zu GOFOLIO, so können sie sich gerne an den Autoren wenden:

              Lutz Herrmann
              Lorichsstrasse 35
              22307 Hamburg.
              
              E-Mail : windkraft@hotmail.com
              Hompage: http://www.bitpilot.de


Sollten Sie ein interessantes Programm mit GOFOLIO entwickelt haben, so können Sie es mir gerne zusenden. Ich werde es dann in die Sammlung der Beispielprogramme mitaufnehmen.

1.1 Vorbemerkung

Bei den weiteren Ausführungen ist die folgende Terminologie zu beachten:

  • Alle Schlüsselworte, welche zur Sprache Gofolio gehören, sind stets groß geschrieben, z.B. die Funktion PRINT().
  • Soll ausgedrückt werden, daß bestimmte Elemente eines Gofolio-Programms oder einer Gofolio-Funktion als Option vorgesehen sind, so werden diese zwischen spitzen Klammern angegeben, z.B.: <Ausdruck>.
  • Soll ausgedrückt werden, daß ein bestimmtes Element eines Gofolio-Programms oder einer Gofolio-Funktion sich hier beliebig oft wiederholen kann, so wird dies durch 4 aufeinander folgende Punkte angezeigt, z.B.:

Ausdruck, Ausdruck,…. oder Ausdruck,…. Zu beachten ist hierbei auch immer das Zeichen, welches die einzelnen Wiederholungen voneinander trennt (in diesem Fall das Komma).

2.0 Einleitung

Gofolio ist ein leistungsfähiger Semi-Compiler (GF.EXE) mit Runtime-Modul (GO.EXE). Die mit GF.EXE compilierten Programme enthalten nur den reinen Objekt-Code, sie können mit GO.EXE gestartet werden. Diese Methode ist gegenüber der Generierung von EXE-Dateien sehr sparsam mit Massenspeicher, da die Laufzeitbibliothek für alle Programme nur einmal in GO.EXE vorliegt.

Gofolio wurde ursprünglich für den Atari-Portfolio entwickelt; Compiler und Runtime-Modul sind daher vom Codeumfang sehr klein gehalten. Gofolio eignet sich daher besonders für alle Dos-Rechner mit kleinem Hauptspeicher bzw. Massenspeicher (Palmtop-/Notebook-Computer).

Zu den meisten heute erhältlichen Compilern gehören riesige Laufzeitbibliotheken, Includedateien, Entwicklungsumgebungen usw., weshalb diese auf diesen kleinen Computern häufig nicht lauffähig sind bzw. zu umständlich zu handhaben sind (abgesehen davon, daß diese Entwicklungssysteme häufig einen 80286 oder 80386 Prozessor voraussetzen). Für denjenigen, der z.B. auf seinem Atari-Portfolio, Hewlet-Packart HP 95LX, SHARP PC-3000 oder PT-30 kleine bis mittlere Programme entwickeln möchte, ohne umständliches Laden bzw. Linken von Bibliotheken, für den ist Gofolio gedacht. Der Sprachumfang von Gofolio wurde bewußt auf das Wesendliche beschränkt. Trotzdem können sie aber mit Gofolio ihren Computer vollständig beherrschen; d.h. auf DOS-Funktionen und Hardware zugreifen. Dies ist wichtig, wenn Sie z.B. Ihren Computer für Steuerungen, Messungen und Regelungen einsetzen. Ein Einsatz auf jeden beliebigen DOS-Rechner ist aber ohne Einschränkung ebenfalls möglich.

2.1 Eigenschaften

Gofolio ist eine eigenständige Programmiersprache. Die Syntax wurde an die Form der Funktionen von Tabellenkalkulations-Arbeitsblättern angelehnt. D.h. alle Befehle und Kontrollstrukturen werden in Form von Funktionen ausgedrückt. Gofolio unterstützt strukturierte Programmierung mit der Möglichkeit zur Definition eigener Funktionen (welche auch rekursiv verwendet werden können), der Bildung von Blöcken sowie der Anwendung von Kontrollstrukturen wie IF…. ELSE ….-Entscheidungen und WHILE-Schleifen. Es stehen die folgenden Datentypen zur Verfügung:

  • Charakter (Zeichen)
  • Byte (Ganzzahlen 0 bis 255)
  • Integer (Ganzzahlen -32768 bis 32767)
  • Real (Fließkommazahlen 3.4E-38 bis 3.4E+38).

Von diesen Typen können jeweils beliebig-dimensionale Arrays (Felder) gebildet werden. Arrays vom Typ Char können als Strings (Zeichenketten) verwendet werden. Weiterhin können über vordefinierte Variablen vom Typ Integer die Prozessorregister geladen und gelesen werden (_AX, _BX, _CX, _DX,_SI, _DI, _FI). Gofolio verwaltet maximal 32000 Byte für Daten.

Gofolio beinhaltet eine Menge Funktionen, welche zum Sprachumfang gehören. U.a. zur formatierten Ein- und Ausgabe von Daten (SCAN, PRINT), zur systemnahen Programmierung (PEEK, POKE, IN, OUT, INTR) sowie mathematische Funktionen (z.B.: SIN, ASIN, COS, ACOS, TAN, ATAN, EXP, LN). Die Ein- und Ausgabefunktionen, Stringverarbeitung sowie die Array-Darstellung arbeiten ähnlich wie die Äquivalente in der Programmiersprache C.

2.2 Compilieren und Ausführen von Programmen

Der Programmquelltext muß als reiner ASCII-Text vorliegen. Zur Erstellung eines Programms kann z.B. der DOS-Editor Edit vewendet werden. Der Progamm-Quelltext wird compiliert, indem die Quelltext-Datei GF.EXE als Kommandozeilenparameter übergeben wird. GF.EXE hat nach erfolgreicher Compilierung eine Datei mit der Erweiterung .GFO erstellt. Die Datei mit der Erweiterung .GFO wird ausgeführt, indem sie GO.EXE als Kommandozeilenparameter übergeben wird. Beispiel:

Ihre Datei mit dem Programmquelltext heißt myprog.txt. Um myprog.txt zu compilieren geben Sie folgendes ein:

gf myprog.txt


GF.EXE hat (wenn kein Fehler aufgetreten ist) die Datei myprog.gfo erzeugt. Um myprog.gfo zu starten geben Sie folgendes ein:

go myprog


Das Editieren, Compilieren und Ausführen kann durch die folgende Batch-Datei automatisiert werden:

@echo off
edit %1
gf %1.txt
if not errorlevel 1 go %1


3.0 Der Aufbau von Gofolio-Programmen

3.1 Beispiel-Programm

Der typische Aufbau eines Gofolio-Programms wird im folgenden anhand eines dokumentierten Beispiels erläutert. Das Programm füllt ein Integer-Array mit Zufallszahlen und sortiert das Array dann aufsteigend. Das Sortieren wird am Bubble-Sort-Algorithmus und am Quick-Sort-Algorithmus demonstriert. Schlüsselworte, welche zur Gofolio-Syntax gehören, sind groß geschrieben.

1:  DEFINT(intfeld[1000],anzahl);
2:
3:  VOIDTYPE #FillFeld(DEFINT(n));
4:  BLOCK(
5:    DEFINT(nr),
6:    nr:=0,
7:    WHILE(nr <= n, BLOCK(
8:      intfeld[nr]:=RND()%100,
9:      INC(nr))
10:   ),
11:   RETURN()
12: );
13:
14: VOIDTYPE #QuickSort(DEFINT(l,r));
15: BLOCK(
16:   DEFINT(i,j,x,w),
17:   i:=l, j:=r,
18:   x:=intfeld[(l+r)/2],
19:   WHILE(i <= j, BLOCK(
20:     WHILE(intfeld[i] < x, INC(i)),
21:     WHILE(x < intfeld[j], DEC(j)),
22:     IF(i <= j, BLOCK(
23:       w:=intfeld[i],
24:       intfeld[i]:=intfeld[j],
25:       intfeld[j]:=w,
26:       INC(i), DEC(j))
27:     ))
28:   ),
29:   IF(l < j, QuickSort(l,j)),
30:   IF(i < r, QuickSort(i,r)),
31:   RETURN()
32: );
33:
34: VOIDTYPE #PrintFeld(DEFINT(n));
35: BLOCK(
36:   DEFINT(nr),
37:   nr:=0,
38:   WHILE(nr <= n, BLOCK(
39:     PRINT("%i ",intfeld[nr]),
40:     INC(nr))
41:   ),
42:   RETURN()
43: );
44:
45: VOIDTYPE #BubbleSort(DEFINT(n));
46: BLOCK(
47:   DEFINT(i,j,x),
48:   i:=1,
49:   WHILE(i <= n, BLOCK(
50:     j:=n,
51:     WHILE(j >= i, BLOCK(
52:       IF(intfeld[j-1] > intfeld[j], BLOCK(
53:         x:=intfeld[j-1],
54:         intfeld[j-1]:=intfeld[j],
56:         intfeld[j]:=x)
57:       ),
58:       DEC(j))
59:     ),
60:     INC(i))
61:   ),
62:   RETURN()
63: );
64:
65: CLS();
66: PRINT("\nBitte Anzahl eingeben: "); scan("%i",anzahl);
67: FillFeld(anzahl);
68: QuickSort(0,anzahl);
69: @ BubbleSort(anzahl);
70: PrintFeld(anzahl).

In Zeile 1 werden die globlalen Variablen deklariert. Die globalen Variablen sind vom Typ Integer und werden mit der Funktion DEFINT(Variable,<Variable>,….) deklariert.
Bei der Variablen intfeld handelt es sich um ein eindimensionales Integer-Array mit 1001 Elementen.
Die Variable anzahl ist eine einfache Integer-Variable.
Die ersten Anweisungen in einem Gofolio-Programm müssen immer die Deklarationen der globalen-Variablen sein. Eine Anweisung wird in Gofolio immer mit einem Semikolon beendet.

In Zeile 3 wird die Funktion FillFeld deklariert. VOIDTYPE gibt den Typ der Funktion an. VOIDTYPE bedeutet, daß die Funktion keinen Rückgabewert liefert (Funktionen können weiterhin vom Typ CHARTYPE, INTTYPE und REALTYPE sein, wobei sie den entsprechenden Daten-Typ zurückliefern). Der Name der Funktion wird in der Deklaration immer mit dem #-Zeichen eingeleitet. Sollen der Funktion Parameter übergeben werden können, so werden in Klammern hinter dem Funktionsnamen Variablen deklariert, welche beim Aufruf der Funktion die Parameter aufnehmen. Der Funktion FillFeld kann somit beim Aufruf ein Parameter vom Typ Integer übergeben werden.
Sollen mehrere Parameter übergeben werden, so muß die Reihenfolge der Übergabe der Deklarations-Reihenfolge entsprechen. Die Funktions-Deklaration (Zeile 3) wird mit einem Semikolon abgeschlossen.

Die Nachfolgende Anweisung stellt den Programm-Code der Funktion FillFeld dar. Wenn der Programm-Code mehrere Anweisungen umfassen soll, so muß er zu einem BLOCK zusammengefaßt werden. Dies geschieht in Zeile 4 durch die Funktion BLOCK(Anweisung, <Anweisung> ,….). Die erste Anweisung, welche zum Anweisungsblock der Funktion FillFeld gehöhrt, ist die Deklaration der lokalen Integer-Variablen nr mittels DEFINT() in Zeile 5.

Die in einem BLOCK befindlichen Anweisungen werden durch Kommata voneinander getrennt. In Zeile 6 wird der lokalen Variablen nr der Wert 0 zugewiesen. Der Doppelpunkt mit dem Gleichheitszeichen := ist hierbei der Zuweisungsoperator.

In Zeile 7 beginnt eine WHILE-Schleife. Die Funktion WHILE enthält eine Bedingung sowie eine Anweisung bzw. mehrere in einem BLOCK zusammengefaßte Anweisungen: WHILE(Bedingung, Anweisung). Die Anweisung wird in einer WHILE-Schleife sooft wiederholt, bis die Bedingung nicht mehr erfüllt ist.

Die Anweisungen in den Zeilen 8 und 9 sind in einen BLOCK zusammengefaßt und werden sooft wiederholt bis nr < = n (Inhalt der Variablen nr kleiner gleich dem Inhalt der Variablen n) ist. Wobei die Variable n der Übergabeparameter an die Funktion FillFeld ist.

In Zeile 8 wird dem Array-Element des Arrays intfeld mit der Nummer entsprechned dem Inhalt der Variablen nr eine Zufallszahl zwischen 0 und 99 zugewiesen. Die Funktion RND() erzeugt Zufallszahlen zwischen 0 und 30000. Das Prozentzeichen (%) ist der Modulo-Operator, liefert also den Ganzzahligen Divisionsrest zurück. Die Modulo-Operation kann nur auf Daten vom Typ Integer angewendet werden.

In Zeile 9 wird der Inhalt der Variablen nr durch die Funktion INC(Variable) um 1 erhöht (incrementiert). Die Variable nr hätte auch durch die Anweisung nr:=nr+1 um 1 erhöht werden können. Die Variante über INC() wird aber wesendlich schneller ausgeführt. Nach dem die Klammer der Funktion INC() geschlossen wurde, wird die Klammer der Funktion BLOCK() geschlossen.

In Zeile 10 wird die Klammer der Funktion WHILE() geschlossen. Da WHILE() eine Anweisung innerhalb des BLOCK´s von Zeile 4 ist, wird die nächste Anweisung in Zeile 11 mit einem Komma getrennt.

In Zeile 11 wird die Funktion FillFeld durch Aufruf der Funktion RETURN() verlassen. Da FillFeld eine VOIDTYPE Funktion ist, also keinen Wert zurückliefert, wird der Funktion RETURN() kein Parameter übergeben. Bei anderen Funktionstypen wird der Rückgabewert über RETURN(Ausdruck) übergeben.

In Zeile 12 wird der Anweisungsblock der Funktion FillFeld geschlossen. Es folgt ein Semikolon, da sämtliche Blöcke verlassen sind.

In Zeile 14 wird die Funktion QuickSort deklariert. Beim Aufruf von QuickSort können 2 Parameter vom Typ Integer übergeben werden, auf welche innerhalb von QickSort über die Varialen l und r zugegriffen werden kann.
In Zeile 22 wird die Funktion IF() verwendet. IF() enthält eine Bedingung und mindestens eine Anweisung: IF(Bedingung, Anweisung). Ist die Bedingung erfüllt so wird die Anweisung ausgeführt, wenn nicht, so wird die Anweisung übersprungen. IF() kann aber auch mit einer Bedingung und 2 Anweisungen aufgerufen werden: IF(Bedingung, Anweisung1, <Anweisung2>). Wenn in diesem Fall die Bedingung erfüllt ist, so wird Anweisung1 ausgeführt, und wenn die Bedingung nicht erfüllt ist, wird Anweisung2 ausgeführt.

QuickSort ist eine rukursive Funktion, dies zeigen die Zeilen 29 und 30, in denen sich QuickSort selbst aufruft.

In Zeile 34 wird die Funktion PrintFeld deklariert. PrintFeld enthält in der Zeile 39 die Funktion PRINT(). PRINT() wird verwendet, um Daten auf dem Bildschirm, auf dem Drucker oder in eine Datei auszugeben. In Zeile 39 soll eine Ausgabe auf dem Bildschirm erfolgen. PRINT() hat die folgende Aufrufsyntax: PRINT(<Ausgabeeinheit>, String, <Ausdruck>). Wenn keine Ausgabeeinheit angegeben ist (wie in Zeile 39), erfolgt die Ausgabe auf dem Bildschirm. Der String kann eine Text enthalten, welcher einen Platzhalter enthält, der angibt, wo der Ausdruck innerhalb des Textes auf dem Bildschirm erscheinen soll. Der Platzhalter besteht aus dem Prozentzeichen und einem Buchstaben, welcher den Typ des Ausdrucks angibt, der ausgegeben werden soll. In Zeile 39 befindet sich ein i hinter dem Prozentzeichen, d.h. der Ausdruck (die Variable intfeld[nr]) wird nach dem Format integer ausgegeben. Die Funktion PRINT() wird später noch eingehender beschrieben.

In Zeile 65 wird die Funktion CLS() aufgerufen. CLS() bewirkt ein Löschen des Bildschirmes.

Zeile 66 einthält die Funktion SCAN(). SCAN() ermöglicht ein Einlesen von Daten von der Tastatur oder aus einer Datei in eine Variable. Es gilt die folgende Aufrufsyntax: SCAN(<Eingabeeinheit>, String, Variable). Wenn keine Eingabeeinheit angegeben ist, wird von der Tastatur eingelesen (wie in Zeile 66). Der String enthält analog zur Funktion PRINT() einen Platzhalter, welcher angibt, nach welchem Format eingelesen werden soll. In Zeile 66 wird ein Datum nach dem Format integer von der Tastatur eingelesen und der Variable anzahl zugewiesen.

In Zeile 67 wird die oben definierte Funktion FillFeld() aufgerufen, und hierbei der Inhalt der Variablen anzahl als Parameter übergeben.

In Zeile 68 wird die oben definierte Funktion QuickSort() aufgerufen, und es werden zwei Parameter übergeben.

Zeile 69 wird vom Compiler ignoriert, da sie mit dem @-Zeichen beginnt. Stößt der Compiler auf das @-Zeichen so wird der folgende Programmtext bis zum Zeilenende überlesen. Diese Methode bietet also die Möglichkeit Kommentare in den Programmtext einzufügen.

Zeile 70 endet mit einem Punkt. Gofolio-Programme enden immer mit einem Punkt.

Wenn Sie die Geschwindigkeit der Sortierfunktionen QuickSort() und BubbleSort() vergleichen wollen, so stellen Sie Zeile 69 wieder her und machen Zeile 68 zur Kommentarzeile.

3.2 Bezeichner in Gofolio

Gofolio unterscheidet nicht zwischen Groß- und Kleinschreibung. Es bleibt also Ihnen überlassen, ob Sie Ihre Variablen-Bezeichner, Funktions-Bezeichner oder die Gofolio-Funktionen groß bzw. klein schreiben. Leerzeichen werden vom Compiler grundsätzlich überlesen. Variablen- und Funktions-Bezeichner dürfen aus den folgenden Buchstaben und Zahlen bestehen: a-z und 0-9. Wobei die Bezeichner allerdings nicht mit einer Zahl beginnen dürfen. Ein Bezeichner darf aus maximal 20 Zeichen bestehen.

3.2.1 Preprocessor-Anweisungen

Eine besondere Art von Bezeichnern sind die sog. Preprocessoranweisungen. Dies sind konstante Bezeichner, die am Beginn des Programmtextes stehen und durch das „&“ Zeichen deklariert werden. Sie haben somit die Möglichkeit Konstante zu deklarieren.
Schreiben Sie z.B. in die erste Zeile ihres Programmtextes

&Pi=3.14;

so ist im folgenden Quelltext der Bezeicher &Pi immer gleichbedeutend mit 3.14. Bitte beachten Sie,

  • dass Preprocessoranweisungen immer vor dem eigentlichen GoFolio-Programm stehen müssen;
  • dass eine Preprocessoranweisung mit einem Semikolon endet;
  • dass der Preprocessor im Prinzip nur Textersetzungen im Programmquelltext vornimmt. Daher findet keine Typüberprüfung statt;
  • das Beispielprogramm pre.txt zur weiteren Erläuterung.

Beispiel:

&Pi=3.14;
&rMax=10;
 
defreal(r[&rMax]);
defint(n);
 
n:=0;
while(n < &rMax, block(
  r[n]:=&Pi*real(n),
  inc(n))
);
n:=0;
while(n < &rMax, block(
  print("%f\n",r[n]),
  inc(n))
).

3.3 Variablen

Zum Erzeugen von Variablen bietet Gofolio die folgenden Funktionen:

  • DEFBYTE(Bezeichner, <Bezeichner>,….), erzeugt Variablen vom Typ Byte, welcher Zahlen von 0..255 aufnehmen kann.
  • DEFCHAR(Bezeichner, <Bezeichner>,….), erzeugt Variablen vom Typ Character, welcher Zeichen aufnimmt (ASCII-Codes).
  • DEFINT(Bezeichner, <Bezeichner>,….), erzeugt Variablen vom Typ Integer, welcher Zahlen von -32768..32767 aufnehmen kann.
  • DEFREAL(Bezeichner, <Bezeichner>,….), erzeugt Variablen vom Typ Real, welcher Zahlen von 3.4E-38..3.4E+38 (Fließkommazahlen) aufnehmen kann.


Gofolio besitzt eine strenge Typen-Überprüfung. Wollen Sie einer Variablen den Wert einer anderen zuweisen, wobei die andere Variable einen unterschiedlichen Typ hat, so muß dieser Typ in den Typ der Ziel-Variablen gewandelt werden. Andernfalls erhalten Sie einen Syntaxfehler. Lediglich Variablen vom Typ Byte und Integer sind zuweisungskompatibel. Wollen Sie z.B. den Wert der Real-Variable r der Integer-Variablen i zuweisen, so gilt:

i:=INT(r)


Um Typenwandlungen vorzunehmen, bietet Gofolio die folgenden Funktionen:

  • CHAR(Bezeichner) wandelt in den Typ Charakter,
  • INT(Bezeichner) wandelt in den Typ Integer und Byte,
  • REAL(Bezeichner) wandelt in den Typ Real.


3.4 Darstellung von Zahlenkonstanten

Zahlenkonstanten können in Gofolio in dezimaler und hexadezimaler Schreibweise dargestellt werden. Variablen vom Typ Real können nur Zahlen zugewiesen werden, welche dezimal mit Dezimalpunkt angegeben sind. Variablen vom Typ Integer und Byte können Zahlen in dezimaler Darstellung (ohne Dezimalpunkt !) sowie in hexadezimaler Darstellung zugewiesen werden.

Hexadezimale Konstanten beginnen immer mit den Zeichen 0x, worauf die Hex-Ziffern folgen (analog zur Programmiersprache C).

Beispiel:

DEFINT(i,n);
DEFREAL(r);
i:=0xEF11;
n:=100;
r:=100.0;
print("i=%i\n",i);
print("n=%i\n",n);
print("r=%f\n",r).


3.5 Arrays

In Gofolio können Array-Variablen von beliebiger Dimension erzeugt werden. Deklariert werden Array-Variablen mit den Gofolio-Funktionen DEFINT(), DEFCHAR(), DEFBYTE() und DEFREAL(). Wollen Sie ein eindimensionales Integer-Array mit 10 Elementen erzeugen, so geben Sie DEFINT(i[9]) ein. Hinter dem Variablen-Bezeichner schließt für jede Dimension ein Paar eckiger Klammern eine Zahl ein, welche die Anzahl der Elemente für die entsprechende Dimension minus 1 angibt. Anzahl-1 deshalb, weil das erste Element den Index 0 hat. Das letzte Element hat einen Index entsprechend der angegebenen Zahl.
Ein 3-dimensionales Real-Array mit jeweils 20 Elementen pro Dimension, wird wie folgt deklariert:

DEFREAL(raum[19][19][19])


3.6 Strings

Strings (Zeichenketten) werden in Gofolio als Arrays vom Typ Charakter aufgefaßt. Die Behandlung von Strings erfolgt ähnlich wie in der Programmiersprache C; d.h. das letzte Element eines Strings muß immer den Wert 0 (binäre Null) besitzen. Gofolio-Funktionen wie PRINT() oder STRCPY() erkennen so das Ende der Zeichenkette. Das folgende kleine Programm erzeugt einen String und gibt ihn auf dem Bildschirm aus:

DEFCHAR(str[20]);
STRCPY(ADDR(str),"Hallo Welt");
PRINT("%s\n",ADDR(str)).


Die Gofolio-Funktion:

STRCPY(Adresse-Zielstring, Adresse-Quellstring oder String-Const)


kopiert die String-Constante an die Startadresse von str. Um die Adresse einer Variablen zu ermitteln, steht die Gofolio-Funktion ADDR(Variable) zur Verfügung. ADDR() gibt einen Integer-Wert zurück (welcher den Offset der Variablen im Datensegment darstellt). ADDR(str) ist mit ADDR(str[0]) identisch. Soll das Wort „Welt“ in dem String durch das Wort „Hans“ überschrieben werden, so kann dies durch STRCPY(addr(str[6]),„Hans“) geschehen.
Die Gofolio-Funktion PRINT() erwartet, um einen String auszugeben, immer die Adresse des Strings. Von dieser Adresse an werden dann solange Zeichen ausgegeben, bis PRINT() auf eine binäre Null stößt. Soll aus obigem String z.B. nur „Hallo“ ausgegeben werden so müßte hinter „Hallo“ eine binäre Null folgen: str[5]:=CHAR(0). Damit z.B. das 5.Zeichen in dem String kein ´o´sondern ein ´i´ enthält, geben Sie folgendes ein: str[4]:=´i´.
Zeichenketten werden also immer zwischen „“ und einzelne Buchstaben zwischen ´´ angegeben. Steuerzeichen werden in einem String durch den Gegenstrich (\) eingeleitet. Folgt in einem String dem Gegenstrich z.B. ein n (\n), so entspricht dies dem ASCII-Code 10, d.h. es erfolgt ein Zeilenvorschub. Gofolio unterstützt die folgen Zeichen zur Angabe von Steuerzeichen:

\n  Zeilenvorschub
\r  Wagenrücklauf
\t  Tabulator
\f  Seitenvorschub
\v  Vertikaltabulator.


Ferner kann, wenn hinter dem Gegenstrich ein x folgt, der ASCII-Code in hexadezimaler Form direkt eingegeben werden.

Beispiel:

DEFCHAR(st1[10], st2[10]);
STRCPY(ADDR(st1), "1234\n");
STRCPY(ADDR(st2), "\x31\x32\x33\x34\x0a");
PRINT("%s",ADDR(st1));
PRINT("%s",ADDR(st2))


Das Einlesen einer Zeichenkette von der Tastatur wird mit der Gofolio-Funktion SCAN() durchgeführt. SCAN(„%s“,str) bewirkt, daß str vom Element mit dem Index 0 an mit Zeichen von der Tastatur gefüllt wird. SCAN(„%s“,str[5]) bewirkt, daß str vom Element mit dem Index 5 an mit Zeichen von der Tastatur gefüllt wird. Im Gegensatz zur Funktion PRINT() benötigt SCAN() nicht die Adresse des Strings, sondern die Variable wird direkt angegeben.

3.7 Dateien

Die Bearbeitung von Dateien unterstützt Gofolio mit den folgenden Funktionen:

  • OPENIN(String), diese Funktion öffnet eine Datei, deren Name als Argument (in Form einer Zeichenkette) übergeben wird. Aus einer mit OPENIN() geöffneten Datei kann nur gelesen werden. Tritt beim Öffnen der Datei ein Fehler auf, so gibt OPENIN() den Wert 1 zurück. Tritt kein Fehler auf, so wird der Wert 0 zurückgegeben (jeweils als Typ Integer).
  • OPENOUT(String), diese Funktion öffnet eine Datei, deren Name als Argument (in Form einer Zeichenkette) übergeben wird. In eine mit OPENOUT() geöffneten Datei kann nur geschrieben werden. Tritt beim Öffnen der Datei ein Fehler auf, so gibt OPENOUT() den Wert 1 zurück. Tritt kein Fehler auf so wird der Wert 0 zurückgegeben (jeweils vom Typ Integer).
  • CLOSEIN(), diese Funktion schließt eine mit OPENIN() geöffnete Datei.
  • CLOSEOUT(), diese Funktion schließt eine mit OPENOUT() geöffnete Datei.
  • EOF(), diese Funktion gibt den Integer-Wert 1 zurück, wenn das Ende der Datei, aus der gerade gelesen wird, erreicht ist. Ist das Datei-Ende noch nicht erreicht gibt EOF() den Wert 0 zurück.


Geschrieben und gelesen wird in bzw. aus Dateien mit den Funktionen PRINT() bzw. SCAN(), wobei als Aus-/Eingabeeinheit FILE angegeben wird.
In dem folgenden Beispiel werden die beiden Worte „Hallo Welt“ in die Datei d1.txt geschrieben und anschließend wieder aus der Datei gelesen und auf dem Bildschirm ausgegeben.

DEFCHAR(str[10]);
IF(OPENOUT("d1.txt"), BLOCK(
  PRINT("Fehler beim Öffnen der Datei"),
  HALT())
);
PRINT(FILE,"Hallo\n");
PRINT(FILE,"Welt\n");
CLOSEOUT();
IF(OPENIN("d1.txt"), BLOCK(
  PRINT("Fehler beim Öffnen der Datei"),
  HALT())
);
SCAN(FILE,"%s",str);
PRINT("%s\n",ADDR(str));
SCAN(FILE,"%s",str);
PRINT("%s\n",ADDR(str));
CLOSEOUT().

Anstatt Zeichen und Zeichenketten können natürlich auch Zahlen vom Typ Integer, Byte und Real in Dateien geschrieben bzw. aus Dateien gelesen werden.

3.8 Funktionen

3.8.1 Die Deklaration von Funktionen

Die Deklaration von Funktionen in Gofolio muß immer direkt der Deklaration der globalen Programm-Variablen (wenn denn welche deklariert wurden) folgen. Funktionen können die folgenden Rückgabe-Typen haben:

  • CHARTYPE #Funktions-Bezeichner (Charakter),
  • INTTYPE #Funktions-Bezechner (Integer und Byte),
  • REALTYPE #Funktions-Bezeichner (Real),
  • VOIDTYPE #Funktion-Bezeichner (Kein Rückgabewert).


Beispielprogamm mit Funktionsdeklaration:

DEFCHAR(str[20]);
 
INTTYPE #Pos(DEFCHAR(ch));
BLOCK(
   DEFINT(n),
   n:=0,
   WHILE(str[n] <> ch, INC(n)),
   RETURN(n)
);
 
STRCPY(ADDR(str),"Dies ist ein Test");
PRINT("Position=%i\n",Pos(´T´)).


In Zeile 3 des Programms wird die Funktion Pos() deklariert. Pos() liefert einen Rückgabewert vom Typ Interger. Die Funktionsdeklaration wird deshalb mit dem Gofolio-Bezeichner INTTYPE eingeleitet. In der Deklarationsphase folgt jetzt das #-Zeichen, welches die Deklaration des Funktionsnamen einleitet. Zwischen den Klammern hinter dem Funktionsnamen werden die Variablen für eventuelle Funktionsparameter deklariert. Im obigen Fall ist es die Variable mit dem Namen ch, und sie ist vom Typ Charakter. Die Zeilen 4-9 enthalten den Progamm-Code der Funktion Pos(). Dieser kann - wie im vorliegenden Fall - zu einem Block zusammengefaßt sein. Er kann aber auch nur aus einer einzelnen Anweisung bestehen - der Gofolio-Funktion RETURN().
Funktionen müssen immer mit RETURN() beendet werden. RETURN() wird verwendet, um eine Funktion zu verlassen sowie um einen Rückgabewert zurückzugeben. Auch VOIDTYPE-Funktionen müssen mit RETURN() verlassen bzw. beendet werden. Allerdings ohne Rückgabewert, welcher ansonsten zwischen den Klammern steht. Folgende Funktions-Deklaration ist daher auch möglich:

  REALTYPE #Quadrat(defreal(x));
  RETURN(x*x);
 
  PRINT("%f\n",Quadrat(1.234))


Eine Funktion kann wiederum eine andere Funktion aufrufen, wenn diese vor der rufenden Funktion deklariert wurde. Wie an dem kommentierten Programmbeispiel gezeigt, kann eine Funktion sich auch selbst aufrufen (Rekursion). In Gofolio ist es nicht möglich innerhalb einer Funktion weitere Funktionen - also funktionslokale Funktionen - zu deklarieren.
Beispiel zum Thema Funktion ruft Funktion:

  REALTYPE #HochZwei(DEFREAL(x));
  RETURN(x*x);
 
  REALTYPE #HochVier(DEFREAL(x));
  RETURN(HochZwei(x)*HochZwei(x));
 
  PRINT("%f\n",HochVier(1.234))


3.8.2 Parameterübergabe

Den Funktionen können beliebig viele Parameter (Argumente) übergeben werden. Hierzu werden - wie oben schon gezeigt - zwischen den Klammern hinter dem Funktionsbezeichner Variablen deklariert, über die auf die Übergabeparameter zugegriffen werden kann. Diese Variablen werden als formale Parameter bezeichnet. Die formalen Parameter können vom Typ Charakter, Byte, Integer sowie Real sein.
Bei den Typen Integer und Byte ist es bezüglich der Parameterübergabe egal welchen Sie verwenden. Die Verwendung von Byte ist hier nicht sparsamer. Ich empfehle für den Fall der Formalparameter-Deklaration eine Beschränkung auf die Typen Charakter, Integer und Real. Die Parameter-übergabe erfolgt immer als Wertübergabe. D.h. wird beim Funktionsaufruf als Parameter eine Variable aus dem rufenden Progammteil übergeben, so wird deren Inhalt nicht durch die aufgerufene Funktion verändert. Die Positionen der Übergabeparameter beim Aufruf der Funktion müssen immer mit denen der formalen Parameter exakt übereinstimmen. Übergeben werden die Parameter jeweils getrennt durch ein Komma.

Beispiel:

  VOIDTYPE #Test(DEFINT(i1,i2),DEFCHAR(ch),DEFREAL(r1,r2));
  BLOCK(
    PRINT("i1=%i\n",i1),
    PRINT("i2=%i\n",i2),
    PRINT("r1=%f\n",r1),
    PRINT("r2=%f\n",r2),
    PRINT("ch=%c\n",ch),
    RETURN()
  );
 
  Test(123,234,´w´,3.14,0.0034)


Der Compiler überprüft hierbei nicht, ob Sie beim Aufruf der Funktion die Parameter bezüglich Anzahl und Position korrekt übergeben haben. Sollte dies nicht der Fall sein, so stürzt Ihr Programm mit Sicherheit ab.

3.8.3 Lokale Variablen

Innnerhalb von Funktionen können Variablen deklariert werden. Die Deklarationen dieser lokalen Variablen müssen die ersten Anweisungen in einer Funktion sein. Die so erzeugten Variablen haben nur Gültigkeit innerhalb der Funktion, in welcher sie deklariert wurden. Es kann also weder vom Hauptprogramm noch von einer evt. rufenden Funktion auf sie zugegriffen werden. Die Namen der lokalen Variablen können identisch mit globalen Variablen aus dem Hauptprogramm sein. Ein Zugriff auf eine solche Variable innerhalb einer Funktion bezieht sich dann immer auf die lokale Variable. Grundsätzlich kann aber von Funktionen aus auf jede globale Programm-Variable zugegriffen werden (wenn sie nicht den selben Namen wie eine lokale Variable trägt).
Ruft eine Funktion eine andere Funktion, so kann die gerufene Funktion nicht auf die lokalen Variablen der rufenden Funktion zugreifen. Ferner ist zu beachten, daß ein Name einer lokalen Variablen nicht identisch sein darf mit einem Namen eines formalen Parameters der entsprechenden Funktion. Denn die formalen Parameter sind praktisch ebenfalls lokale Variablen.

3.9 Zusammenfassung zum Aufbau von Gofolio-Programmen

Beim Aufbau eines Gofolio-Programms muß also die folgende Reihenfolge beachtet werden:

  1. <Deklaration der Preprocessoranweisung;….>
  2. <Deklaration der globalen Variablen;….>
  3. <Deklaration der Funktionen;….>
  4. <Deklaration der formalen Parameter,….>
    1. <Deklaration der lokalen Variablen,….>
    2. <Anweisungen,….>
    3. RETURN(<Ausdruck>)
  5. <Anweisungen;….>
  6. Letzte Anweisung.


4.0 Operatoren in Gofolio

4.1 Additive Opreatoren

  • Additions-Operator +

Dieser Operator kann auf die Typen Byte, Integer und Real angewendet werden. Die Operanden werden addiert. Z.B.: PRINT(„%i\n“,1+1).

  • Subtraktions-Operator -

Dieser Operator kann auf die Typen Byte, Integer und Real angewendet werden. Vom linken Operand wird der rechte subtrahiert.

Z.B.: PRINT(„%i\n“,2-1).

4.2 Multiplikative Operatoren

  • Multiplikations-Operator *

Dieser Operator kann auf die Typen Byte, Integer und Real angewendet werden. Die Operanden werden multipliziert. Z.B.: PRINT(„%i\n“,2*2).

  • Divisions-Operator /

Dieser Operator kann auf die Typen Byte, Integer und Real angewendet werden. Der linke Operand wird durch den rechten dividiert.
Z.B.: PRINT(„%i\n“,6/3).

  • Modulo-Operator %

Dieser Operator kann nur auf die Typen Byte und Integer angewendet werden. Modulo (Divisionsrest wird gebildet) Z.B.: PRINT(„%i\n“,10%3).

  • Operator zum Potenzieren ^

Dieser Operator kann nur auf den Typ Real angewendet werden. Der linke Operand entspricht der Basis, und der rechte dem Exponenten.
Z.B.: PRINT(„%f\n“,2.0^0.5).

4.3 Relationale Operatoren

  • Vergleichs-Operator Gleich =

Kann auf alle Typen angewendet werden. Bildet mit einem linken und einem rechten Operanden (müssen vom gleichen Typ sein) eine Bedingung, welche wahr ist, wenn diese gleich sind.
Z.B.: IF(3 = 4, PRINT(„wahr“), PRINT(„falsch“)).

  • Vergleichs-Operator Größer-Gleich >=

Kann auf alle Typen angewendet werden. Bildet mit einem linken und einem rechten Operanden (müssen vom gleichen Typ sein) eine Bedingung, welche wahr ist, wenn der linke größer-gleich dem rechten ist. Z.B.: IF(3 >= 4, PRINT(„wahr“), PRINT(„falsch“)).

  • Vergleichs-Operator Kleiner-Gleich < =

Kann auf alle Typen angewendet werden. Bildet mit einem linken und einem rechten Operanden (müssen vom gleichen Typ sein) eine Bedingung, welche wahr ist, wenn der linke kleiner-gleich dem rechten ist. Z.B.: IF(3 < = 4, PRINT(„wahr“), PRINT(„falsch“)).

  • Vergleichs-Operator Größer >

Kann auf alle Typen angewendet werden. Bildet mit einem linken und einem rechten Operanden (müssen vom gleichen Typ sein) eine Bedingung, welche wahr ist, wenn der linke größer dem rechten ist. Z.B.: IF(3 > 4, PRINT(„wahr“), PRINT(„falsch“)).

  • Vergleichs-Operator Kleiner <

Kann auf alle Typen angewendet werden. Bildet mit einem linken und einem rechten Operanden (müssen vom gleichen Typ sein) eine Bedingung, welche wahr ist, wenn der linke kleiner dem rechten ist. Z.B.: IF(3 < 4, PRINT(„wahr“), PRINT(„falsch“)).

  • Vergleichs-Operator Ungleich <>

Kann auf alle Typen angewendet werden. Bildet mit einem linken und einem rechten Operanden (müssen vom gleichen Typ sein) eine Bedingung, welche wahr ist, wenn diese ungleich sind.
Z.B.: IF(3 <> 4, PRINT(„wahr“), PRINT(„falsch“)).

Eine Bedingung gibt für den Fall, daß sie wahr ist, den Wert 1 zurück. Für den Fall, daß die Bedingung nicht wahr ist, wird 0 zurückgegeben. Es ist daher möglich das Ergebnis einer Bedingung einer Variablen zuzuweisen. Der Rückgabewert ist immer vom Typ Integer.

Beispiel:

DEFINT(bool);
bool:=(10.1 > 10.0);
PRINT("%i\n",bool).

4.4 Der Zuweisungs-Operator :=

Der Zuweisungsoperator kann auf alle Typen angewendet werden. Dem linken Operanden wird der rechte zugewiesen. Beide Operanden müssen vom gleichen Typ sein. Bei dem linken Operanden muß es sich um eine Variable handeln. Der rechte Operand kann eine Variable oder ein Ausdruck sein.

Z.B.:

DEFCHAR(ch);
DEFINT(i,a);
DEFREAL(r);
 
ch:=´k´;
i:=135;
r:=(0.199)^2.0;
a:=i;
a:=i+1;
i:=INT(ch)-10;
a:=INT(r);
r:=REAL(ch).

5.0 Beschreibung der Gofolio-Funktionen in alphabetischer Reihenfolge

In diesem Abschnitt werden sämtliche Gofolio-Funktionen nach folgendem Schema beschrieben:

  • Rückgabetyp FUNKTIONSNAME(Prametertyp, Parametertyp, ….).
    Der Typ Void bedeutet hierbei, daß kein Wert zurückgegeben wird bzw., daß keine Parameter übergeben werden.


  • Real ABS(Real),
    gibt den Absolutbetrag des Arguments zurück. Z.B.:
PRINT("%f\n",ABS(-1.23))


  • Real ACOS(Real),
    gibt den Arcuscosinus (in Rad) des Arguments zurück. Z.B.:
PRINT("%f\n,ACOS(3.14))


  • Integer ADDR(Variable),
    gibt die Offset-Addresse einer Variablen (von beliebigem Typ) im Datensegment zurück.


  • Integer AND(Bedingung, <Bedingung>, <Bedingung>, ….),
    führt einen logischen Und-Vergleich der einzelnen Bedingungen durch. Gibt den Wert wahr (1) zurück, wenn alle Bedingungen wahr sind. Ist eine Bedingung falsch, so wird der Wert falsch (0) zurückgegeben. Z.B.:
IF(AND(1 >= 0, 2 = 2), PRINT("wahr"), PRINT("falsch"))


  • Integer ANDB(Integer, Integer),
    liefert das Ergebnis des bitweisen Und-Vergleiches der beiden Übergabeparameter zurück. Z.B.:
 PRINT("%i\n",ANDB(2,18))


  • Real ASIN(Real),
    gibt den Arcussinus (in Rad) des Arguments zurück. Z.B.:
PRINT("%f\n",ASIN(1.552))


  • Real ATAN(Real),
    gibt den Arcustangens (in Rad) des Arguments zurück. Z.B.:
PRINT("%f\n",ATAN(1.23))


  • Void BLOCK(Anweisung, <Anweisung>, <Anweisung>, ….),
    faßt beliebig viele Anweisungen zu einem Block zusammen. Mit anderen Worten: es werden beliebig viele Anweisungen zu einer Anweisung zusammengefaßt. Es ist zu beachten, daß ausserhalb eines Blockes die einzelnen Anweisungen durch Strichpunkte (Semikolon) voneinander getrennt werden.
    Innerhalb eines Blockes werden die Anweisungen dagegen durch Kommata getrennt. Z.B.:


  DEFINT(i);
  i:=0;
  WHILE(i < 100, BLOCK(
     PRINT("%i\n"),
     i:=i+1)
  )


Sie können die Syntax von GoFolio vereinfachen, wenn Sie das gesamte Programm als BLOCK auffassen. Die einzelnen Anweisungen werden dann nur durch Kommata getrennt. Obige Programmzeilen würden sich in die folgenden ändern (evt. Funktionsdeklarationen müssen sich allerdings vor dem BLOCK befinden):


BLOCK(
  DEFINT(i),
  i:=0,
  WHILE(i < 100, BLOCK(
    PRINT("%i\n"),
    i:=i+1)
)


  • Charakter CHAR(alle Typen),
    wandelt den übergebenen Typ in einen Wert vom Typ Charakter.


  • Void CLOSEIN(Void),
    schließt die Datei, aus welcher gelesen wurde.


  • Void CLOSEOUT(Void),
    schließt die Datei, in welche geschrieben wurde.


  • Void CLS(Void),
    löscht den Bildschirm.


  • Real COS(Real),
    gibt den Cosinus des Argments (in Rad) zurück.


  • Void DEC(Integer Varable),
    erniedrigt (decrementiert) den Inhalt der übergebenen Integer-Variablen um 1. Diese Verfahren erfolgt wesendlich effizenter als z.B.: n:=n-1.


  • Void DEFBYTE(Bezeichner, <Bezeichner>, <Bezeichner>, ….),
    deklariert die übergebenen Bezeichner als Variablen vom Typ Byte.


  • Void DEFCAHR(Bezeichner, <Bezeichner>, <Bezeichner>, ….),
    deklariert die übergebenen Bezeichner als Variablen vom Typ Charakter.


  • Void DEFINT(Bezeichner, <Bezeichner>, <Bezeichner>, ….),
    deklariert die übergebenen Bezeichner als Variablen vom Typ Integer.


  • Void DEFREAL(Bezeichner, <Bezeichner>, <Bezeichner>, ….),
    deklariert die übergebenen Bezeichner als Variablen vom Typ Real.


  • Integer DS(Void),
    gibt die Segmentadresse des Datensegments zurück. Soll z.B. mit den Funktionen PEEK() oder POKE() auf eine Variable zugegriffen werden, so wird die Adresse des Datensegments in denen sich die Variablen befinden benötigt. Z.B.:


  DEFINT(i);
  i:=10000;
  PRINT("Low-Byte  %i\n", PEEK(DS(),ADDR(i));
  PRINT("High-Byte %i\n", PEEK(DS(),ADDR(i)+1)


  • Void ELSE(Anweisung, <Anweisung>, <Anweisung>, ….),
    hat die gleiche Wirkung wie die Gofolio-Funktion BLOCK(). Es erhöht aber die Lesbarkeit Ihres Programmtextes, wenn die Anweisungen des Else-Zweiges der Gofolio IF() Funktion anstatt mit BLOCK() mit ELSE() zusammengefaßt werden. Z.B.:


    IF(x < y, BLOCK(
      print("x ist kleiner y"),
      y:=y-1),
    ELSE(
      print("x ist größer gleich y"),  
      x:=x-1
    );


  • Integer EOF(Void),
    gibt 1 zurück, wenn das Ende einer Datei, aus welcher gelesen wird, erreicht ist.


  • Real EXP(Real),
    Berechnet die Exponentialfunktion e^x.


  • Void GOTOXY(Integer, Integer),
    positioniert den Textcursor entsprechend der beiden übergebenen Integer-Werte, wobei der erste Wert die x-Position angibt, und der zweite die y-Position.


  • Void HALT(Void),
    wird diese Funktion aufgerufen, so wird das Programm beendet.


  • Void IF(Bedingung, Anweisung1, <Anweisung2>),
    führt eine Verzweigung in Abhängigkeit der Bedingung durch. Ist die Bedingung wahr (1), so wird Anweisung1 ausgeführt. Ist die Bedingung falsch (0), so wird - wenn vorhanden - Anweisung2 ausgeführt. Ist keine Anweisung2 vorhanden, so wird der Programmlauf mit der nächsten Anweisung nach der IF()-Funktion weitergeführt.


  • Byte IN(Integer),
    list ein Byte aus einer I/O-Adresse, welche durch das Argument angegeben wird, und gibt den Inhalt des Bytes zurück.


  • Void INC(Integer),
    erhöht den Inhalt der übergebenen Integer-Variablen un 1. Dieses Verfahren ist wesendlich effizenter als z.B.: n:=n+1.


  • Integer INT(alle Typen),
    wandelt den übergenbenen Typ in einen Wert vom Typ Integer.


  • Void INTR(Integer),
    führt einen allgemeinen 8086-Software-Interrupt aus. Als Argument wird die Nummer des Interrupt-Vektors übergeben. Die Prozessorregister können hierbei über die folgenden in Gofolio vordefinierten Variablen beschrieben und gelesen werden:
    _AX, _BX, _CX, _DX, _SI, _DI, _FL.
    Das folgende Programm-Beispiel ermittelt über den Interrupt 0x21 und dessen Funktion 0x2a den Monat (1 bis 12) sowie den Tag des Monats (1 bis 31):


_AX:=256*0x2a;
INTR(0x21);
PRINT("Tag=  %i\n",ANDB(_DX,0x00ff));
PRINT("Monat=%i\n",ANDB(_DX,0xff00)/256)


Hier noch ein paar Erläuterungen zum Umgang mit den Prozessorregistern unter GoFolio:
Die Register AX, BX usw. sind 16 Bit breit. Sie werden prozessorintern aber noch unterteilt in ein High-Byte (8-Bit) und ein Low-Byte (ebenfalls 8-Bit).
Viele Programmiersprachen erlauben es z.B. das Register AX auf drei Arten anzusprechen:

  • einmal als 16-Bit-Register z.B. mit AX:=0x2eff
  • einmal die unteren 8 Bit von AX z.B. mit AL:=0xff
  • einmal die oberen 8 Bit von AX z.B. mit AH:=0x2e


Aus Performence-Gründen gibt es unter Gofolio die Register AL, AH, BL, BH usw. nicht. Sondern sie müssen mit folgendem Trick angesprochen werden (das Beispiel betrifft wieder das AX-Register, gleiches gilt aber für alle weiteren Register):

  • beschreiben der unteren 8-Bit von AX: _AX:=0xff (entspr. AL:=0xff)
  • beschreiben der oberen 8-Bit von AX: _AX:=0x2e*256 (entspr. AH:=0x2e)
  • lesen der unteren 8-Bit von AX: bit:=andb(_AX,0x00ff) (entspr. bit:=AL)
  • lesen der oberen 8-Bit von AX: bit:=andb(_AX,0xff00)/256 (entspr. bit:=AH)


  • Integer KEY(Void),
    gibt den ASCII-Wert einer gedrückten Taste zurück. Wird keine Taste gedrückt, so wird 0 zurückgegeben.


  • Real LN(Real),
    gibt den natürlichen Logarithmus des Arguments zurück.


  • Integer NOT(Bedingung),
    führt eine logische Verneinung der Bedingung durch. Wenn die Bedingung wahr (1) ist, so wird falsch (0) zurückgegeben. Ist die Bedingung falsch (0) so wird wahr (1) zurückgegeben.


  • Integer OPENIN(String),
    als Argument wird ein Dateiname übergeben. Die betreffende Datei wird zum Lesen geöffnet. Sollte beim Öffnen ein Fehler auftreten (z.B. dadurch, daß die Datei nicht existiert), so wird der Wert 1 zurückgegeben. Im Falle einer fehlerfreien Öffnung der Datei wird der Wert 0 zurückgegeben.


  • Integer OPENOUT(String),
    als Argument wird ein Dateiname übergeben. Die betreffende Datei wird zum Schreiben geöffnet. Sollte beim Öffnen ein Fehler auftreten, so wird der Wert 1 zurückgeben. Im Falle einer fehlerfreien Öffnung der Datei wird der Wert 0 zurückgegeben.


  • Integer OR(Bedingung, <Bedingung>, <Bedingung>, ….),
    führt einen logischen Oder-Vergleich der einzelnen Bedingungen durch. Ist mindestens eine Bedingung wahr (1), so wird wahr (1) zurückgegeben. Sind alle Bedingungen falsch (0), so wird falsch (0) zurückgegeben.


  • Integer ORB(Integer, Integer),
    liefert den bitweisen Oder-Vergleich der beiden Argumente zurück.


  • Void OUT(Integer, Byte),
    schreibt ein Byte an eine I/O-Adresse, wobei das erste Argument die Adresse angibt, und das zweite Argument den Wert welcher geschrieben werden soll.


  • Byte PEEK(Integer, Integer),
    gibt den Wert des Bytes, welches durch eine Segmentadresse (erstes Argument) und eine Offsetadresse (zweites Argument) spezifiziert ist, zurück.


  • Void POKE(Integer, Interger, Byte),
    schreibt ein Byte (drittes Argument) an die mit Offset (zweites Argument) und Segment (erstes Argument) angegebene Adresse.


  • Void PRINT(<Ausgabeeinheit>, String-Const, <Ausdruck>),
    gibt zur Ausgabeinheit entsprechend dem in der String-Const angegebenen Format das Ergebnis des Ausdrucks aus. Wird keine Ausgabeeinheit angegeben, so erfolgt die Ausgabe auf dem Bildschirm. Wird der Gofolio-Bezeichner FILE als Ausgabeeinheit angegeben, so erfolgt die Ausgabe in eine zuvor mit der Gofolio-Funktion OPENOUT() geöffneten Datei.
    Wird der Gofolio-Bezeichner LPT als Ausgabeeinheit angegeben, so erfolgt die Ausgabe an den Drucker (parallele Schnittstelle). Die String-Constante wird auch als Format-String bezeichnet. Er kann normale Zeichen enthalten, die direkt ausgegeben werden. Z.B.: PRINT(„Hallo Welt“).
    Die String-Constante kann Konvertierungsanweisungen enthalten, die die Auswertung des als weiteres Argument vorhanden Ausdrucks bestimmen. Die Kovertierungsanweisungen haben die folgende Syntax:
    % <Flags> <Breite> <.Präzision> Typ.
    Jede Anweisung beginnt mit einem Prozentzeichen (%). Auf dieses Zeichen folgen:
    • <Flags>, eine optionale Zeichenfolge, über die die Ausgabe bezüglich Vorzeichen, Dezimalpunkte, führende und folgende Nullen, rechts-/links-bündig festgelegt wird:
      • - bewirkt eine linksbündige Ausgabe;
      • + bewirkt, daß numerische Werte mit ihrem entsprechenden Vorzeichen ausgegeben werden.
    • <Breite>, eine optionale Angabe über die minimal auszugebende Zeichenzahl.
    • <.Präzision>, eine optionale Angabe über die maximal auszugebende Zeichenzahl.
    • Typ, die Angabe über den Typ des konvertierten Zeichen:


Typ Ausdruck Ausgabe
i Integer signed integer (dezimal)
o Integer unsigned integer (oktal)
u Integer unsigned integer (dezimal)
x Integer unsigned integer (hexadezimal)
f Real Gleitkommawert, die Anzahl der Nachkommastellen wird durch Präzision festgelegt
e Real Gleitkommawert, welcher mit Exponent ausgegeben wird
c Charakter Zeichen
s String Zeichenkette.


Beispiel:

DEFINT(i); DEFREAL(r); DEFCHAR(ch[20]);
i:=-1234;
r:=SIN(1.0/3.0);
STRCPY(ADDR(ch),"Gofolio ist super");
print("signed integer: %i\n",i);
print("unsigned integer: %u\n",i);
print("unsigned integer (oktal): %o\n",i);
print("unsigned integer (hexadezimal): %x\n",i);
print("Gleitkomma: %f\n",r);
print("Gleitkomma: %2.3f\n",r);
print("Gleitkomma: %e\n",r);
print("String: %s\n",ADDR(ch));
print("Zeichen: %c\,ch[3])


Kenner haben es sicherlich schon bemerkt - , daß die Gofolio-Funktion PRINT() weitgehend der C-Funktion printf() entspricht. PRINT() kann, im Unterschied zur C-Funktion, allerdings nur einen Ausdruck ausgeben. Weiterhin muß der Formatstring immer direkt zwischen den Anführungszeichen angegeben werden - er kann also nicht über ein Array vom Typ Charakter (String) übergeben werden.


  • Real REAL(alle Typen),
    wandelt den übergebene Typ in einen Wert vom Typ Real.


  • Void RETURN(Alle Typen),
    beendet die Funktion, welche momentan bearbeitet wird. Die Funktion, die beendet wurde, gibt den Wert zurück, welcher RETURN() als Argument übergeben wurde. Es ist unbedingt darauf zu achten, daß der Typ des Arguments von RETURN() und der Rückgabe-Typ der Funktion übereinstimmen.


  • Integer RND(Void),
    gibt eine Zufallszahl zwischen 0 und 30000 zurück.


  • Void SCAN(<Eingabeeinheit>, String-Const, Variable),
    liest aus der Eingabeeinheit entsprechend dem in String-Const angegeben Format Daten und schreibt diese in die angegebe Variable. Wird keine Eingabeeinheit angegeben, so liest SCAN() die Daten von der Tastatur. Wird der Gofolio-Bezeichner FILE als Eingabeeinheit angegeben, so liest SCAN() aus einer zuvor mit der Gofolio-Funktion OPENIN() geöffneten Datei. Die String-Constante wird als Format-String bezeichnet. Über den Format-String wird festgelegt, nach welchem Format und Typ die Daten gelesen werden sollen. Es gilt die folgende Sytax:

% <Breite> <[Eingabefeld]> Typ.

  • <Breite> eine optionale Angabe über die maximal zu lesende Zeichenzahl.
  • <[Eingabefeld]> eine optionale Angabe, welche das Einlesen von Strings betrifft. Das Einlesen der Zeichen wird beendet, wenn ein Zeichen gelesen wurde, das nicht im Eingabefeld steht. Ist kein Eingabefeld angegeben, so werden alle Zeichen bis zum Lesen eines Whitespace-Zeichens gelesen. Whitespace-Zeichen sind das Leerzeichen, Zeilenvorschub (Return), Tabulator usw.


Beispiele:

  • SCAN(„%[abcde]s“, ch), dieses Beispiel bewirkt, daß so lange in den String ch eingelesen wird, bis ein Zeichen gelesen wurde, das nicht a,b,c,d oder e war.


  • SCAN(„%[a-zA-Z]s“, ch), hier wird so lange eingelesen bis ein Zeichen auftritt, welches nicht zwischen a-z oder A-Z liegt.


  • SCAN(„%[^abc]s“, ch), das ^-Zeichen bewirkt eine Invertierung, d.h. der Einlesevorgang wir beim Einlesen von a,b oder c abgebrochen.


  • Typ, legt fest nach welchen Typ die Daten eingelesen werden sollen:


Typ Eingabe Variablen-Typ
i Integer (dezimal) Integer
o Integer (oktal) Integer
x Integer (hexadezimal) Integer
f Real Real
s String Array of Charakter
c Zeichen Charakter


Beispiel:

DEFCHAR(ch[20]); DEFINT(i); DEFREAL(r);
PRINT("Bitte String eingeben: ");
SCAN("%s",ch);
PRINT("\nBitte Integerwert eingeben: ");
SCAN("%i",i);
PRINT(\nBitte Realwert eingeben: ");
SCAN("%f",r);
PRINT("%s\n",ADDR(ch));
PRINT("%i\n",i);
PRINT("%f\n",r)


Auch SCAN() stimmt nahezu mit der C-Funktion scanf() überein. Der Unterschied zur C-Funktion besteht bei SCAN() darin, daß nur eine Variable angegeben werden darf und der Format-String nur als Constante (d.h. zwischen Anführungszeichen) angegeben werden darf.

Sollte es Probleme beim Einlesen eines Zeichens von der Tastatur nach dem Format „%c“ geben, so verwenden Sie das Format „%s“.


  • Real SIN(Real),
    gibt den Sinus des Arguments (in Rad) zurück.


  • Void STRCPY(Integer, String-Const oder Integer),
    kopiert eine Zeichenkette deren Anfangsadresse als 2. Argument übergeben wird, in einen Speicherbereich, dessen Startadresse mit dem 1. Argument bestimmt wird. Beispiel:


  DEFCHAR(c1[20], c2[20]);
  STRCPY(ADDR(c1), "Hallo Welt");
  STRCPY(ADDR(c2), ADDR(c1));
  PRINT("String c1: %s\n", ADDR(c1));
  PRINT("String c2: %s\n", ADDR(c2))


  • Real TAN(Real),
    gibt den Tangens des Arguments (in Rad) zurück.


  • Real VAL(String),
    wandelt eine Zeichenkette in einen Real-Wert. Die Zeichenkette (String) wird als Argument übergeben. Beispiel:


  DEFCHAR(ch[10]); DEFREAL(r);
  STRCPY(ADDR(ch), "1.2345");
  r:=VAL(ADDR(ch));
  r:=r-1.0;
  PRINT("%f\n",r)


  • Void WHILE(Bedingung, Anweisung),
    führt die Anweisung sooft aus, wie die Bedingung erfüllt ist, d.h. wahr (1) ist.


Beispiel:

  DEFINT(n);
  n:=0;
  WHILE(n < 100, BLOCK(
    PRINT("%i\n",n),
    INC(n))
  )


  • Integer XORB(Integer, Integer),
    liefert den bitweisen Exclusiv-Oder-Vergleich der beiden Argumente zurück.


6.0 Fehlermeldungen des Compilers (GF.EXE)

FehlernummerBedeutung
1„(“ Klammer auf erwartet
2„)“ Klammer zu erwartet
3„,“ Komma erwartet
4Type-Error (Typen sind nicht kompatibel)
5Der verwendete Bezeichner wurde schon deklariert
6„:=“ Zuweisungs-Operator erwartet
7„]“ eckige Klammer zu erwartet
8Bezeichner erwartet
9String erwartet
10Unbekannter Bezeichner
11„.“ Punkt erwartet
12„;“ Semikolon erwartet
13Zahlen-Konstante erwartet
Achtung! Wurde Ihr Programm fehlerfrei compiliert und läuft beim Starten mit GO nicht bzw. stürzt ab, so haben Sie in einer Ihrer selbsgeschriebenen Funktionen sicherlich ein RETURN() vergessen. Überprüfen Sie also, ob Sie Ihre Funktionen immer mit RETURN() verlassen. Dies ist einer die häufigsten Fehler beim Schreiben von GOFOLIO-Programmen.


7.0 Versionsinformationen

Version 1.0 von GF.EXE und GO.EXE (1994)

  • Version 1.1 von GF.EXE und GO.EXE (1996):

In den Versionen 1.0 gab es einen Fehler beim Vergleichen von Real-Zahlen, dieser wurde behoben;
Auf dem ATARI Portfolio arbeitet GF.EXE teilweise nicht korrekt. Ursache waren hier Compilereinstellungen beim Übersetzen des Programms GF.EXE.
GF.EXE wurde erneut übersetzt und arbeitet jetzt korrekt auf dem ATARI Portfolio.

  • Version 1.2 von GF.EXE und GO.EXE (1996):

Auf älteren ATARI Portfolio Versionen funktioniert das Überschreiben von Dateien nicht korrekt. Dies hatte zur Folge, daß, wenn mit GF.EXE ein Programm erneut übersetzt und somit eine bestehende *.GFO Datei überschrieben wurde, die neu erzeugte *.GFO Datei fehlerhaft war. Man kann dieses Problem umgehen, indem vor einer neuen Compilation die entsprechende *.GFO Datei gelöscht wird (es wird dann also keine Datei überschrieben). Die Version 1.2 von GF.EXE löscht vor dem Schreiben der *.GFO Datei eine evt. vorhandene *.GFO Datei automatisch, weshalb „manuelles“ Löschen nicht mehr erforderlich ist.

  • Version 1.3 von GF.EXE und GO.EXE (1998):

Die Ausgabe von Byte-Arrays mit der Funktion PRINT() funktionierte teilweise nicht richtig. Dieser Fehler wurde behoben.

  • Version 1.31 von GF.EXE und GO.EXE (1998):

An GO.EXE wurde eine kleine interne Änderung vorgenommen. Das Programm wurde dadurch etwas kleiner und schneller.

  • Version 1.32 von GF.EXE und GO.EXE (1998):

Der interne Puffer für String-Konstenten wurde bei GF.EXE vergrößert.

  • Version 1.33 von GF.EXE und GO.EXE (1998):

Ein Fehler der bei der Verwendung der Funktionen AND() und OR() auftrat wurde behoben.

  • Version 1.50 von GF.EXE und GO.EXE (1998):

GO.EXE wurde überarbeitet. Das Programm wurde dadurch schneller.

  • Version 1.51 von GF.EXE und GO.EXE (1998):

Fehler, die sich bei der Überarbeitung von GO.EXE eingeschlichen haben wurden bereinigt. Die Funktionen PEEK(), POKE() und OUT() arbeiten wieder korrekt.

  • Version 2.0 von GF.EXE und GO.EXE (2001):

GoFolio hat einen Preprocessor erhalten. Sprachumfang und Ausführungsgeschwindigkeit haben sich gegenüber der Version 1.51 nicht geändert.
Genaue Erläuterungen siehe Punkt 3.2.1.

  • Version 2.1 von GF.EXE und GO.EXE (2001):

Der Preprocessor legt eine temporäre Quelltextdatei an. In der Version 2.0 wurde diese Datei auch dann angelegt, wenn wenn keine Preprocessoranweisungen vorhanden waren. In der Version 2.1 wird diese temporäre Datei nur angelegt, wenn tatsächlich Preprocessoranweisungen vorliegen.

  • Version 2.2 von GF.EXE (2004):

Ein Fehler im Preprocessor wurde behoben.

8.0 Tips

8.1 Maschinenprogramme unter Gofolio

Sie haben die Möglichkeit Maschinencode in Ihre Gofolio-Programme zu integrieren. Hierzu schreiben Sie die Hex-Codes des Maschinenprogramms in ein Char-Array (String). Gestartete wird das Maschinenprogramm, indem ein Interrupt-Vektor eines unbenutzten Interrupts auf die Adresse des Strings mit dem Maschinencode „umgebogen“ wird, und anschließend der Interrupt aufgerufen wird. Zum Umbiegen des Interrupt-Vektors wird die Funktion 25h des Interrupt 21h „Setze Interrupt-Vektor“ verwendet. Hierzu wird das AH-Register mit der Funktionsnummer 25h geladen und das AL-Register mit der Nummer des Interrupts, welcher „umgebogen“ werden soll. In das DX-Register wird die Offset-Adresse des Maschinencodes (also des Strings) geschrieben (das DS-Register muß nicht gesetzt werden, da es schon die korrekte Segment-Adresse enthält). Nach dem nun der Interrupt 21h ausgeführt wurde, zeigt jetzt der „verbogene“ Vektor auf den Maschinen-Code.
Es ist darauf zu achten, daß die letzte Anweisung in dem Maschinenprogramm immer IRET (Interrupt-Return) ist.

In dem folgenden Gofolio-Programm wird der (freie) Interrupt 63h auf das Beispiel-Maschinenprogramm, welches einen Signalton ausgibt, gesetzt.

Beispiel-Maschinenprogramm:

  PUSH AX
  PUSH DX
  MOV DL,07
  MOV AH,02
  INT 21
  POP DX
  POP AX
  IRET


Gofolio-Programm:

  defchar(ch[20]);
  defint(off,seg);
  off:=addr(ch);
  strcpy(off,"\x50\x52\xb2\x07\xb4\x02\xcd\x21\x5a\x58\xcf");
  _ax:=0x25*256+0x63;
  _dx:=off;
  intr(0x21);
  intr(0x63)


Mit dem Befehl intr(0x63) wird das Maschinenprogramm gestartet.
Der Datenaustausch zwischen Maschinen- und Hauptprogramm kann über die Registervariablen _AX, _BX, _CX usw. erfolgen.

8.2 Unterprogramme zur Stringbearbeitung

Gofolio beinhaltet nur wenige Funktionen zur Stringbehandlung. Anhand der Funktionen len() (berechnet die Länge eines Strings) und pos() (berechnet die Position eines Zeichens in einem String) soll demonstriert werden, wie eigene Funktionen zur Stringbehandlung effektiv selbstgeschrieben werden können.

Beispiel:

defchar(c[50],ch);
 
inttype #len(defint(x));
block(
  defint(n),
  n:=0,
  while(peek(ds(),x+n) <> 0, inc(n)),
  return(n)
);
 
inttype #pos(defchar(c),defint(x));
block(
  defint(n),
  n:=0,
  while(char(peek(ds(),x+n)) <> c,inc(n)),
  if(len(x) < n, return(-1), return(n)),
);
 
print("String?: "); scan("%s",c);
print("Zeichen?: "); scan("%s",ch);
print("\nlen=%i",len(addr(c)));
print("\npos=%i",pos(ch,addr(c))).


8.3 Geschwindigkeitsoptimierung

Besondes bei der Programmierung der Hardware (z.B. beim Ein-/Auslesen von Ports oder Prozessorregistern) ist es wichtg, daß das GOFOLIO-Programm hinterher kommt. Hier einige Tips:
Laufvariablen von WHILE-Schleifen immer als Integer definieren und mit den Funktionen INC() bzw. DEC() erhöhen bzw. erniedrigen. Dies ist wesentlich schneller als z.B.: i:=i+1 bzw. i:=i-1.
Beim Umgang mit Variablen gibt es beträchtliche Geschwindigkeitsunterschiede:

  • Am schnellsten arbeiten die globalen Nicht-Array-Variablen.
  • Dann folgen lokale Nicht-Array-Variablen
  • Dann folgen globale Array-Variablen
  • Am langsamsten arbeiten lokale Array-Variablen.
software/diy/andere/gofolio.txt · Zuletzt geändert: 21/01/2009 00:01 (Externe Bearbeitung)