home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AMIGA PD 1
/
AMIGA-PD-1.iso
/
Programme_zum_Heft
/
Programmieren
/
Workshops
/
E-Compiler
/
Doks
/
E-Doku.Deutsch.TXT
< prev
next >
Wrap
Text File
|
1994-04-08
|
112KB
|
3,213 lines
Inhalt
}
Compiler für die E Sprache
Von Wouter van Oortmerssen
Supertolle Preise zu gewinnen
}
1. Formatierung
2. Direkte Werte
3. Ausdrücke
4. Operatoren
5. Statements
6. Funktions Definition und Deklaration
7. Deklaration von Konstanten
8. Typen
9. Eingebaute Funktionen
10. Library Funktionen und Module
11. Ausgewertete Ausdrücke
12. Fließkommaunterstützung
13. Exception Behandlung
14. Objekt-Orientiertes Programmieren
15. Der Inline Assembler
16. Eingebaute Ausgaben
Bemerkung
Hääää, reingelegt... ROFL
Für den Fall, daß irgendjemand Fragen zur Übersetzung einzelner Kapitel
hat, wende er sich bitte an:
Kapitel 1,4-5,7-9,11-12,15 : Rolf Breuer
Marktstr. 13
45891 Gelsenkirchen
Kapitel 2,3,14, : Daniel van Gerpen
Amiga-Guide Fassung Alter Postweg 3
26759 Hinte
Kapitel 10 : Gregor Goldbach
Grüner Weg 10
21423 Pattensen
Kapitel 16 : Christoph Lange
Altdorferstr. 19
63739 Aschaffenburg
Kapitel 6, 13 : Jörg Wach
Waitzstr. 75
24105 Kiel
Wenn jemand eine, seiner Meinung nach besser, Übersetzung eines oder
mehrerer Kapitel hat, dann kann er diese an Daniel van Gerpen (s.o.)
schicken, und wird dann beim nächsten Mal hier erwähnt.
Index
}
Compiler für die E Sprache
Von Wouter van Oortmerssen
Index
1. Formatierung
A. Tabulatoren(tabs), Zeilenvorschübe(lf) usw.
B. Kommentare
C. Identifier und Typen
2. Direkte Werte
A. Dezimalzahlen (1)
B. Hexadezimalzahlen ($1)
C. Binärzahlen (%1)
D. Fließkommazahlen (1.0)
E. Zeichen ('a')
F. Zeichenketten ('bla')
G. Listen ([1,2,3]) und symbolische Listen
3. Ausdrücke
A. Format
B. Abarbeitung und Anordnung
C. Arten von Ausdrücken
D. Funktionsaufrufe
4. Operatoren
A. Mathematische (+ - * /)
B. Vergleiche (= <> > < >= <=)
C. Logische und Bitweise (AND OR)
D. Unary (SIZEOF ` ^ {} ++ -- -)
E. Dreifach (IF THEN ELSE)
F. Strukturen (.)
G. Felder ([])
H. Fließkommaoperator (|)
I. Zuweisungsoperator (:=)
J. Reihenfolge (BUT)
5. Statements
A. Format (;)
B. Sprungmarken und Sprunganweisungen (JUMP)
C. Zuweisungen (:=)
D. Assembler Mnemonics
E. Bedingte Anweisungen (IF)
F. For-Anweisung (FOR)
G. While-Anweisung (WHILE)
H. Repeat-Anweisung (REPEAT)
I. Loop-Anweisung (LOOP)
J. Auswahl-Anweisungen (SELECT)
K. Zuwachs-Anweisungen (INC/DEC)
L. Void-Ausdrücke (VOID)
6. Funktions Deklaration und Definition
A. Prozedur Definition und Argumente (PROC)
B. Lokale und globale Definitionen (DEF)
C. Endproc/return
D. Die 'main' Funktion
E. E-eigene Systemvariablen
7. Deklaration von Konstanten
A. Konstanten (CONST)
B. Aufzählungen (ENUM)
C. Sets (SET)
D. E-eigene Konstanten
8. Typen
A. Über das 'type' System
B. Der Grundtyp (LONG/PTR)
C. Die einfachen Typen (CHAR/INT/LONG)
D. Der Feldtyp (ARRAY)
E. Die komplexen Typen (STRING/LIST)
F. Der Verbundtyp (OBJECT)
G. Einrichtung
9. Eingebaute Funktionen
A. Ein-/Ausgabeoperationen
B. Zeichenketten und Zeichenkettenfunktionen
C. Listen und Listen Funktionen
D. Intuition unterstützende Funktionen
E. Grafikfunktionen
F. Systemfunktionen
G. Mathematische Funktionen
H. Funktionen zum Verbinden von Zeichenketten und Listen
10. Library Funktionen und Module
A. Eingebaute Library Aufrufe
B. Schnittstellen zum Amiga Sytem mit den 2.04 Modulen bilden
11. Ausgewertete Ausdrücke
A. Auswertung und Bereich
B. Eval()
C. Eingebaute Funktionen
12. Fließkommaunterstützung
A. Gebrauch/Überladen von Fließkommazahlen/-operatoren
B. Fließkommaausdrüke und Umwandlungen
13. Exception Behandlung
A. Definition von Exceptionhandlern (HANDLE/EXCEPT)
B. Benutzung der Raise() Funktion
C. Exceptions für eingebaute Funktionen (RAISE/IF)
D. Benutzung von Exception-ID's
14. Objektorientierte Programmierung
15. Der Inline-Assembler
A. Variablenteilung
B. Vergleich zwischen Inline-/Makroassembler
C. Wege, Binäredaten zu nutzen (INCBIN/CHAR..)
D. OPT ASM
16. Dinge über den Compiler
A. Das OPT Schlüsselwort
B. Small/Large Modell
C. Stack Organisation
D. Festgeschriebene Begrenzungen
E. Fehlermeldungen, Warnungen und nicht dokumentierte Tests
F. Compiler Puffer Organisation und Anforderung
G. Eine kurze Entstehungsgeschichte
Formatierung
}1.FORMATIERUNG@{uu}
B. Kommentare
C. Identifier und Typen
Vorheriges Kapitel
Nächstes Kapitel
Formatierung
}1A.
-----------------------------------------------
E-Sources sind reine ASCII-Dateien, mit Zeilenvorschüben (lf) und Semiko-
lons ";" als Trennung zwischen zwei Ausdrücken. Ausdrücke die mehrere Ar-
gumente haben, die durch ein Komma "," getrennt sind, können über mehrere
Zeilen verteilt werden, wenn die Zeile mit einem Komma endet, indem der
folgende Zeilenvorschub ignoriert wird.
Jedes lexikalische Elemente in einer Source-Code-Datei kann durch eine
beliebige Anzahl von Leerzeichen oder Tabulatoren vonm nächsten getrennt
werden.
Formatierung
}1B.
--------------
Kommentare können überall im Sourcecode plaziert werden, wo Leerzeichen
korrekt wären. Sie beginnen mit "/*" und enden mit "*/" und können unend-
lich verschachtelt werden.
Formatierung
}1C.
------------------------
Identifier sind Strings die Programmierer benutzen um bestimmte Objekte zu
benennen, in den meisten Fällen Variabeln, oder nur Schlüsselwörter oder
Funktionsnamen die vom Compiler vordefiniert wurden. Ein Identifier kann
aus folgenden bestehen:
-große und kleine Buchstaben
-"0".."9" außer als ersten Buchstaben
-"_" dem Unterstrich
Alle Zeichen werden beachtet, aber der Compiler benutzt nur die ersten
beiden um den Typ des Identifiers zu bestimmen, mit dem er ihn behandelt:
beide groß - Schüsselwort wie IF, PROC usw
- Konstanten wie MAX-LENGTH
- Assembler Mnemonic, wie MOVE
erster klein - Identifier von Variabel/Sprungmarken/Objekten usw.
erster groß und
zweiter klein - E-System-Funktionen
- Library Aufrufe: z.B. OpenWindow()
Zu bedenken ist, daß alle Identifier dieser Schreibweise folgen, zum Bei-
spiel: WBenchToFront wird zu WbenchToFront
Direkte Werte
}2.DIREKTE
Direkte Werte werden in E immer zu einem 32 Bit Ergebniss
umgewandelt. Der einzige Unterschied zwischen diesen Werten
(A-G) ist entweder ihre interne Darstellung, oder die
Tatsache, daß sie einen Zeiger anstatt eines Wertes
zurückgeben.
A. Dezimalzahlen (1)
B. Hexadezimalzahlen ($1)
C. Binärzahlen (%1)
D. Fließkommazahlen (1.0)
E. Zeichen ('a')
F. Zeichenketten ('bla')
G. Listen ([1,2,3]) und symbolische Listen
Vorheriges Kapitel
Nächstes Kapitel
Direkte Werte
}2A.
---------------------
Eine Dezimalzahl ist eine Folge der Zeichen "0"..."9", möglicherweise durch
ein Minuszeichen "-" angeführt um negative Zahlen zu kennzeichnen.
Beispiel: 1, 100, -12, 1024
Direkte Werte
}2B.
--------------------------
Ein hexadezimaler Wert benutzt die zusätzlichen Zeichen "A"..."F" (oder
"a"..."f") und wird mit einem "$" Zeichen begonnen.
Beispiele: $FC, $DFF180, -$ABCD
Direkte Werte
}2C.
--------------------
Binärzahlen beginnen mit einem "%" Zeichen und benutzen nur die Zeichen
"1" und "0" um einen Wert zu bilden.
Beispiele: %111, %1010100001, -%10101
Direkte Werte
}2D.
--------------------------
Fließkommazahlen unterscheiden sich nur durch einen "." von normalen
Dezimalzahlen, der dazu dient die beiden Teile auseinander zu halten.
Jeweils einer der beiden Teile darf weggelassen werden, nie beide. Zu
Bedenken ist, daß Fließkommazahlen eine andere interne 32 Bit Darstellung
(FFP) haben. Mehr Informationen über Fließkommazahlen gibt es im Kapitel
12.
Beispiele: 3.14159, .1 (entspricht 0.1), 1. (entspricht 1.0)
Direkte Werte
}2E.
-----------------
Der Wert eines Zeichens (in Anführungszeichen "" eingeschlossen) ist ihr
ASCII Wert, z.B. "A"=65. In E können direkte Zeichenwerte kurze Zeichen-
ketten mit bis zu 4 Zeichen sein, zum Beispiel "FORM", wobei das erste
Zeichen "F" das MSB und "M" das LSB (least significat Bit) der 32 Bit-Dar-
stellung ist.
Direkte Werte
}2F.
-------------------------
Zeichenketten sind irgendwelche ASCII-Darstellungen, die von Hochkommatas
'' (Alt+'Ä') eingeschlossen sind. Der Wert einer solchen Zeichenkette ist
ein Zeiger auf das erste Zeichen der Kette. Spezifischer: 'bla' erzeugt
einen 32 Bit Zeiger zu einem Speicherbereich wo wir die Bytes "b", "l"
und "a" finden können. Alle Zeichenketten in E werden mit einem 0 Byte ab-
geschlossen.
Zeichenketten können Formatzeichen, von einem Backslash "/" angeführt, ent-
halten. Entweder um Zeichen in eine Zeichenkette einzufügen, die aus irgend-
welchen Gründen nicht darstellbar sind, oder um Zeichenkettenformatierungs-
funktionen wie von WriteF(), TextF() und StringF(), oder der Kickstart 2.0
Funktion Vprintf zu nutzen.
\n ein Zeilenvorschub
\a oder '' ein Hochkomma (das zum Einschließen von Zeichenketten benutzt
wird)
\e Escape (ASCII 27)
\t Tabulator (ASCII 9)
\\ Backslash
\0 ein Null-Byte. Wird nur selten benutzt, da jede Zeichenkette
mit einem Null-Byte abgeschlossen wird
\b ein Carriage Return (Wagenrücklauf)
Zusätzlich, bei Benutzung mit Format-Funktionen:
\d schreibt ein Dezimalzahl
\h schreibt eine Hexadezimalzahl
\s schreibt eine String
\c schreibt ein Zeichen
\z schreibt Füllzeichen bei Nullen
\l formatiert linksbündig
\r formatiert rechtsbündig
Feldvariabeln können /d,/h und /s Codes folgen:
[x] bezeichnet die genaue Feldbreite x
(x,y) bezeichnet das Minimum und das Maximum y (nur bei Zeichenketten)
Beispiel: Schreibt eine Hexadezimalzahl mit 8 Stllen und führenden Nullen
WriteF ('\z\h[8]\n',num)
Eine Zeichenkette kann über meherer Zeilen verteilt werde, indem man sie mit
einem "+" Zeichen und einen <lf> (Zeilenvorschub) verbindet:
'dies ist eine sehr lange Zeichenkette'+
'sie wurde über mehrere Zeilen verteilt'
Direkte Werte
}2G.
-------------------------------------------
Eine direkte Liste ist das konstante Gegenstück des List Datentyps, genauso
wie eine "Zeichenkette" das konstante Gegenstück für den STRING oder den
ARRAY OF CHAR Datentyp ist. Beispiel:
[3,2,1,4]
ist ein Ausdruck, das als Wert einen Zeiger auf eine bereits fertigestellte
Liste hat. Eine Liste ist eine Darstellung im Speicher, die gleichwertig
mit ARRAY OF LONG ist, mit einigen zusätzlichen Längeninformationen an
einem negativen Offset. Du kannst diese direkten Listen überall benutzen,
wo eine Funktion einen Zeiger auf ein Feld von 32 Bit Werten oder eine Liste
erwartet. Beispiele:
['Zeichenkette',1.0,2.1]
[WA_FLAGS,1,WA_IDCMP,$200,WA_WIDTH,120,WA_HEIGHT,150,TAGDONE]
Schaue Dir das Kapitel über List-Funktionen für eine Besprechung von symbo-
lischen Listen und Detailinformationen an.
Ausdrücke
}3.AUSDRÜCKE@{uu}
B. precedence and grouping
C. types of expressions
D. function calls
Vorheriges Kapitel
Nächstes Kapitel
Ausdrücke
}3A.
----------
Ein Ausdruck ist ein Stück Quelltext, das aus Operatoren, Funktionen und
Klammern besteht, um einen Wert zu erstellen.
Sie bestehen meistens aus:
- direkten Werten wie im Kapitel 2 besprochen
- Operatoren wie im Kapitel 4 besprochen
- Funktionsaufrufen wie im Kapitel 3D besprochen
- Klammern wie im Kapitel 3B besprochen
- Variabeln oder Variabelausdrücken (siehe Kapitel 3C)
Beispiele für Ausdrücke
1
'Hallo'
$ABCD+(2*5)+Abs(a)
(a<1) OR (b>=100)
Ausdrücke
}3B.
-----------------------------
E hat keinen Abarbeitungsvorrang. D. h., daß Ausdrücke von links nach
rechts ausgewertet werden. Du kannst die Abarbeitung durch Einklammern
von (Unter-) Funktionen ändern:
1+2*3 /*=9*/ 1+(2*3) /*=7*/ 2*3+1 /*=7*/
Ausdrücke
}3C.
------------------------
Es gibt drei Arten von Ausdrücken, die für unterschiedliche Verwendungs-
zwecke genutzt werden:
- <var> besteht nur aus einer Variabel
- <varexp> bestehend aus einer Variabel, möglicherweise mit einem unary(??)
Operator dazu, wie ++ (increment) oder [] (Array Operator). Hierfür siehe
Kapitel 4D und 4G. Es zeigt einen veränderbaren Ausdruck an, wie Lvalues
in C.
Bedenke das diese unary (??) Operatoren nie Teil der Abarbeitung sind
- <exp>. Dies beinhaltet <var> und <varexp, und jede andere Art von Aus-
druck
Ausdrücke
}3D.
--------------------
Ein Funktionsaufruf ist eine zeitweilig Unterbrechung des aktuellen Codes,
um in eine Funktion zu springen. Dies kann entweder eine selbstgeschriebene
Funktion (PROC), oder eine Funktion die vom System zu verfügung gestellt
wird.
Das Format eines solchen Funktionsaufruf ist der Name der Funktion, gefolgt
von zwei Klammern(), die von Null bis zu unendlich vielen Argumenten, die
durch Kommas getrennt werden, enthält. Argumente für Funktionen sind
wiederum Ausdrücke. In Kapitel 6 steht wie man seine eigene Funktion er-
stellt und Kapitel 9 und 10 beschreiben die eingebauten Funktionen. Bei-
spiele:
foo (1,2)
Gadget(buffer,glist,2,0,40,80+offset,100,'Cancel')
Close(handle)
Operatoren
}4.OPERATOREN@{uu}
B. Vergleiche (= <> > < >= <=)
C. Logische und Bitweise (AND OR)
D. Unary (SIZEOF ` ^ {} ++ -- -)
E. Dreifach (IF THEN ELSE)
F. Strukturen (.)
G. Felder ([])
H. Fließkommaoperator (|)
I. Zuweisungsoperator (:=)
J. Reihenfolge (BUT)
Vorheriges Kapitel
Nächstes Kapitel
Operatoren
}4A.
---------------------------
Diese festen Operatoren verbindett einen Ausdruck mit einem anderen Wert,
um einen neuen Wert zu bilden. Beispiele:
1+2, MAX-1*5
in Kapitel 12 wird beschrieben, wie man diese Operatoren überlädt um sie
Fließkommazahlen zu benutzen. "-" kann als erster Teil eines Ausdrucks be-
nutzt werden, natürlich inklusive 0.
z.B. sind -a oder -b+1 zulässig
Bedenke, daß * und / standardmäßig 16 Bit Operatoren sind: siehe Mul()
Operatoren
}4B.
-------------------------------
Gleich wie mathematische Operatoren, mit dem Unterschied, das ihr Ergebniss
entweder TRUE (Wahr) (32 Bit Wert -1) oder FALSE (Falsch). Diese können
auch für Fließkommazahlen überladen werden.
Operatoren
}4C.
----------------------------------
Diese Operatoren kombinieren entweder Wahrheitswerte zu neuen oder operie-
ren bitweise mit AND und OR. Beispiele:
(a>1) AND ((b=2) OR (c>=3)) /*logisch */
a:=b AND $FF /*bitweise*/
Operatoren
}4D.
++ -- `)
b}
---------------------------------
-4E. Dreifach (IF THEN ELSE)
b}
---------------------------
Der4F. Strukturen (.)
b}
------------------
<prt2objekt>.<memberofobjekt>4G. Felder ([])
b}
---------------
<var>[<indexexp>]4H. Fließkommaoperator (|)
b}
--------------------------
<exp>\<exp>
Wandelt4I. Zuweisungsoperator (:=)
b}
---------------------------
Zuweisungen4J. Reihenfolge (BUT)
b}
---------------------
Der5.STATEMENTS
u}
B. Sprungmarken und Sprunganweisungen (JUMP)
C. Zuweisungen (:=)
D. Assembler Mnemonics
E. Bedingte Anweisungen (IF)
F. For-Anweisung (FOR)
G. While-Anweisung (WHILE)
H. Repeat-Anweisung (REPEAT)
I. Loop-Anweisung (LOOP)
J. Auswahl-Anweisungen (SELECT)
K. Zuwachs-Anweisungen (INC/DEC)
L. Void-Ausdrücke (VOID)
Vorheriges Kapitel
Nächstes Kapitel
Statements
}5A.
--------------
Wie im Kapitel 1A, steht ein Statement in seiner eigenen Reihe, aber mehrere
von ihnen können in einer Reihe, durch ein Semikolon getrennt, geschrieben
werden. Auch kann ein Statement über mehr als eine Zeile verteilt werde,
wobei jede Zeile mit einem Komma enden muß. Beispiel:
a:=1, WriteF('Hallo!\n')
DEF a,b,c,d, /*zuviele Argumente für eine Zeile (vorgemacht)*/
e,f,g
Statement können sein
- Zuweisungen
- Bedingt Zuweisungen für Statement und sowas, siehe auch Kapitel 5E-5K
- Rückgabefreie Ausdrücke
- Sprungmarken
- Assembleranweisungen
Das Komma ist das erste Zeichen um zu zeigen, das Du das Statement nach dem
nächsten Zeilenvorschub noch nicht beenden willst, aber auch die folgenden
Zeichen zeigen an, daß das Statement in der folgenden Zeile fortgeführt
wird:
+ - * /
= > < <> >= <=
AND OR BUT THEN
Statements
}5B.
---------------------------------------------
Lables sind globale Identifier mit einem zusätzlichen ":", wie bei
mylable:
sie können von Anweisungen wie JUMP benutzt werden, aber auch um statische
Daten zu erzeugen. Sie können benutzt werden, um aus jeder Art von Schleife
zu springen (obwohl diese Technik nicht gut ist), aber es kann nicht aus
einer Prozedure gesprungen werden. In normalen E-Programmen werden sie
meistens für den Inline-Assembler benutzt. Lables sind immer global sicht-
bar.
Benutzung von JUMP: JUMP <lable>
führt die Abarbeitung beim <lable> fort. Du solltest dies aber nicht be-
nutzen, es ist eigentlich nur für Situationen da, wo man die Komplexität
eines Programms vermindert. Beispiel:
IF Mouse()=1 THEN JUMP stopnow
/*andere Programmteile*/
stopnow:
Statements
}5C.
--------------------
Das grundsätzliche Format einer Zuweisung ist <var>:=<exp>
Beispiele: a:=1, a:=myfunc(), a:=b*3
Statements
}5D.
-----------------------
In E ist der Inline-Assembler ein wirklicher Teil der Sprache, er muß nicht
in spezielle "ASM" Blöcke oder sowas, wie es in anderen Sprachen notwendig
ist, noch ist ein extra Assembler nötig, um den Code zu Asseblieren. Das
heißt auch, daß er den normalen E Syntax-Regeln gehorcht, usw. In Kapitel
15 kannst Du alles über den Inline-Assembler lesen. Beispiele:
DEF a,b
b:=2
MOVEQ #1,D0 /*nur einige Assembler-Statements*/
MOVEL D0,a /*a:=1+D*/
ADD.C b,a
WriteF('a=\d\n',a) /*a wird 3 sein*/
Statements
}5E.
-----------------------------
IF, THEN, ELSE, ELSEIF, ENDIF
Syntax: IF <exp> THEN <Statment> [ELSE <Statement>]
oder : IF <exp>
<Statements>
[ELSEIF <exp> /*mehrere elseifs können vorkommen*/
<Statements>]
[ELSE
<Statements>]
ENDIF
bilden einen Bedingten-Block. Bedenke das es zwei Hauptformen von diesem
Statement gibt, eine einzeilen und eine mehrzeilen Version.
Statements
}5F.
-----------------------
FOR, TO, STEP, DO, ENDFOR
Syntax: FOR <var>:=<exp> STEP <Schrittweite> DO <Statement>
oder : FOR <var>:=<exp> STEP <Schrittweite>
<Statements>
ENDFOR
bilden einen FOR-Block, beachte die beiden Hauptformen. <Schrittweite> kann
jede positive oder negative Konstanten, außer 0 sein. Beispiele:
FOR a:=1 TO 10 DO WriteF('\d\n'a)
Statements
}5G.
---------------------------
WHILE, DO, ENDWHILE
Syntax: WHILE <exp> DO <Statement>
oder : WHILE <exp>
<Statements>
ENDWHILE
bilden eine While-Schleife, die solange durchlaufen wird, wie <exp> TRUE
ergibt. Beachte die Ein-Zeile/Ein-Statement-Version und die Mehrzeilen-
Version.
Statements
}5H.
-----------------------------
REPEAT, UNTIL
Syntax: REPEAT
<Statements>
UNTIL <exp>
bilden einen Repeat-Until-Block. Die Schleife wird fortgesetzt bis <exp>=
TRUE ist. Beispiel:
REPEAT
WriteF('Möchtest du wirklich dieses Programm beenden?\n'
ReadStr(stdout,s)
UNTIL StrCmp(s,'ja bitte!')
Statements
}5I.
-------------------------
LOOP, ENDLOOP
Syntax: LOOP
<Statements>
ENDLOOP
bilden eine unendliche Schleife.
Statements
}5J.
--------------------------------
Syntax: SELECT <var>
[CASE <exp>
<Statements>]
[CASE <exp>
<Statements>] /*eine beliebige Anzahl weiterer Blöcke*/
[DEFAULT <exp>
<Statement>]
ENDSELECT
bilden einen Select-Case-Block. Beliebige Ausdrücke werden mit der Varia-
bel <var> verglichen, und der erste passende Block wird ausgeführt. Wenn
kein gleicher Ausdruck vorhanden ist, kann ein Default-Block ausgeführt
werden.
SELECT zeichen
CASE 10
WriteF('Hey, wir haben einen Zeilenvorschub gefunden\n')
CASE 9
WriteF('Wow, das muß ein Tabulator sein!\n')
DEFAULT('Kennst Du dieses Zeichen: \c?\n',zeichen)
ENDSELECT
Statements
}5K.
---------------------------------
INC, DEC
Syntax: INC <var>
DEC <var>
kurz für <var>:=<var+1> und <var>:=var-1. Der einzige Unterschied zu var++
und var-- ist, daß dies Statements sind, und keinen Wert zurückgeben und
folglich optimaler sind.
Statements
}5L.
------------------------
Syntax: VOID <exp>
Berchnet den Ausdruck ohnen das der Wert irgendwohin geht. Dies ist nur
für eine lesbarere Syntax nützlich, da Ausdrücke in E auch als Statement
ohne VOID benutzt werden können. Dies kann heikle Fehler verursachen, da
"a:=1" a den Wert 1 zuweist, aber "a=1" als Statement nichts tut. E warnt
Dich, wenn das passiert.
Function Definitions and Declarations
}6.FUNKTIONS
A. Prozedur Definition und Argumente (PROC)
B. Lokale und globale Definitionen (DEF)
C. Endproc/return
D. Die 'main' Funktion
E. E-eigene Systemvariablen
Vorheriges Kapitel
Nächstes Kapitel
Funktions Deklaration und Definition
}6A.
--------------------------------------------
Du darfst PROC und ENDPROC zur Zusammenfassung von Ausdrücken in deinen
eigenen Funktionen zu verwenden.
Solche ein Funktion darf irgendwelche Anzahl von Argumente haben und liefert
einen Wert zurück.
PROC, ENDPROC
Syntax: PROC <Marke> ( <Argumente> , ... )
ENDPROC <Rückgabewert>
Definiert eine Prozedur mit irgendeiner Anzahl von Argumenten.
Argumente sind von Typ LONG oder Optional als PTR TO <TYP> (siehe
Kapitel 8
)
und brauchen kein weitere Deklarationen.
Das Ende einer Prozedur wird gekennzeichnet durch ENDPROC. Wenn kein Rück-
gabewert mitgegeben wird, so wird 0 zurückgeliefert.
Beispiel: Eine Funktion, die zwei Argumente zusammengefasst zurückliefert:
PROC add(x,y) /* x und y sind lokale Variablen */
ENDPROC x+y /* liefert das Resultat zurück */
Funktions Deklaration und Definition
}6B.
-----------------------------------------
Du darfst lokale Variablen definieren, indem Du die Argumente mit der
DEF-Angabe bestimmst. Der leichteste Weg ist
DEF a,b,c
erklärt die Bezeichner a, b und c als Variablen deiner Funktion.
Beachten daß solche Deklarationen am Anfang Deiner Funktionen stehen müssen.
DEF
Syntax: DEF <Deklarationen>,...
Beschreibung definiert Variablen. Eine Deklarationen hat eine der Formen:
<Variable>
<Variable>:<Typ> wobei <typ>=LONG,<objectidentifizierer>
<Variable>[<Größe>]:<Typ> wobei <typ>=ARRAY,STRING,LIST
Siehe
Kapitel 8
für mehr Beispiele, wo steht, wie die Typen benutzt
werden.
Fürs erste ist es gut die <Variable>-Form zu benutzen.
Argumente für Funktionen sind beschränkt auf die Basis-Typen; siehe
Kapitel 8B
.
Ein Deklarationen eines Basis-Types kann eine Initialisierung haben, in der
aktuellen Version muß dieses ein Integer sein (kein Ausdruck):
DEF a=1,b=2
Ein Programm beinhaltet mehrere Funktionen, genannt PROCs. Jede
procedure may have Local variables, and the program as a whole may have
Prozedur darf lokale Variablen haben, und das Programm als ganzes
darf globale Variablen haben.
Ein Programm muß mindestens aus der Prozedur PROC main() bestehen, da diese
Prozedur den Anfang der Ausführung bestimmt.
Ein einfaches Programm könnte wie folgt ausschauen:
DEF a, b /* Definition der globalen Variablen */
PROC main() /* alle Funktionen in zufälliger Ordnung */
bla(1)
ENDPROC
PROC bla(x)
DEF y,z /* Eigene, lokalen Variablen möglich. */
ENDPROC
Zusammengefasst: lokale Definitionen sind diejenigen, die Du am Start der
Prozeduren nennst und welche erst in der Prozedur sichtbar werden. Globale
Definitionen werden vor der ersten PROC gemacht, also am Start deines
Quell-Codes, und sie sind global verfügbar. Globale und lokale Variablen
(und natürlich lokale Variablen von zwei unterschiedlichen Funktionen)
dürfen den gleichen Name haben.
Lokale Variablen haben immer höhere Priorität!
Funktions Deklaration und Definition
}6C.
------------------
Wie zuvor gesagt, markiert ENDPROC das Ende einer Funktionen-Definition,
und darf einen Wert zurückliefern.
Optional kann RETURN an irgendwelchen Punkt in der Funktion zum beenden der
Funktion benutzt werden. Wenn REURN in der Prozedur main() benutzt wird,
dann endet das Programm.
Siehe auch CleanUp() in
Kapitel 9F
.
RETURN [<Rückgabewert>] /* optional */
Beispiel:
PROC getresources()
/* ... */
IF error THEN RETURN FALSE /* etwas ist schiefgegangen, also raus
aus der Funktion mit dem Rückgabewert
"FALSCH". */
/* ... */
ENDPROC TRUE /* wir sind soweit, damit liefern wir TRUE zurück. */
Eine sehr kurz Version bei einer Funktion-Definition ist
PROC <marke> ( <Argument> , ... ) RETURN <Ausdruck>
These are function definitions that only make small computations, like
Diese sind Funktions-Definitionen die kleine Berechnungen machen, wie
fakultative Funktionen und sie sind (ein-Zeiler :-)
PROC fac(n) RETURN IF n=1 THEN 1 ELSE fac(n-1)*n
Funktions Deklaration und Definition
}6D.
-----------------------
Die PROC mit dem Namen main() ist unheimlich Wichtig, weil es
die erste aufgerufene Funktion ist; sie ist genauso aufgebaut wie andere
Funktionen und darf auch lokale Variablen haben.
main() hat keine Argumente; die CLI-Kommando-Zeilen Argumente werden in
der System-Variable "arg" geliefert, oder können überprüft werden mit
ReadArgs()
Funktions Deklaration und Definition
}6E.
----------------------------
Folgende globale Variablen sind immer verfügbar in Deinem Programm,
sie werden System Variablen genannt.
arg Wie oben gesagt, beinhaltet "arg" einen Zeiger zu einem mit
mit Null abgeschlossen String. Der String wiederum
beinhaltet die CLI-Kommando-Zeilen-Argumente.
Benutze nicht diese Variable wenn du ReadArgs() in
Deinem Programm benutzt.
stdout Beinhaltet ein File-Handle zu der Standard Ausgabe
(und Eingabe).
Wenn dein Programm von der Workbench gestartet wurde, so daß
kein Shell-Fenster verfügbar ist, WriteF() öffnet ein CON:
Fenster für dich und setzt den entsprechenden File-Handler
hier hinein.
conout Hier wird das File-Handle abgelegt, und das CON:
Fenster wird automatisch geschlossen nach einem exit
von Deinem Programm.
Siehe WriteF() in Abschnitt 9E, um zu sehen, wie die zwei
Variablen richtig benutzt werden.
execbase, Diese fünf Variablen enthalten IMMER die
dosbase, richtigen Werte.
gfxbase,
intuitionbase,
mathbase
stdrast Zeiger zum Standard-Rastport, um diesen in deinem Programm
benutzten zu können, oder NIL.
Die eingebauten Grafik-Funktionen wie Line() benutzen
diese Variable.
wbmessage Beinhaltet einen Zeiger zu ein Nachricht die du bekommst,
wenn du von der Worbench startest, sonst NIL.
Darf benutzt werden wie ein Boolean-Wert um festzustellen,
ob du von der Workbench gestartet bist oder sogar zum
überprüfen irgendwelcher Argumente, die mit Deinem ICON
"Shift-ausgewählt" wurden.
Siehe WbArgs.e in dem sources/Examples Verzeichnis, um zu
sehen, wie gut man wbmessage benutzen kann.
Deklaration von Konstanten
}7.DEKLARATION
A. Konstanten (CONST)
B. Aufzählungen (ENUM)
C. Sets (SET)
D. E-eigene Konstanten
Vorheriges Kapitel
Nächstes Kapitel
Deklaration von Konstanten
}7A.
----------------------
Syntax: CONST <Deklaration>
Ermöglicht es Dir eine Konstante zu deklarieren. Eine Deklaration sieht so
aus:
<ident>=<Wert>
Konstanten müssen großgeschrieben sein, und werden für den Rest des Pro-
gramms als <Wert> behandelt. Beispiel:
CONST MAX_LINES=100, ER_NOMEM=1, ER_NOFILE=2
Man kann keine Konstanten mit Termen deklarieren in denen Konstanten sind
die im selben Statement deklarier werden: Schreibe diese ins nächste.
Deklaration von Konstanten
}7B.
-----------------------
Aufzählungen sind ein spezieller Typ von Konstanten, bei denen kein Wert an-
gegeben werden braucht, da sie im Bereich von 0..n definiert sind, das erste
Element ist 0. An einem beliebigen Punkt in einer Aufzählung kannst Du
"=<Wert>" einsetzen um den Zähler auf einen Wert zu setzen oder rückzuset-
zen. Beispiele:
ENUM ZERO, ONE, TWO, THREE, MONDAY=1, TUESDAY, WENDSDAY
ENUM ER_NOFILE=100, ER_NOMEM, ER_NOWINDOW
Deklaration von Konstanten
}7C.
--------------
Sets sind den Aufzählungen ähnlich, mit dem Unterschied, daß anstatt einem
Wert wie (0,1,2..) eine Bitnummer hat (0,1,2...) die erhöht wird. So haben
Sets die Werte (1,2,4,8...). Das hat den zusätzlichen Vorteil, daß sie als
Sets von Flags benutzt werden können, wie das Schlüsselwort sagt.
Stellen wir uns ein Set wie oben vor, das die Einrichtung eines Fensters
beschreibt:
SET SIZEGAD, CLOSEGAD, SCROLLBAR, DEPTH
um eine Variabel mit den Werten DEPTH und SIZEGAD vorzubereiten:
winflags:=DEPTH OR SIZEGAD
um einen zusätzlichen SCROLLBAR einzurichten
winflags:=winflags OR SCROLLBAR
und testen ob zwei Einrichtung gehalten wurden
IF winflags AND (SCROLLBAR OR DEPTH) THEN /* */
Deklaration von Konstanten
}7D.
-----------------------
Folgende eingebaute Konstanten können benutzt werden:
TRUE, FALSE Repräsentiert die boolschen Wert Wahr und Falsch (-1,0)
NIL (=0) nicht initialisierter Pointer
ALL wird bei String-Funktionen wie StrCopy benutzt, damit
alle Zeichen kopiert werden.
GADGETSIZE kleinste Größe in Bytes um ein Gadget zu erhalten, siehe
auch Gadget() 9D
OLDFILE, NEWFILE Modusprameter beim benutzen von Open()
STRLEN Hat immer den Wert der zuletzt benutzten Zeichenkette.
Beispiel: Write(handle,'Hallo Leute!',STRLEN) /* =9 /*
Typen
}8.TYPEN@{uu}
B. Der Grundtyp (LONG/PTR)
C. Die einfachen Typen (CHAR/INT/LONG)
D. Der Feldtyp (ARRAY)
E. Die komplexen Typen (STRING/LIST)
F. Der Verbundtyp (OBJECT)
G. Einrichtung
Vorheriges Kapitel
Nächstes Kapitel
Typen
}8A.
--------------------------
E hat kein strenges Typen-System wie in Pascal oder Modula2, es ist sogar
flexibler als in C. Du kannst es auch ein Datentypen-System. Dies geht Hand
in Hand mit der Philosophie, daß alle Datentypen in E gleich sind: alle
kleinen Grundtypen wie Zeichen, Dezimalzahlen etc. Alle haben die gleichen
32 Bitgröße und alle anderen Daten und alle anderen Datentypen wie Felder
und Zeichenketten werden von auf einen 32 Bitzeiger auf sie. So kann der
Compiler einen vielseitigen Code generieren.
Die Vor- und Nachteile sind offensichtlich:
Nachteile des E-Typen-Systems:
- weniger Compiler-Überprüfungen für dumme Fehler von DIR!
Vorteile:
- Low-Level Vielseitigkeit
- flexible Programmgestaltung: kein Problem das einige Typen Werte zurück
geben die nicht zu anderen Aufrufe usw.
- es ist nicht schwer Fehler beim mischen von verschieden großer Daten in
Ausdrücken zu finden
- er werden immer noch selbstdokumentierende Typen unterstützt, wie:
PTR to newscreen
Typen
}8B.
---------------------------
Es gibt nur einen nicht komplexen Grundtyp in E, es ist der 32 Bit Typ LONG.
Da er der Defaulttyp ist, kann er so definiert werden:
DEF a:LONG oder nur DEF a
Diese Variabel kann das aufnehmen, was in anderen Programmiersprachen die
Typen CHAR/INT/PTR/LONG enthalten. Eine spezielle Art des LONG Typen ist
der PTR-Typ. Dieser Typ ist kompatibel mi dem LONG-Typen, mit dem Unter-
schied, daß angegeben wird, auf was er zeigt. Als Voreinstellung gilt, das
LONG als PRT TO CHAR angegeben wird. Syntax:
DEF <var>:PTR TO <Typ>
wobei Typ entweder ein einfacher oder ein zusammengesetzter Typ ist. Bei-
spiel:
DEF x:PTR TO INT, myscreen: PTR TO screen
Beachte, daß 'screen' der Name eines Objekts ist, das im Module intuition/
screens.m definiert ist. Zu Beispiel wenn Du Deinen eigenen Screen öffnest
mit:
myscreen:=OpenS(... usw.
kannst Du den Zeiger myscreen z.B. als 'myscreen.rastport' benutzen. Wenn
Du aber nichts mit den Variabeln machen willst, bis Du CloseS(myscree)
aufrufst, kannst Du sie so deklarieren:
DEF myscreen
Typen
}8C.
---------------------------------------
Die einfachen Typen CHAR(8 Bit) und INT (16 Bit) sollten nicht als Grund-
typen für (einzelne) Variabeln benutzt werden; der Grund dafür sollten
jetzt wohl klar sein. Trotzdem können sie als Datentypen zum Bilden von
Arrays benutzt werden. Sie können auch in Objektdefinitionen benutzt wer-
den, und man kann einen Zeiger auf sie setzen.
Typen
}8D.
-----------------------
ARRAYs werden über ihre Länge in Bytes definiert:
DEF b[100]:ARRAY
dies definiert ein Feld von 100 Bytes. Intern ist b eine Variabel des Typs
LONG und ein Zeiger auf diesen Speicherbereich. Standardmäßig ist der Typ
eines Feldelements CHAR, es kann aber jeder andere sein:
DEF x[100]: ARRAY OF LONG
DEF mymenus[10]:ARRAY OF newmenu
wobei "newmenu" ein Beispiel für eine Struktur ist, die in E OBJECT genannt
werden.
Der Feldzugriff ist sehr einfach mit <var>[<sexp>]:
b[1]:="a"
z:=mymenu[a+1].multiexclude
Bedenke das der Index eines Felds der Größe n von 0 bis n-1 und nicht von
1 bis n geht.
ARRAY OF <Typ> ist kompatibel mit PRT TO <Typ>, mit dem Unterschied das die
Variabeln die in einem Feld sind schon eingerichtet.
Typen
}8E.
-------------------------------------
- STRINGs. Ähnlich den Feldern, sind aber anders, weil sie nur von den E
Zeichkettenfunktionen geändert werden können, und das sie Größen- und
Maximalgrößenangaben enthalten. So können die E-Funktionen den String
auf sichere Art verändern. Z. B.: Der String kann nie größer werden als
der Speicherbereich, indem er steht. Definition:
DEF s[80]:STRING
Der String-Typ ist abwärtskompatibel mit PTR OF CHAR und natürlich mit
ARRAY OF CHAR, aber nicht andersherum. Mehr Details im Abschnitt über
Zeichenkettenfunktionen.
- LISTs. Diesen Datentyp gibt es in anderen prozedualen Programmiersprachen
nicht, es gibt ihn in Programmiersprachen wie Lisp oder Prolog. Die E-
Variante kann als Mischung zwischen STRING und ARRAY OF LONG interpre-
tiert werden. Zum Beispiel kann diese Datenstruktur eine Liste von LONG-
Variabeln aufnehmen, welche als STRINGs erweitert oder verkürzt werden
können. Definition:
DEF x[100]:LIST
Eine mächtige Erweiterung dieses Typs ist, daß er ein konstantes Gegen-
stück [], wie Zeichenketten mit '', hat. LIST ist abwärtskompatibel mit
PTR TO LONG und natürlich ARRAY OF LONG, aber nichts andersherum. In
Kapitel 2G und 9C steht mehr darüber.
Typen
}8F.
---------------------------
OBJECTs sind fast wie eine struct in C oder ein RECORD in Pascal. Beispiel:
OBJECT meinobject
a: LONG
b: CHAR
c: INT
ENDOBJECT
Dies definiert eine Struktur die aus drei Elementen. Syntax:
OBJECT
<Elementname>[:<Typ>] /*hiervon eine unbeschränkte Zahl*/
ENDOBJECT
wobei Typ wieder ein einfacher Typ, ein zusammengesetzter Typ oder ein
einfacher Feldtyp ist, z. B. [<Elementzahl>]:ARRAY mit der Größe von CHAR
für ein Element. Bedenke das <Elementname> nicht ein einzigartiger Identi-
fier sein muß, er kann auch in anderen Objekten enthalten sein. Es gibt
viele Arten um Objekte zu benutzen:
DEF x:meinobj /* x ist eine Strucktur*/
DEF y:PRT TO meinobj /* y ist ein Zeiger auf ein Struktur*/
DEF z[10]:ARRAY OF meinobj
y:=[-1,"a",100]:meinobj /*geschriebene Liste*/
IF y.b="a" THEN /*...*/
z[4].c:=z[d+1].b++
ARRAY in Objekten werden immer auf gerade Zahlen gerundet und werden auf
gerade Offsets gesetzt.
OBJECT meinstring
len:CHAR, daten[9]:ARRAY
ENDOBJECT
SIZEOF meinstring ist 12, und "daten" beginnt auf dem Offset 2.
Bedenke: OBJECTs in E sind nicht so wie sie in anderen Sprachen benutzt
werden können. Z. B. kann nicht jeder Typ ein Element eines Objekts bilden,
und deswegen machen rekursive Zugriffe wie x.y.z wenig Sinn (bis jetzt).
Typen
}8G.
---------------
1. Immer mit NIL eingerichtet (oder anders wenn extra angegeben)
-Globale Variabel
Bedenke: Für Dokumentationszwecke ist es immer besser wnn Du =NIL in
Definitionen von Variabeln schreibst, die du als NIL erwartest
2. Als '' oder [] eingerichtet:
-Globale und lokale STRINGs
-Globale und lokale LISTs
3. Nicht eingerichtet
-Lokale Variabel (wenn nicht extra angegeben)
-Globale und lokale ARRAYs
-Globale und lokale OBJECTs
Eingebaute Funktionen
}9.EINGEBAUTE
A. Ein-/Ausgabeoperationen
B. Zeichenketten und Zeichenkettenfunktionen
C. Listen und Listen Funktionen
D. Intuition unterstützende Funktionen
E. Grafikfunktionen
F. Systemfunktionen
G. Mathematische Funktionen
H. Funktionen zum Verbinden von Zeichenketten und Listen
Vorheriges Kapitel
Nächstes Kapitel
Eingebaute Funktionen
}9A.
---------------------------
WriteF(Formatzeichenkett, Argumente,...)
schreibt eine Zeichenkette (die Formatcodes enthalten kann) in den stdout.
Es können von keinem bis zu unendlich vielen Argumenten angefügt werden.
Bedenke, daß Formatzeichenketten dynamisch erzeugt werden können. Die An-
zahl der Argumente wird nicht überprüft. Beispiele:
WriteF('Hallo Welt!\n') /*schreibt nur eine Zeichenkette mit einem Zeilen-
vorschub am Ende*/
WriteF('a=\d\n',a) /*schreibt "a=123" wenn a=123 ist*/
Alles andere mußt Du unter dem Thema Strings nachschauen.
Wenn stdout=NIList, zum Beispiel wenn Dein Programm von der Workbench ge-
startet wir, erzeugt WriteF() ein Ausgabefenster, und schreibt den Handle
in conout und stdout. Dieses Fenster wird am Ende des Programms geschlossen,
nachdem der Anwender ein <Return> eingegeben hat. WriteF() ist die einzige
Funktion die dieses Fenster öffnet. als, wenn Du eine Ein-/Ausgabefunktion
über stdout machen willst, un nicht sicher weißt ob stdout<>NIL benutze ein
WriteF('') als ersten Befehl deines Programms um die Ausgabe sicher zu
stellen. Wenn Du selbst ein Consolen-Fenster öffnen willst, solltest Du den
resultierenden Filehandle in die 'stdout' und 'conout' Variabel schreiben,
da Dein Fenster so nach dem Programmende automatisch geschlossen wird. Wenn
Du das Fenster manuelle schließen willst, vergewisser Dich, daß Du 'conout'
wieder auf NIL gesetzt hast, um E anzuzeigen das es kein Console-Fenster
gibt, das geschlossen werden muß.
Out(filehandle, char) und char:=Inp(filehandle)
Schreibt oder ließt ein einzelnes Byte in/aus einem File oder stdout. Wenn
char=-1 ist, ist das Ende des Files erreicht oder ein Fehler ist aufgetre-
ten.
len:=FileLength(Namenstring)
Bestimmt die Länge eines Files, den Du vielleicht laden willst, und gibt
ebenso an, ob er existiert (gibt -1 zurück, wenn ein Fehler auftritt oder
der File nicht vorhanden ist.
ok:=ReadStr(filehandle, estring)
siehe Stringunterstützung
oldout:=StdOut(newstdout)
setzt die Standard-Output-Variabel 'stdout' auf den neuen Wert. Gleich mit:
oldout:=stdout; stdout:=newstdout
Eingebaute Funktionen
}9B.
---------------------------------------------
E hat einen Datentyp STRING. Dies ist ein String, von nun an 'EString' ge-
nannt, der in der Größe modifizier und verändert werden kann, als Gegen-
stück zu einem normalen 'String', welcher als durch ein Null-Byte beendete
Zeichenfolge benutzt wird. EStrings sind abwärtskompatibel, aber nicht an-
dersherum. Also wen ein Argument ein String erfordert, können beide benutzt
werden. Wenn ein EString erforderlich ist, kann nur ein solcher benutz wer-
den. Beispiele fü die Anwendung:
DEF s[80]:STRING /*s ist ein EString mit einer maximalen Länge von 80
Zeichen*/
ReadStr(stdout,s) /*ließt eine Eingabe von der Console*/
m:=Val(s,N) /*holt eine Nummer von der Console*/
Bei allen Zeichenkettenfunktionen bei denen Strings größer werden können
als ihr Maximum, werden Vorsichtsmaßnahmen getroffen.
DEF s[6]:STRING
StrAdd(s,'dieser String ist länger als 6 Zeichen',ALL)
s wird nur 'dieser' enthalten.
Ein String kann dynamisch aus dem Systemspeicher mit der Funktion String()
angefordert werden (der Zeiger hierfür muß auf NIL geprüft werden)
s:=String(maxlen)
DEF s[80] ist gleich mit DEF s und s:=String(10)
bool:=StrCmp(string,string,len)
vergleicht zwei Zeichenketten, len ist die Anzahl der Bytes, die verglichen
werden sollen, oder All, wenn die ganze Länge überprüft werden soll. Gibt
True oder False zurück.
StrCopy(estring,string,len)
kopiert den String in EString. Wenn len=ALL ist, wird alles kopiert.
StrAdd(estring,string,len)
genauso wie StrCopy(), nur das der String am Ende angehängt wird.
len:=StrLen(string)
berechnet die Länge eines Strings der durch ein Null-Byte abgeschlossen
wurde
len:=EstrLen(estring)
gibt die maximale Länge eines EStrings zurück.
RightStr(estring,estring,n)
Füllt den ersten EString mit den letzten n Bytes des zweiten EStrings.
MidStr(estring,string,pos,len)
kopiert jede beliebige Anzahl von Zeichen (alle eingeschloseen, wenn len=
All) von der Position pos im String in den EString.
WICHTIG: Bei allen stringverarbeitenden Funktionen ist zu Bedenken, daß das
erste Zeichen die Position 0 hat, und nicht 1, wie in normalen
Sprachen, wie Basic.
wert:=Val(string,read)
Findet eine Dezimalzahl im ASCII-Code codiert aus einr Zeichenkette. Führen-
de Leerzeichen/Tabulatoren werden übersprungen. Auch Hexadezimalzahlen
(1234567890ABCDEFabcdef) und Binärzahlen (01) können so gelesen werden,
wenn sie von einem "$"- oder "%"-Zeichen angeführt werden. Ein Minuszeichen
kann eine negative Zahl anzeigen. Val() gibt die Anzahl der gelesenen
Zeichen im zweiten Argument zurück, welches über Referenz (<-!!!) übergeben
werden muß. Wenn read den Wert 0 (wert wird auch 0 sein) hat, dann enthält
der String keine Dezimalzahl, oder der Wert ist zu groß um in 32 Bit auf-
genommen zu werden. "read" kann NIL sein.
Beispiel für Zeichenketten die korrekt übersetzt werden:
'-12345', '%10101010', '-$ABcd12'
diese würden in "wert" und der Variabel [read] eine 0 zurückgeben:
'', 'Hallo'
findepos:=IntStr(string1, string2, startpos)
sucht in string1 nach dem Vorkommen von string2. Es kann auch von einer
anderen Position als 0 gestartet werden. Zurückgegeben wird die *Addresse*,
an der der Unterstring gefunden wurde, ansonsten -1.
neuestringadr:=TrimStr(string)
gibt die *Addresse* des ersten Zeichen in einem String, z.B. nach führenden
Leerzeiche, Tabulatoren usw.
UperStr(string) und LowerStr(string)
ändert die Groß- und Kleinschreibung einer Zeichenkette.
BEACHTE: diese Funktion verändert die Elemente einer Zeichenkette. Deshalb
sollte man sie nur bei EStrings und Zeichenketten die ein Teil des Codes
sind verwenden. Effektiv heißt das, daß wenn Du eine Stringaddresse vom
Betriebssystem bekommen hast, mußt Du diesen erst mit StrCopy() in einen
String Deines Programms kopieren, und dann erst mit diesem Programm be-
nutzen.
ok:=ReadStr(filehandle, EString)
ließt eine String (mit ASCII 10 endent) aus einem File oder stdout. ok ent-
hält -1 wenn ein Fehler festgestellt oder das EOF erreicht wurde.
Bedenke: Die Elemente des Strings, die bis dahin gelesen wurden sind gültig.
SetStr(EString,neuelänge)
Setzt manuelle die Länge eines Strings. Dies ist nur nützlich, wenn Du Daten
in einen EString über nicht E-String-Funktionen ließ, und ihn als EString
weiter benutzen willst. Z. B. nach der Benutzung einer Funktion die nur
einen Null-Byte-Beendeten String auf die Addresse eines EStrings schreibt,
benutze SetStr(meinstr,StrLen(meinstr)) um ihn wieder manipulierbar zu
machen.
Für String-Zusammenführungsfunktionen siehe Kapitel 9H
Eingebaute Funktionen
}9C.
--------------------------------
Listen sind wie Strings nur das sie sich aus LONGs und nicht aus CHARs zu-
sammensetzen. Sie können auch entweder global, lokal oder dynamisch angefor-
dert werden:
DEF meineliste[100]:LIST /*lokal oder global*/
DEF a
a:=LIST(10) /*dynamisch*/
(beachte das im letzteren Fall der Zeiger a NIL enthalten kann). Genauso wie
Strings als Konstanten in Ausdrücken dargestellt werden können, haben Listen
ihr konstantes Equivalent:
[1,2,3,4]
Der Wert eines solchen Ausdrucks ist ein Zeiger auf eine fertig initalisier-
te Liste. Eine spezielle Eigenschaft ist, das sie dynamische Teile, z. B.,
welche während der Laufzeit gefüllt werden:
a:=3
[1,2,a,4]
außerdem können Listen auch einige andere Typen als die Voreinstellung LONG
enthalten, wie:
[1,2,3]:INT
[65,66,67,0]:CHAR /*gleich mit 'ABC' *
['topaz.font',8,0,0]:textattr
OpenScreenTagList(NIL,[SA_TITEL,'MeinScreen',TAG_DONE])
Wie im letzten Beispiel gezeigt, sind Listen extrem nützlich bei der Benut-
zung von Systemfunktionen: Sie sind abwärtskompatibel mit einem ARRAY OF
LONG, und auf ein Objektzeigende können überall dort benutzt werden, wo eine
Systemfunktion einen benutzt werden, wo eine Systemfunktion einen Zeiger auf
einige Strukturen oder ein Feld von Zeigern benötigt. Taglist und vararg-
Funktionen können auch auf diese Weise benutzt werden.
BEACHTE: Alle Funktionen arbeiten nur mit LONG Listen, typenzugeordnete
Listen sind nur geeignet um komplexe Datenstrukturen und Ausdrücke
aufzubauen.
Wie bei Strings gibt es eine klare Hierachie.
Listen Variabeln -> Konstante Liste -> Feld von Longs/Zeiger auf Longs
Wenn eine Funktion ein Feld von Longs braucht, kannst Du auch eine Liste als
Argument angegeben. Wenn aber eine Funktion eine Listenvariabel oder eine
konstante Liste braucht, reicht ein Feld von Longs nicht aus.
Es ist wichtig, daß Du die Mächtigkeit von Listen besonders typenorien-
tierter verstehst: dis kann Dir viel Ärger beim Aufbau irgendeiner Daten-
struktur ersparen. Versuche diese Listen in Deinen eigenen Programmen zu
benutzen und schauen welche Funktion sie in den Beispielprogrammen haben.
Wenn Du Listen einmal im Griff hast, möchtest Du niemals ein Programm ohne
sie schreiben.
Zusammenfassung:
[<Element>, <Element>,...] direkte Liste (von LONGs, Benutzung mit
Listenfunktion
[<Element>, <Element>,...]:<Typ> Typenorientierte Liste (nur um Daten-
strukturen zu bauen)
Wenn <Typ> ein einfacher Typ wie INT oder CHAR ist, hast Du nur das einge-
richtete Gegenstück zu ARRAY OF <Typ> ein Objektname ist erzeugst Du ein
eingerichtetes Objekt oder ARRAY OF <Objekt>, sich auf die Länge der Liste
stützend.
Wenn Du schreibst [1,2,3]:INT erzeugst Du eine Datenstruktur von 6 Bytes,
von 3 16 Bit Werten um genau zu sein. Der Wert eines solchen Ausdrucks ist
dann ein Zeiger zu einem Speicherbereich um genau zu sein. Es funktoniert
z. B. mit einem Objekt.
OBJECT meinobjekt
a:LONG, b:CHAR, c:INT
ENDOBJECT
wenn Du jetzt schreibst: [1,2,3]:meinobjekt würde dann eine Datenstruktur
von 8 Bytes im Speicher erstellen. Diese ersten vier Byte sind eine LONG-
Zahl mit dem Wert 1, das folgende Byte ist ein CHAR mit dem Wert 2, dann
ein Füllbyte, um die Wort-Anordnung zu erhalten (16 Bit). Es ist trotzdem
sehr wahrscheinlich, daß ein E-Compiler für eine 80x86 Architektur das Füll-
byte nicht nutzen wird und eine 7 Byte Struktur erzeugen wird. Und ein E-
Compiler für eine Sun-Sparc Architektur (wenn ich mich nicht vertue) wird
versuchen alles auf 32 Bit Grenzen zu stzen, so macht er eine 10 oder 12
Byte Struktur. Einige Mikroprozessoren (sie sind selten aber es gibt sie)
benutzen sogar (36:18:9) als Anzahl von Bits für ihre Typen (LONG:INT:CHAR)
anstatt von (32:16:8) wie wir es gewöhnt sind. Mache Dir kein zu großen
Vorstellungen der Struktur eines OBJECTS oder einer LISTe, wenn Du Code
schreiben willst, der eine Chance haben soll portabel zu sein oder sich auf
Seiteneffekte zu verlassen.
ListCopy(Listenvar,Liste,Anzahl)
Kopiert Anzahl Elemente aus Liste in die Listenvar. Beispiel:
DEF meineliste[10]:LIST
ListCopy(meineliste,[1,2,3,4,5],ALL)
ListAdd(Listenvariabel, Liste, Anzahl)
Kopiert Anzahl Elemente von Liste an die erste nicht belegte Stelle von
Listenvariabel
ListCmp(Liste, Liste, Anzahl)
Vergleicht zwei Listen, oder Anzahl Teile von ihnen.
länge:=ListLen(Liste)
Gibt die Länge der Liste zurück, wie ListLen([a,b,c]) 3 zurückgeben würde.
maximum:=ListMax(Listenvariabel)
Gibt die maximal mögliche Listenlänge von Listenvariabel zurück.
wert:=ListItem(Liste,Index)
funktioniert wie wert:=Liste[Index] mit dem Unterschied, daß Liste ein kon-
stanter Wert anstatt eines Zeiger sein kann. Dies kann in Situationen sehr
nützlich sein, in denen wir direkt ein Liste von Werten benutzen wollen:
WriteF(ListItem(['ok','kein Speicher','keine Datei'],fehler))
Es verhält sich wie:
dummy:=['ok','kein Speicher','keine Datei']
WriteF(dummy[fehler])
SetList(Listenvariabel, neuelänge)
setzt manuell die Länge einer Liste. Dies is nur nützlich, wenn Du mit nicht
listenspezifischen Funktionen Daten in eine Liste schreibst, sie aber als
richtige Liste weiterverwenden willst.
Für Listenfunktion, die ausgewertete Ausdrücke benutzen siehe Kapitel 11C.
Für Listenverbindungsfunktionen siehe Kapitel 9H
Eingebaute Funktionen
}9D.
---------------------------------------
wptr:=OpenW(x,y,Breite,Höhe,IDCMP,WFlags,Titel,Screen,SFlags,Gadgets)
erzeugt ein Fenster, wobei WFlags die Flags für das Windowlayout sind (wie
BACKDROP, SIMPLEREFRESH usw, normalerweise $F) und SFlags ist da um die
Screenart zu bestimmen auf der das Fenster geöffnet werden soll (1=WB,
15=Custom). Screen muß nur gültig sein, wenn SFlags=15, ansonsten reicht
NIL. Gadgets kann auf eine GList-Struktur zeigen, welche einfach mit Gad-
get() erzeugt werden kann, ansonsten NIL.
CloseW(wptr)
schließt das Fenster wieder. Der einzige Unterschied zu CloseWindow ist
das es NIL-Zeiger akzeptiert und den stdrast wieder auf NIL setzt.
sptr:=OpenS(Weite,Höhe,Tiefe,SFlags,Titel)
Öffnet einen Customscreen. Tiefe ist die Anzahl der Bitplanes (1-6, 1-8
AGA), SFlags ist etwas wie 0, oder $8000 für Hires (addiere 4 für Interlace)
CloseS(sptr)
wie CloseW(), nun für Screens.
nächsterbuffer:=Gadget(buffer,glist,id,flags,x,y,Breite,string)
Diese Funktion erstellt eine Liste von Gadgets, welche in Deinem Fenster
angezeigt werden können, in dem Du sie als Argument bei OpenW() als Argu-
ment übergibst. Später kannst Du das auch mit der Intuitionfunktion
AddGlist() erledigen.
Bufer ist meistens ein ARRAY on mindestens der GrößeGADGETSIZE Bytes um alle
Strukturen die zu einem Gadget gehören aufzunehmen. ID ist eine beliebige
Nummer die Dir helfen soll später zu erkennen welches Gadget gedrückt wurde,
wenn ine IntuiMessage ankommt. Flags sind 0=normal, 1=Boolean Gadget, 3=
Boolean Gadget das ausgewählt ist. Width ist die Weite in Pixeln, die groß
genug sein sollte um den String aufzunehmen, welcher automatisch zentriert
wird. Glist sollte beim ersten Gadget NIL sein, und glistvar für alle ande-
ren, so kann E alle Gadget zusammenlinken. Die Funktion gibt einen Zeiger
auf den nächsten Buffer zurück (=buffer+GADGETSIZE). Beispiel für 3 Gadgets:
CONST MAXGADGETS=GADGETSIZE*3
DEF buf[MAXGADGETS]:ARRAY, next, wptr
next:=Gadget(buf,NIL,1,0,10,20,80,'bla' /*das erste Gadget*/
next:=Gadget(next,buf...)
next:=Gadget(next,buf...) /*jede Anzahl kann zum ersten gelinkt werden*/
wptr:=OpenW(...,buf)
Schaue Dir die richtigen Beispiele wie SuperVisor.e für richtige Anwendugen
an.
code:=Mouse()
gibt Dir den momentanen Status von allen 2 oder 3 Mausknöpfen zurück, links
=1, rechts=2 und mitte=4. Wenn der Code z.B. gleich 3 ist, sind die linke
und die rechte Maustaste gedrückt.
WICHTIG: die ist keine richtige Inituition-Funktion, wenn Du auf regulären
Weg etwas über die Maus-Events erfahren willst, muß Du die IntuiMessages
kontrollieren, die an Deinem Window ankommen. Das ist die einezige E-Funk-
tion die direkt auf die Hardware zugreift, und ist deshalb nur für demo-
artige Programme nützlich:
x:=MouseX(win) und y:=MouseY(win)
ermöglicht es Dir die Mauskoordinaten zu lesen. Win ist das Window zu dem
sie relativ sind.
class:=WaitIMessage(window)
Diese Funktion macht es einfacher auf ein Window-Event zu warten. Es spei-
chert andere Variabeln wie Cod und Qualifiers als private, globale Varia-
beln, für den Zugriff mit Funktionen, die unten beschrieben werden.
WaitIMessage() representiert folgenden Code:
PROC waitimessage(win:PTR TO window)
DEF port,mes:PTR TO intuimessage,class,code,qual,iaddr
port:=win.userport
IF (mes:=GetMsg(port))=NIL
REPEAT
WaitPort(port)
UNTIL (mes:=GetMsg(port))<>NIL
ENDIF
class:=mes.class
code:=mes.code /* intern abgespeichert */
qual:=mes.qualifier
iaddr:=mes.iaddress
ReplyMsg(mes)
ENDPROC class
wie Du siehst, holt es exakt eine Nachricht, und vergißt keinen mehrfach
Message, die bei einem Ereigniss ankommt. Wenn mehr als ein Aufruf erfolgt.
Zum Beispiel, sagen wir Du hast ein Window geöffnet, das etwas anzeigt, und
nur auf das Cosegadget wartet (Du hast nur IDCMP_CLOSEWINDOW angegeben):
WaitMessage(meinwindow)
oder Du hast ein Programm das auf mehrere Arten von Events wartet, sie in
einer Schleife bearbeitet, un mit einem Closewindow-Event endet:
WHILE (class:=WaitIMessag(win))<>IDCMP_CLOSWINDOW
/*Bearbeitung der anderen Klassen */
ENDWHILE
code:=MsgCode() qual:=MsgQualifier() iaddr:=MsgIaddr()
Dies alles versorgt Dich mit den privaten globalen Variabel, die vorher er-
wähnt wurden. Die Werte die zurückgegeben werden, wurden alle vom letzten
Aufruf von WaitIMessage() definiert. Beispiel:
IF class:=IDCMP_GADGETUP
mygadget:=MsgIaddr()
If mygadget.userdata=1 THEN /* der Anwender hat Gadget #1 gedrückt*/
ENDIF
Eingebaute Funktionen
}9E.
--------------------
Alle grafikunterstützenden Funktionen, die nicht extra einen Rastport ver-
langen, benutzen die System-Variabel 'stdrast'. Sie wird automatisch vom
letzten Aufruf von OpenW() oder OpenS() definiert, und wird von CloseW()
und CloseS() auf NIL gesetzt. Der Aufruf dieser Routinen, während 'stdrast'
NIL ist, ist erlaubt. stdrast kann manuelle über SetStdRast() oder stdrast:=
meinrast geändert werden.
Plot(x,y,Farbe)
Malt einen einzelnen Punkt auf Deinem Screen/Window in einer der verfügbaren
Farben. Die Farbe geht von 0-255, oder 0-31 auf vor-AGA Maschinen.
Line(x1,y1,x2,y2,Farbe)
Malt eine Linie.
Box(x1,y1,x2,y2,Farbe)
Malt ein Rechteck.
Colour(Vordergrund, Hintergrund)
setzt die Farbe für alle Grafikfunktionen (aus dem Library), die kein Farb-
argumente annehmen. Dies ist das *Farbregister* (z.B. 0-31) und nicht der
*Farbwert*.
BEACHTE: Funktionen, die ein "Farbe" als Argument haben, verändern den Apen
des stdrast.
TextF(x,y,Formatstring,args,....)
hat genau dieselbe Funktion wie WriteF(), nur an irgendeiner (x,y) Position
in deinem stdrast, anstatt von stdout. Siehe auch WriteF() und Strings in
der Sprachbeschreibung.
alterrast:=SetStdRast(neuerrast)
verändert den Ausgaberastprot der E-Grafik-Funktionen.
SetTopaz(größe)
setzt den Font des Rastport "stdras" auf Topaz, nur um sicher zu sein, daß
einige Custom-Fonts des Anwenders nicht unser Bildschirmlayout durchein-
ander werfen. Größe ist natürlich 8 oder 9.
Eingebaute Funktionen
}9F.
--------------------
bool:=KickVersion(vers)
Gibt TRUE zurück, wenn die Kickstart in der Maschine, auf der Dein Programm
läuft, gleich oder größer ist, ansonsten FALSE.
mem:=New(n)
Dies erzeugt dynamisch ein Feld (oder Speicherbereich, wenn Du möchtest) von
n Bytes. Unterschiede zu AllocMem() sind, daß es automatisch die Flaggs
$10000 (also gelöschter Speicher, jeder Typ) angibt und keine Dispose()
Aufrufe notwendig sind, da es an eine Speicherliste angefügt wird, die auto-
matisch am Ende des Programms freigegeben wird.
Dispose(mem)
Gibt jedes mem frei, das durch New() angefordert wurde. Du muß diese Funk-
tion nur benutzen, wenn Speicher während des Programmablaufs freigegeben
werden soll, da es am Ende sowieso freigegeben wird.
CleanUp(Rückgabewert)
Beendet das Programm von jeden Punkt. Es ist der Ersatzt für den DOS-Aufruf
Exit(): benutze diesen niemals!!!!!! anstatt von CleanUp(), welcher es
ermöglicht Speicher freizugeben, Libraries richtig zu schließen usw. Der
Rückgabewert wird als Returncode an DOS zurückgegeben.
menge:=FreeStack
gibt die Menge des freien Stackspeichers zurück. Diese sollte immer 1000
oder mehr betragen. Siehe in Kapitel 16 wie E seinen Stack organisiert.
Wenn Du nicht im Rekursionswahn bist, brauchst Du Dir über den freien Stack-
Speicher keine Sorgen zu machen.
bool:=CtrlC()
Gibt TRUE zurück, wenn Ctrl-C nach der letzten Überprüfung gedrückt wurde,
ansonsten FALSE. Dies arbeitet nur mit Programmen, die über die Console
laufen, d.h. CLI-Programme.
/*berechnet die Fakultät des CLI-Arguments*/
OPT STACK=100000
PROC main()
DEF num,r
num:=Val(arg,{r})
IF r=0 THEN WriteF('Argumentfehler.\n') ELSE WriteF('Wert: \d\n',fac(num))
ENDPROC
PROC fac(n)
DEF r
IF FreeStack()<1000 OR CtrlC() THEN CleanUp(5) /* Extra Controlle */
IF n=1 THEN r:=1 ELSE r:=fac(n-1)*n
ENDPROC r
Natürlich wird diese Rekursion kaum den Stack zum überlaufen bringen, und
wenn dies passiert, wird es so schnell von FreeStack() angehalten, das Du
keine Zeit hast Ctrl-C zu drücken, aber es ist die Idee die hier zählt.
Eine Definition von fac(n) wie:
Proc fac(n) RETURN IF n=1 THEN 1 ELSE fac(n-1)*n
wäre nicht so sicher.
Eingebaute Funktionen
}9G.
----------------------------
a:=And(b,c) a:=Or(b,c) a:=Not(b)
a:=Eor(b,c)
Diese arbeiten mit den normalen Operatoren, boolschen genauso wie aritme-
thische. Beachte, daß für And() und Or() Operatoren existieren:
a:=Mul(b,c) a:=Div(a,b)
Macht dasselbe wie die '*' und '/' Operatoren, aber jetzt mit vollen 32 Bit.
Aus Geschwindigkeitsgründen sind normale Operationen 16 Bit * 16 Bit =
32 bit und 32 Bit/ 16 Bit = 16 Bit. Dies reicht für fast alle Rechnungen aus
und wo nicht, kannst Du Mul() und Div() benutzen. BEACHTE: im Fall von Div()
wird a durch b geteilt und nicht umgekehrt.
bool:=Odd(x) bool:=Even(x)
Gibt TRUE oder FALSE zurück wenn ein Ausdruck gerade oder ungerade ist.
randnum:=Rnd(max) seed:=RndQ(seed)
Rnd() berechnet eine Zufallszahl aus einer Internen seed im Raum von 0..
max-1. Zum Beispiel, Rnd(1000) gibt eine Dezimalzahl von 0..999 zurück. Um
die Interne Quelle zu Initalisieren, rufe Rnd() mit einem negativen Wert
auf. Der Abs() dieses Werts wird dann als Ursprungs'seed' genommen.
RndQ() berechnet eine Zufallszahl schneller als Rnd(), aber gibt nur ganze
32 Bit Zufallszahlen zurück. Benutze das Ergebniss als seed für den nächsten
Aufruf, und als Anfangs'seed' benutze einen großen Wert wie $AGF87EC1
abswert:=Abs(wert)
berechnet den absoluten Wert.
a:=Mod(b,c)
Dividiert 32 Bit b durch 16 Bit c und gibt den 16 Bit Modulo a zurück.
x:=Shl(y,num) x:=Shr(y,num)
Schiebt y um num Bits nach links oder nach rechts.
a:=Long(adr) a:=Int(adr) a:=Char(adr)
Ließt aus einer Speicheraddresse einen Wert und gibt ihn zurück. Dies geht
mit 32, 16 und 8 Bit Werten in dieser Reihenfolge. Der Compiler überprüft
nicht ob die Addresse gültig ist. Diese Funktionen sind in E verfügbar für
den Fall, daß das Lesen und Schreiben im Speicher mit PTR TO <Typ> das Pro-
gramm nur noch komplexer und uneffizienter machen würde. Du solltest aber
nicht dazu ermutigt werden, diese Funktionen zu benutzen.
PutLong(adr,a) PutInt(adr,a) und PutChar(adr,a)
Poket (schreibt) den Wert 'a' in den Speicher, Siehe auch Long()
Eingebaute Funktionen
}9H.
---------------------------------------------------------
E ist mit einer Reihe von Funktionen ausgestattet, die die Erstellung von
verketteten Listen mit dem STRING und LIST Datentyp, oder Strings und
Listen, die mit String() und List() erstellt wurden, erlaubt. Wie Du viel-
leicht weißt, sind Listen, Strings, komplexe Datentypen Zeiger auf ihre
verschiedenen Daten, und haben ein extra Feld an einem negativen Offset
dieses Zeigers die ihre aktuelle und ihre maximale Länge enthält. Die Off-
sets dieses Feld sind PRIVATE. Als Zusatzt zu diesen beiden, hat jeder
komplexe Datentyp ein 'next' Feld, welches Defaultmäßig auf NIL gesetzt ist.
Dieses kann benutzt werden, um verkettete Listen zu erzeugen, z.B. von
Strings. Ab jetzt verstehe ich unter komplex einen ptr auf einen STRING
oder eine LISTe, und unter 'tail' noch einen solchen Zeiger, oder einen
der schon einen solchen String anghängt hat. 'tail' kann auch ein NIL Zeiger
sein, der das Ende einer verketteten Liste anzeigt. Die folgenden Funktionen
können benutzt werden.
komplex:=Link(komplex,tail)
schreibt den Wert von tail in das 'next'-Feld von komplex. Beispiel:
DEF s[10]:STRING, t[10]:STRING
Link(s,t)
erzeugt eine verkettete Liste wie: s-->t-->NIL
tail:=Next(komplex)
ließt das 'next' Feld einer komplexen Variabel. Dies kann natürlich NIL
sein, oder eine komplett verkettete Liste. Next(NIL) aufrufen ergibt NIL,
so ist es sicher Next aufzurufen, wnn man sich nicht sicher ist ob man am
Ende einer verketteten Liste ist.
tail:=Forward(c,1)
genau dasselbe, geht nur um num Links vorwärts, anstatt von einem, also:
Next(c)=Forward(c,1)
Du kannst Forward sicher mit Nummern aufrufen, die zu weit gehen; Forward
hält an sobald es ein NIL beim suchen eines Links entdeckt und gibt NIL
zurück.
DisposeLink(complex)
dasselbe wie Dispose(), mit dem Unterschied: es ist nur für Strings und
Listen die mit String() und List() angefordert wurden, und entfernt auto-
matisch den 'tail' eines komplexen Datentyps. Beachte, daß in große verket-
teten Listen, die Strings enthalten, die sowohl mit String() als auch einige
lokal und global mit STRING allociert wurden können auch auf diese Art
freigegeben werden.
Für ein gutes Beispiel, wie man Listen von Strings gut im wirklichen Leben
gebrauchen kann, siehe 'D.e'.
Library Funktionen und Module
}10.LIBRARY
A. Eingebaute Library Aufrufe
B. Schnittstellen zum Amiga Sytem mit den 2.04 Modulen bilden
Vorheriges Kapitel
Nächstes Kapitel
Library Funktionen und Module
}10A.
-------------------------------
Wie Du vielleicht schon aus den vorherigen Abschnitten weißt, wird vor Dein
Programm automatisch um ein Programmteil (der "initialisation code") ergänzt,
der beim Programmstart immer folgende vier Bibliotheken öffnet: Intuition,
Dos, Graphics und Mathffp. Daher sind die Funktionsaufrufe zu diesen fünf
Bibliotheken (Exec eingeschlossen) im Compiler integriert (es sind einige
Hundert). Jedenfalls bis zu AmigaDos v2.04, v3.00 sollte bis zur nächsten
Version von Amiga E implementiert sein. Um Open() von der dos.library
aufzurufen, genügt ein schlichtes:
handle:=Open('meinedatei',OLDFILE)
oder AddDisplayInfo() von graphics.library:
AddDisplayInfo(meindispinfo)
So einfach ist das.
Library Funktionen und Module
}10B.
---------------------------------------------------------------
Um eine beliebige andere Bibliothek als die fünf im vorherigen Abschnitt
genannten zu benutzen, mußt Du Module wählen. Du brauchst auch Module, wenn
Du - wie in C oder Assembler üblich - OBJECT oder CONST Definition aus den
Amiga-Includes benutzt. Module sind Binärdateien, die Definitionen von
Konstanten, Objekten, Bibliotheken und Funktionen (code) beinhalten können.
Die Tatsache, daß sie binär vorliegen, hat den ASCII-Dateien (benutzt in C
und Assembler) gegenüber den Vorteil, daß sie nicht jedesmal neu compiliert
werden müßen, wenn Dein Programm neu compiliert wird. Der Nachteil ist, daß
man sie sich nicht einfach anschauen kann; um ihren Inhalt sichtbar zu
machen, ist ein Utility wie ShowModule (siehe utility.doc) nötig. Die
Module, die die Bibliotheksdefinitionen (d.h. deren Aufrufe) enthalten,
stehen im Wurzelverzeichnis von emodules: (dem Modul-Verzeichnis in der
Distribution), die Definitionen der Konstanten/Objekte befinden sich in den
Unterverzeichnissen, sie sind wie die Originale von Commodore aufgebaut.
MODULE
Sytax: MODULE <Modulname>,...
Lädt ein Modul. Ein Modul ist eine Binärdatei, die Informationen über
Bibliotheken, Konstanten und manchmal auch Funktionen enthält. Durch
Modulbenutzung ist es Dir möglich, Bibliotheken und Funktionen zu benutzen,
die dem Compiler vorher nicht bekannt waren.
Nun zu einem Beispiel, unten steht ein kleine Version des Sources
sources/examples/asldemo.e, das Module verwendet, um einen Filerequester
der 2.0 Asl.library darzustellen.
MODULE 'Asl', 'libraries/Asl'
PROC main()
DEF req:PTR TO filerequestr
IF aslbase:=OpenLibrary('asl.library',37)
IF req:=AllocFileRequest()
IF RequestFile(req) THEN WriteF('File: "\s" in "\s"\n',req.file,req.dir)
FreeFileRequest(req)
ENDIF
CloseLibrary(aslbase)
ENDIF
ENDPROC
Aus dem Modul 'asl' erfährt der Compiler die Definitionen der
asl-Funktionen, wie zum Beispiel RequestFile(), und die globale Variable
'aslbase', die vom Programmierer lediglich initialisiert werden muß. Aus
'libraries/asl' erfährt er die Definition des Objektes filerequestr, das
wir benutzen, um zu erfahren, welche Datei der Anwender ausgewählt hat.
Das war doch nun wirklich nicht schwer: hast Du gedacht, daß es so einfach
wäre, einen Filerequester in E zu programmieren?
Ausgewertete Ausdrücke
}11.AUSGEWERTETE
A. Auswertung und Bereich
B. Eval()
C. Eingebaute Funktionen
Vorheriges Kapitel
Nächstes Kapitel
Ausgewertete Ausdrücke
}11A.
---------------------------
Quotierte Ausdrücke beginnen mit dem Hochkomma. Der Wert eines ausgewerteten
Ausdrucks ist nicht das Ergebniss von einer Berechnung eines Ausdrucks, son-
dern die Adddresse des Codes. Dieses Ergebniss kann als eine normale Varia-
bel weiterverwendet werden, oder als ein Argument für bestimmte Funktionen.
meinefunk:=`x*x*x
meinefunk ist nun ein Zeiger auf eine Funktion die x^3 berechnet, wenn sie
berechnet wird. Diese Zeiger auf Funktionen sind sehr unterschiedlich zu
normalen PROCs, und Du solltest die beiden nie durcheinander bringen. Die
größten Unterschiede sinde, daß quotierte Ausdrücke nur einfache Ausdrücke
sind, und deshalb keine eigenen lokalen Variabeln haben kann. In unserem
Beispiel ist "x" nur eine lokale oder globale Variabel. Das ist warum vor-
sicht sein muß: Wenn meinefunk irgendwo später gleichen PROC auswertest,
kann x lokal sein, aber wenn meinefunk als Parameter an einen anderen PROC
übergibst, und dann auswertest, muß x natürlich global sein. Es gibt keine
Bereichsprüfung hierbei.
Ausgewertete Ausdrücke
}11B.
-----------
Eval(funk)
wertet einfach einen quotierten Ausdruck (exp=Eval('exp)) aus.
BEDENKE: Weil E eine etwas typenlose Sprache ist, wird vom Compiler dummer-
weise nicht bemerkt, wenn wir "Eval(x*x)" anstatt von "Eval(`x*x)" schrei-
ben, und das macht Dir große Laufzeitprobleme: der Wert von x*x wird als
Zeiger auf Code benutzt.
Um zu verstehen warum "quotierte Ausdrücke" so mächtig sind, danke an die
folgenden Fälle: wenn Du eine Reihe von Aktionen mit einer Reihe von Varia-
beln abarbeiten mußt, schreibst Due eine Funktion und rufst die Funktion
mit verschiedenen Argumenten auf. Aber was ist, wenn das Argument ein Teil
des Codes ist. In traditionellen Programmiersprachen wäre dies nicht mög-
lich, so müßtest Du die Blöcke die Deine Funktion repräsentieren "kopieren",
und dann den Ausdruck hineinschreiben. Nicht in E. Sagen wir, Du möchtest
ein Programm schreiben, das die Arbeitungszeit von verschiedenen Ausdrücken
vergleicht. In E würdest Du einfach nur schreiben:
PROC timing(funk,titel)
/*macht alle Dinge um die Zeit zu stellen+/
Eval(funk)
/*und den Rest*/
Write('Die gemessene Zeit von \s war \d\n',titel,t)
ENDPROC
und rufen es auf mit:
timing (`x*x*x,'Multiplication')
timing (`großeberechnung(),'Große Rechnung')
in jeder anderen Befehlssprache, müßtest Du für jeden timing-Aufruf eine Ko-
pie schreiben, oder Du müßtest jeden Ausdruck in eine seperate Funktion
schreiben. Dies ist nur ein einfaches Beispiel: denke daran, was Du mit Da-
tenstrukturen (LISTs) mit unausgewerteten Code machen kannst.
malfunks: [`Plot(x,y,c), `Line(x,y,x+10,y+10,c), `Box(x,y,x+20,y+20,c)]
Die Idee von Funktionen als normale Variabeln/Werten ist keine Neuheit von
E. Quotierte Ausdrücke wurden von LISP beschrieben, welche auch noch etwas
mächtigeres, Lambda Funktionen genannt, hat, was auch als Argument an Funk-
tionen übergeben wird. E`s quotierte Ausdrücke können auch als parameterlo-
se (oder nur globale Parameter) Lambdas angesehen werden.
Ausgewertete Ausdrücke
}11C.
--------------------------
MapList(variabeladr,liste,listenvar,funk)
unterstützt einige Funktionen auf alle Elemente von liste und gibt alle Er-
gebnisse in listenvar zurück. funk muß ein quotierter Ausdruck sein (siehe
oben) und variabel (im welchen Bereich der liste) muß als Referenz überge-
ben werden.
MapList([x],[1,2,3,4,5],r,`x*x) ergibt in r:[1,4,9,16,25]
ForAll(variabeladr,liste,funk)
Gibt TRUE zurück, wenn alle Werte in liste die Funktion (quotierter Aus-
druck) zu TRUE verarbeiten, ansonsten FALSE. Kann auch benutzt werden, um
eine bestimmte Funktion auf alle Elemente einer Liste abzuarbeiten.
ForAll([x],['eins','zwei','drei'],`WriteF('Beispiel: \s\n',x)
Exists(variabeladr,liste,funk)
Wie ForAll(), nur diese gibt TRUE zurück, wenn irgend ein Element TRUE(<>)
ergibt. Beachte, daß ForAll() immer alle Elemente berechnet, aber Exists()
möglicherweise nicht.
Beispiele, wie man diese Funktionen auf eine spezielle Art und Weise be-
nutzt:
wir allozieren verschiedene Größen von Speicher in einem Statement, über-
prüfen Sie alle auf einmal und geben nur die frei, die erfolgreich angefor-
dert wurden. (Beispiel für v37+)
PROC main()
LOCAL mem[4]:LIST,x
MapList({x},[200,80,10,2500],mem,`AllocVec(x,0)) /* einige allozieren */
IF ForAll({x},mem,`x) /* Erfolg ? */
WriteF('Yes!\n')
ELSE
WriteF('No!\n')
ENDIF
ForAll({x},mem,`IF x THEN FreeVec(x) ELSE NOP) /* nur die <>NIL frei-
geben*/
ENDPROC
Beachte das fehlen von Wiederholungen in diesem Code. Versuche doch einfach
dieses Beispiel in irgendeiner anderen Programmiersprache zu schreiben, und
siehe warum dies besonders ist.
Fließkommaunterstützung
}12.FLIEßKOMMAUNTERSTÜTZUNG@{uu}
B. Fließkommaausdrüke und Umwandlungen
Vorheriges Kapitel
Nächstes Kapitel
Fließkommaunterstützung
}12A.
--------------------------------------------------------
Das überladen der standard Operatoren + * usw mit den fließkomma Gegen-
stücken ist seit der E Version 2.0 möglich, aber ich habe die Hauptdokumen-
tation davon entfernt, da wahrscheinlich das Fließkommakonzept ab der Ver-
sion v2.2 oder später sich ändern wird: diese Version wird dann 68881 In-
line-Code neben den normalen FFP-Routinen in einer transparenten Art er-
lauben.
Wenn Du wirklich Fließkommazahlen benutzen willst, mußt Du die eingebauten
SpXxx()-Routinen des mathffp.library benutzen.
Beispiel
x:=SpMul(y,0.013483)
Sei Dir bewußt, daß wenn v2.5 rauskommt, Dein Code vielleicht geändert wer-
den muß. (Für die besseren)
Fließkommaunterstützung
}12B.
----------------------------------------
wie 12A.
Exception Behandlung
}13.EXCEPTION
A. Definition von Exceptionhandlern (HANDLE/EXCEPT)
B. Benutzung der Raise() Funktion
C. Exceptions für eingebaute Funktionen (RAISE/IF)
D. Benutzung von Exception-ID's
Vorheriges Kapitel
Nächstes Kapitel
Exception Behandlung
}13A.
-----------------------------------------------------
Der Ausnahme Mechanismus in E ist hauptsächlich der gleiche wie in ADA;
es steht für flexible Reaktionen auf Fehler in deinem Programm und
komplexe Ressourcen Leitung. Beachte: der Ausdruck 'exeption' in E hat
sehr wenig zu tun mit Ausnahmen ("GURUS"), die vom 680x0 Prozessor verursacht werden!
Ein Exeption-Handler ist ein Stück des Programm-Codes, daß aufgerufen wird,
wenn Laufzeitfehler geschehen, solche wie erfolgloses Öffnen von Fenstern
oder Speicher, der nicht mehr verfügbar ist. Du, oder das Laufzeit-System
selber, dürfen Signalisieren, daß etwas falsch ist (diese wird "Reaktion
auf einen Ausnahmezustand genannt), und dann wird das Laufzeit-System
versuchen, den zutreffenden Ausnahme Handler zu finden.
Ich sage "zutreffend", weil ein Programm mehr als einen Ausnahme Handler
enthalten kann, auf allen Stufen eines Programmes.
Eine normale Funktionen-Definition darf (wie wir alle wissen) folgendermaßen
ausschauen:
PROC bla()
/* ... */
ENDPROC
Eine Funktion mit einem Ausnahme Handler sieht wie diese aus:
PROC bla() HANDLE
/* ... */
EXCEPT
/* ... */
ENDPROC
Der Block zwischen PROC und EXCEPT wird normal ausgeführt, und wenn keine
Ausnahme passiert ist, wird der Block zwischen EXCEPT und ENDPROC
übersprungen, und die Prozedur wird bei ENDPROC verlassen.
Wenn eine Ausnahme passiert, entweder im PROC-Abschnitt oder in
irgendeiner Funktion, die in dem Block aufgerufen wurde, dann wird der
Ausnahme-Handler ausgelöst.
Exception Behandlung
}13B.
-----------------------------------
Es gibt viele Wege um ein Ausnahme-Situation auszulösen, der einfachste
ist der über die Funktion Raise():
Raise(exceptionID)
Die exeptionID ist einfach eine Konstante die den Typ der Ausnahme
definiert und wird benutzt von Ausnahme-Handlern, um zu untersuchen,
was schief gegangen ist.
Beispiel:
ENUM NOMEM,NOFILE /* und andere */
PROC bla() HANDLE
DEF mem
IF (mem:=New(10))=NIL THEN Raise(NOMEM)
myfunc()
EXCEPT
SELECT exception
CASE NOMEM
WriteF('Kein Speicher!\n')
/* ... und anderes */
ENDSELECT
ENDPROC
PROC myfunc()
DEF mem
IF (mem:=New(10))=NIL THEN Raise(NOMEM)
ENDPROC
Die "Ausnahme"-Variable im Handler beinhaltet immer den Wert des Arguments,
das durch den Aufruf der Raise()-Funktion übergeben worden ist.
In beiden New()-Fällen übergab die Raise()-Funktion dem Handler der
Funktion bla(), und dann ging es richtig zurück zum Aufrufer von bla().
Wenn myfunc() einen eigenen Ausnahme-Handler hätte würde dieser aufegrufen
werden für den New()-Funktionsaufruf in myfunc(). Der Umfang eines Ausnahme-
Handler ist vom Start der PROC, in welcher er definiert wurde, bis zum
EXCEPT-Schlüsselwort, einschliesslich alle Aufrufe, die von hier gemacht
werden.
Dieses hat drei Konsequenzen:
A. Handler sind rekursiv organisiert, und welcher Handler eigentlich
aufgerufen wird ist abhängig von dem Fuknktionsaufruf bei
Programmausführung;
B. wenn eine Ausnahme in einem Handler ausgelöst wird, dann wird der Handler
einer niedrigeren Stufe ausgeführt. Dieses Verhalten der Handler
darf benutzt werden, um komplex zusammengesetzte rekursive
Zuteilungsarien mit großartig Bequemlichkeit zu benutzen, wie wir in
Kürze sehen werden.
C. Wenn eine Ausnahme ausgelöst wird auf einer Stufe, in der kein
niedriger "Stufen"-Handler verfügbar ist (oder in einem Programm, daß
keinen Handler bekommen hat), dann wird das Programm abgebrochen
Z.B.: Raise(x) hat den gleichen Effekt wie CleanUp(0)
Exception Behandlung
}13C.
----------------------------------------------
Mit Ausnahmen, wie zuvor beschrieben, haben wir etwas Bedeutendes erreichet
Über den alten Weg der Definition unserer eigenen "Fehler()"-Funktionen,
aber dennoch gibt es eine Menge einzugeben, um NIL bei jedem Aufruf von
New() zu prüfen.
Das E-Ausnahme-Laufzeitsystem erlaubt Definition von Ausnahmen
für alle E Funktionen (wie New(), OpenW() usw..), und für alle Library
Funktionen (OpenLibrary(), AllocMem() usw..), sogar für eingebundene Module.
Syntax:
RAISE <exceptionId> IF <Funktion> <Vergleich> <Wert> , ...
der Teil nach RAISE darf wiederholt werden mit einem ",".
Beispiel:
RAISE NOMEM IF New()=NIL,
NOLIBRARY IF OpenLibrary()=NIL
die ersten Zeilen sagen etwas wie "immer wenn ein Aufruf von New()
in NIL resultiert, dann rufe automatisch die NOMEM Ausnahme auf".
<Vergleich> kann irgendetwas wie = <> > < >= <= sein.
Nach dieser Definition dürfen wir alles über unser Programm schreiben:
mem:=New(size)
ohne zu schreiben:
IF mem=NIL THEN Raise(NOMEM)
Beachte, daß der einzige Unterschied ist, daß "mem" nie einen Wert bekommt,
wenn das Laufzeit-System den Handler aufruft: Code wird erzeugt für
jeden aufruf zu New() um nach der Rückkehr von New() zu prüfen
und evtl. Raise() aufzurufen, wenn dieses notwendig ist.
Wir haben jetzt ein kleines Beispiel, daß komplex genug ist, um ohne
Ausnahme-Handling auszukommen: wir rufen eine Funktion rekursiv auf und
in jedem Aufruf teilen wir eine Ressource zu (in diese Fall Speicher),
welchen wir vorher allokiert haben, und führen danach den rekursiv Aufruf
aus.
Was geschieht, wenn irgendwo oben in der Rekursion ein Fehler entsteht und
wir das Programm zu verlassen haben?
Richtig: wir würden (in einer konventionellen Sprache) nicht die niedrigeren
Resourcen freibekommen, während wir das Programm verlassen, weil alle
Zeiger zu diesem Speicher in unerreichbaren lokalen Variablen hinterlegt
sind!
In E erhöhen wir einfach eine Ausnahme und von dem Ende des Handlers
erhöhen wir wieder eine Ausnahme, so daß wir alle Handler Rekursiv aufrufen
und alle Resourcen freigeben.
Beispiel:
CONST SIZE=100000
ENUM NOMEM /* ,... */
RAISE NOMEM IF AllocMem()=NIL
PROC main()
alloc()
ENDPROC
PROC alloc() HANDLE
DEF mem
mem:=AllocMem(SIZE,0) /* sehen, wie viele Blöcke wir bekommen
können */
alloc() /* und jetzt die Rekursion .... */
FreeMem(mem,SIZE) /* wir werden nie hierher kommen ... */
EXCEPT
IF mem THEN FreeMem(mem,SIZE)
Raise(exception) /* Rekursiver Aufruf aller Handler */
ENDPROC
Dieses ist, natürlich, eine Simulation eines natürlichen Programm-Problem,
daß gewönlich komplexer ist, und soll auch nur den Gebrauch der
Ausnahme-Benutzung darstellen. Für ein echtes Beispiel Programm würde das
Fehlerhandling ohne Ausnahmezustände wesentlich schwieriger werden,
siehe auch das 'D.e'-Utility Programm.
Exception Behandlung
}13D.
---------------------------------
Im echten Leben ist die Ausnahme-ID ein normaler 32-Bit-Wert
und du darfst alles mögliche an einen Ausnahme-Handler geben, z.B.
um es als Ausgabe für fehlerhafte Strings zu nutzen:
Raise('Could not open "gadtools.library"!')
Wie auch immer, wenn du die Ausnahmen in einer ausführbaren Weise
nutzen möchtest und Du möchtest auch zukünftige Module nutzen,
deren Ausnahmen nicht in Deinem Programm definiert sind, dann folge
den folgenden Vorschlägen:
- Benutze und definiere die ID 0 als "kein Fehler" (z.B. normaler Abbruch)
- Um Ausnahmezustände in Deinem Programm zu bestimmen, nutze die
ID's 1-10000.
Definiere diese mit der gewöhnlichen Methode von ENUM:
ENUM OK,NOMEM,NOFILE,...
(OK wird 0, und andere werden 1+)
- ID's 12336 bis 2054847098 (dieses sind alles Bezeichner als
Bestandteil von groß-/kleingeschriebenen Buchstaben und Ziffern
der Länge 2,3 oder 4 eingeschlossen in "") sind reserviert als
gemeinsam benutzte Ausnahmen. Eine gemeinsame Ausnahme ist ein Ausnahme,
die nicht in Deinem Programm definiert werden braucht, und die
benutzt wird von Vorgaben von Modulen (mit Funktionen in ihnen) um
Ausnahmen zu erhöhen: z.B., wenn du eine Anzahl von Prozeduren
erstellst die in einem eigenem Task laufen, dann kannst Du die Ausnahmen
erhöhen.
Wenn du diese Funktionen in verschiedenen Programme nutzen möchtest,
dann würde es nicht praktisch sein, die ID's mit dem Haupt Programm
zu koordinieren, und ferner, wenn du mehr als eine Funktionen benutzt
(in einem Modul, in der Zukunft) und jedes Modul würde eine
unterschiedliche Id haben für 'kein Speicher!', dann können Dir die Dinge
aus der Hand gleiten.
Und hier kommen die gemeinsamen Ausnahmen zum tragen: die gemeinsame
'kein Speicher'-ID ist "MEM" (einschliesslich den Anführungsstrichen):
jeder kann jetzt einfach von jedem Punkt
Raise("MEM")
von allen unterschiedlichen Prozeduren aufrufen, und der Programmierer,
der diese Module benutzt, braucht nur einen Ausnahme-Handler,
der "MEM" versteht.
Zukünftige Module, die verschiede Funktionen beinhalten, werden angeben,
was für Ausnahmen ein gesichertes Verfahren auslösen darf, und wenn diese
sich überlappen mit den ID's von anderen Prozeduren, dann wird die
Umgebung des Programmierers, die mit der Ausnahme zu arbeiten hat,
außerordentlich schwierig sein.
Beispiele
(system)
"MEM" kein Speicher
"FLOW" (beinahe) Stack überfließend
"^C" Kontrollieren-C-Tasten-Abbruch
"ARGS" schlecht Argumente
(exec/libraries)
"SIG" konnte kein Signal zuteilen
"PORT" konnte keinen Nachrichtenport erstellen
"LIB" Library nicht verfügbar
"ASL" keine asl.library
"UTIL" keine utility.library
"LOC" keine locale.library
"REQ" keine req.library
"RT" keine reqtools.library
"GT" keinen gadtools.library (ähnlich für anderen)
(intuition/gadtools/asl)
"WIN" kein Fenster zu öffnen
"SCR" kein Schirm zu öffnen
"REQ" kein Requester zu öffnen
"FREQ" Kein Filerequester zu öffnen
"GAD" konnte kein Gadget erstellen
"MENU" konnte kein Menu erstellen
(dos)
"OPEN" konnte kein File aufmachen/File existiert nicht
"OUT" Proble beim lesen
"IN" Probleme beim schreiben
"EOF" Ende des Files
"FORM" Eingabe Format Fehler
Die allgemeine Tendenz ist Großschreibung für allgemeine System
Ausnahmen und Kleinschreibung (oder gemischt) für spezifizierte Module.
- alles anderen (einschliesslich aller negativen ID's) sind reserviert.
Objektorientierte Programmierung
}14.OBJEKTORIENTIERTE
Da in Version 2.1b noch nichts eingebaut ist, ist auch nichts
dokumentiert. (Im Gegensatz zu Version 3.0 !!!)
Vorheriges Kapitel
Nächstes Kapitel
Der Inline-Assembler
}15.DER
A. Variablenteilung
B. Vergleich zwischen Inline-/Makroassembler
C. Wege, Binäredaten zu nutzen (INCBIN/CHAR..)
D. OPT ASM
Vorheriges Kapitel
Nächstes Kapitel
Der Inline-Assembler
}15A.
---------------------
Wie Du wahrscheinlich beim Beispiel im Kapitel 5D erraten hast, können
Assembleranweisungen frei mit E-Anweisungen vermischt werden. Das große Ge-
heimniss ist, das ein kompletter Assembler in den Compiler eingebaut
wurde.
Getrennt von den normalen Assembler Addressierungsmodies kannst Du auch fol-
gende Identifiers benutzen:
meinlabel:
LEA mylabel(PC),A1 /* Labels */
DEF a /* Variablen */
MOVE.L (A0)+,a /* Beachte das <var> ein <offset>(A4) (or A5) ist */
MOVE.L dosbase,A6 /* Identifiers für Library-Aufrufe */
JSR Output(A6)
MOVEQ #TRUE,D0 /* Konstanten */
Der Inline-Assembler
}15B.
----------------------------------------------
Der Inline-Assembler unterscheidet sich etwas von einem normalen Macro-
Assembler. Dies ist dadurch bedingt, daß er eine Erweiterung von E ist, und
deshalb der E-Syntax folgt. Hauptunterschiede sind:
- Kommentare werden nicht mit einem ';' Semikolon eingeleitet, sondern in /*
*/ eingeschlossen, sie haben unterschiedlich Bedeutung.
- Schlüsselworte und Register werden großgeschrieben, alles ist von der Groß-
und Kleinschreibung abhängig.
- keine Macros und ander luxuriöse Assemblereigenschaften (es gibt schließ-
lich den kompletten E-Sprachumfang dafür)
- Du solltest aufpassen, daß Du den Inhalt der Register A4/A5 nicht mit dem
Inline-Assembler überschreibst, da sie vom E-Code benutzt werden.
- keine Unterstützung des Large Modells/Relloc-Hunks im Assembler -JETZT-
Dies bedeutet hauptsächlich, das Du bis jetzt die PC-Relative Addressie-
rung benutzen mußt.
Der Inline-Assembler
}15C.
------------------------------------------------
INCBIN
Syntax: INCBIN <filename>
Fügt einen Binär-File genau am Punkt des Statements ein, und sollte deshalb
vom Code getrennt werden. Beispiel:
meinetab: INCBIN <filename>
LONG, INT, CHAR
Syntax: LONG <werte>
INT <werte>
CHAR <werte>
Erlaubt Dir binäre Daten direkt in ein Programm einzufügen. Funktioniert
fast wie DC.x in Assembler. Beachte, daß das CHAR-Statement auch Strings
annimmt und immer auf gerade Wortaddressen gelegt wird. Beispiel:
meinedaten: LONG 1,2; CHAR 3,4,'Hey Leute',0,1
Der Inline-Assembler
}15D.
------------
OPT ASM wird im Kaptel 16A besprochen. Es erlaubt Dir EC wie einen Assemb-
ler zu programmieren. Es gibt keinen guten Grund, EC anstatt eines Assemb-
lers zu nehmen, außer der Geschwindigkeit. Er ist wesentlich schneller als
zum Beispiel A68k, gleich mit dem DevPac und langsamer als AsmOne. Du wirst
auch eine schwere Zeit haben, wenn Du die alten Seka-Sources von deiner
Disk schröpfen willst, aufgrund der aufgeführten Unterschiede (siehe 15B).
Wenn Du Assembler-Programme mit EC schreiben und sie zu anderen Assemblern
kompatibel halten willst, schreibe vor jede E-Speziefische Funktion ein ";",
EC wird sie benutzen und jeder andere Assembler ihn wird als Kommentar an-
sehen.
Beispiel:
;OPT ASM
start: MOVEQ #1,D0 ;/*macht etwas dummes*/
RTS ;/*und steigt aus*/
dies wird von jedem Assembler assembliert, EC eingeschlossen.
Dinge über den Compiler
}16.DINGE
A. Das OPT Schlüsselwort
B. Small/Large Modell
C. Stack Organisation
D. Festgeschriebene Begrenzungen
E. Fehlermeldungen, Warnungen und nicht dokumentierte Tests
F. Compiler Puffer Organisation und Anforderung
G. Eine kurze Entstehungsgeschichte
Vorheriges Kapitel
Nächstes Kapitel
Dinge über den Compiler
}16A.
--------------------------
OPT, LARGE, STACK, ASM, NOWARN, DIR, OSVERSION
syntax: OPT <Optionen>
Bietet die Möglichkeit, die Einstellungen des Compilers zu verändern.
LARGE Das Code- und Datenmodell wird auf "LARGE" gestellt. Grundein-
stellung ist "SMALL"; der Compiler generiert einen 100% pc-
ähnlichen Code, mit einer Maximalgröße von 32K. Mit "LARGE"
gibt es keine solchen Begrenzungen, zudem werden "reloc-hunks"
generiert. Siehe -L
STACK=x Setzt die Stackgröße auf x Bytes. Man sollte diese Option
nur verwenden, wenn man weiß, was man tut. Normalerweise
schätzt der Compiler die benötigte Stackgröße selbstständig
recht gut ein.
ASM Der Compiler wird in den Assembler-Modus geschaltet. Von da an
sind nur noch Assembler-Befehle erlaubt und es wird kein Initi-
alisierungscode generiert. Siehe: das Kapitel über integriertes
Assembler.
NOWARN Schaltet die Warnungen aus. Der Compiler gibt eine Warnung
aus, wenn er *glaubt*, daß das Programm falsch ist, syntakt-
isch aber in Ordnung ist. Siehe -n
DIR=moduledir Legt das Verzeichnis fest, in dem der Compiler nach
Modulen sucht. Grundeinstellung ist 'emodules:'
OSVERSION=vers Grundeinstellung ist 33.(V1.2). Setzt die Minimum-
Version des Kickstarts (wie z.B. 37. für V2.04) fest,
ab denen das Programm laufen soll. Auf diesem Weg
bricht das Programm einfach ab, wenn die dos.library
einer älteren Version in der Initialisierungsroutine
auf einer älteren Maschine geöffnet wird. Allerdings
ist es für den User hilfreicher, wenn man die Kick-
startversion selber testet und eine geeignete Fehler-
meldung ausgibt.
Beispiel:
OPT STACK=20000,NOWARN,DIR='DF1:Modules',OSVERSON=39
Dinge über den Compiler
}16B.
-----------------------
Amiga-E läßt einem die Wahl zwischen einem SMALL und einem LARGE Code/
Daten-Modell. Allerdings dürften die meisten Programme, die man schreibt
(besonders, wenn man gerade erst mit Amiga-E angefangen hat), in die
32K passen, wenn compiliert wird: man braucht sich also keine Gedanken
über das Einstellen eines Code-Genrierungs-Modelles machen. Man kann die
Notwendigkeit eines LARGE-Modelles daran erkennen, daß sich EC darüber
beschwert, daß es den Code nicht mehr in die 32K hineinbekommt. Folgender
Befehl compiliert einen Source-Code mit dem LARGE-Modell:
1> ec -l sizy.e
oder, besser, setzen sie die Anweisung
OPT LARGE
in ihren Code.
Dinge über den Compiler
}16C.
-----------------------
Um alle lokalen und globalen Variablen zu speichern, weißt das run-time Sys-
tem eines von E generierten ausführbaren Programmes einen Speicherbereich zu,
von dem es einen festen Teil verwendet, um alle globalen Variablen zu speichern.
Der Rest wird dynamisch verwendet, wenn Funktionen aufgerufen werden. Wenn in E
eine Funktion aufgerufen wird, wird ein Bereich im Stack reserviert, um alle
lokalen Daten zu speichern, sobald die Funktion beendet ist, wird der Bereich
wieder freigegeben. Deshalb ist es gefährlich, große Arrays für lokale Daten
zu haben, wenn diese rekursiv aufgerufen werden: alle Daten der vorherigen Auf-
rufe der selben Funktion befinden sich noch immer im Stack und besetzen somit
einen großen Bereich in diesem. Werden Prozeduren jedoch linear aufgerufen, dann
kann der Stack nicht überlaufen.
Beispiel:
global data: 10K (arrays e.d)
local data PROC #1: 1K
local data PROC #1: 3K
Das run-time System reserviert immer zusätzliche 10K für normale Rekursion (z.B. mit
kleinen lokalen Arrays) und weitere Buffers/Systemspeicher, so daß insgesamt 24K
Stackspeicher zugewiesen werden.
Dinge über den Compiler
}16D.
----------------------------------
Beachte diese Zeichen: (+-) ungefähr, hängt von der Situation ab
(n.l.) kein klares Limit, aber dieser Wert scheint sinnvoll
OBJEKT/GEGENSTAND WERT/MENGE/MAX
---------------------------------------------------------------------------------
Wert des Datentyps CHAR 0 ... 255
Wert des Datentyps INT -32K ... +32K
Wert des Datentyps LONG/PTR -2Gig ... +2 Gig
Identifierlänge 100 bytes (n.l.)
Länge einer Quellcodezeile 2000 lexikalische Zeichen (+-)
Quellcode Länge 2 Gig (theoretisch)
konkrete listen einige hundert Elemente (+-)
konstante Strings 1000 Zeichen (n.l.)
max. Tiefe der Schleifen 500 tief
max. Tiefe der Kommentare unbegrenzt
# der lokalen Variablen pro Prozedur 8000
# der globalen Variablen 7500
# der Argumente für eigene Funktionen 8000 (zusammen mit locals (?))
# der für E-varargs Funktionen [WriteF()] 64
ein Objekt (lokal/global oder dyn. zugewiesen) 8K
ein Array, List oder String (lokal oder global) 32K
ein String (dynamisch) 32K
ein List dynamisch) 128K
ein Array (dynamisch) 250MB
lokale Daten pro Prozedur 250MB
globale Daten 250MB
Code-Größe einer Prozedur 32K
Code-Größe eines ausführbaren Progs. 32K SMALL, 2Gig LARGE Modell
Buffer-Größe eines generierten Codes und Identifiers abhängig vom Quellcode
Buffer-Größe von Sprungmarken/Zweigen unabhängig (wieder)zugewiesen
Dinge über den Compiler
}16E.
--------------------------------------------------------------
Manchmal. wenn sie ihren Quellcode mit EC compilieren, erhalten sie eine Meldung, die
ungefähr folgendermaßen aussieht: UNREFERENCED <ident.>, <ident.>, ...
Dies passiert, wenn sie Variable, Funktionen oder Sprungmarken definieren, diese aber
nicht verwenden. Dies ist ein Extra-Service des Compilers, der helfen soll, solche
schwer zu findenden Fehler zu entdecken. Es gibt mehrere Warnungen, die der Compiler
ausgiebt, um sie darauf aufmerksam zu machen, daß etwas nicht in Ordnung ist, dies aber
kein echter Fehler ist.
- "A4/A5 used in line assembly"
Diese Warnung wird ausgegeben, wenn sie Register A4 und A5 in ihrem Assembler Code
verwenden. Der Grund dafür ist, daß diese Register von E intern verwendet werden,
um lokale und globale Variable richtig zu addressieren. Natürlich kann es gute Gründe
geben, diese zu gebrauchen, wie MOVEM.L A4/A5,-(A7) vor einen großen Stück Inline-
Assembler-Code.
- "keep eye on stacksize"
- "stack is definitely too small"
Beides kann ausgegeben werden, wenn sie OPT STACK=<size> verwenden. Der Compiler ver-
gleicht einfach ihre Angabe mit seiner eigene Schätzung (siehe Kapitel 16C.), und gibt
erstere Meldung aus, wenn er meint, die Größe sei etwas knapp kalkuliert oder letztere,
wenn sie definitiv zu klein ist.
- 'suspicious use of "=" in void expression'
Diese Warnung erscheint, wenn sie den Ausdruck 'a=1' als Anweisung gebrauchen. Ein Grund
ist, daß ein Vergleich als Anweisung wenig Sinn macht, aber der Hauptgrund ist, daß dies
oft vorkommende Rechtschreibfehler bei 'a:=1' ist. Den vergessenen ":" zu finden ist
schwer, aber er kann ernsthafte Konsequenzen haben.
FEHLER:
- 'syntax error'
Häufigster Fehler. Diese Fehlermeldung erscheint, wenn entweder keine andere Meldung passt,
oder ihre Anordnung des Codes dem Compiler etwas seltsam erscheint.
- 'unknown keyword/const'
Sie haben einen Identifier in Großbuchstaben (wie "IF" oder "TRUE") verwendet, und der Compiler
konnte keine Definition dafür finden. Gründe:
* falschgeschriebenes Schlüsselwort
* sie haben eine Konstante verwendet, diese aber nicht zuvor mit CONST definiert
* sie haben vergessen, das Modul anzugeben, in dem ihre Konstante definiert ist
- '":=" expected'
Sie haben eine FOR Anweisung oder eine Zuweisung geschrieben, und haben dabei etwas anderes als
":=" verwendet.
- 'unexpected characters in line'
Sie haben Zeichen verwendet die in E außerhalb von Strings keine syntaktische Bedeutung haben.
Beispiel: "§!&Öß"
- 'label expected'
In bestimmten Fällen, zum Beispiel nach den Schlüsselwörtern PROC oder JUMP, ist ein Iden-
tifier notwendig. Sie haben irgendetwas anderes geschrieben.
- '"," expected'
Innerhalb einer Gegenstandsliste (z.B. eine Parameter Liste), haben sie etwas anderes als
ein Komma verwendet.
- 'variable expected'
Diese Konstruktion braucht eine Variable, Beispiel:
FOR <var>:= ... etc.
- 'value does not fit into 32 bit'
Beim spezifizieren einer Konstanten haben sie einen zu großen Wert einegegeben, Beispiel:
$FFFFFFFFF, "abcdef" /siehe Kapitel 2A-2E)
Diese Meldung erscheint auch, wenn ein SET-Befehl mit mehr als 32 Elementen verwendet wird.
- 'missing apostrophe/quote'
Sie haben ein ' am Ende einer String vergessen.
- 'incoherrent program structure'
* sie haben eine neue PROCedure gestartet, ohne die vorherige zu beenden.
* die Verzweigung ihrer Programme ist falsch, z.B.:
FOR
IF
ENDFOR
ENDIF
- 'illegal command-line option'
Innerhalb der Befehlszeile 'EC -opt source' haben sie für -opt einen Ausdruck verwendet, der
EC unbekannt ist.
- ' division and multiplication 16 bit only'
Der Compiler hat festgestellt, daß sie einen 32 bit Wert für * oder / verwendet haben. Dies
würde nicht den erwünschten Wert im Runtime ergeben.
Siehe Mul() und Div().
- 'superfluous items in expression/statement'
Nachdem der Compiler ihren Anweisung bearbeitet hat, hat er immer noch Zeichen anstelle
eines Linefeeds gefunden. Sie haben wahrscheinlich den <lf> oder ";" vergessen, um zwei
Anweisungen zu trennen.
- 'procedure "main" not available'
Ihre Programm hat keine 'main procedure'.
- 'double declaration of label'
Sie haben eine Sprungmarke zweimal vergeben, z.B.:
label:
PROC label()
- 'unsafe use of "*" or "/"'
Dies hat wieder etwas mit 16 Bit anstelle von 32 Bit * und / zu tun. Siehe 'division and
multiplication 16 bit only'.
- 'reading sourcefile didn't succed'
Überprüfen sie ihre Angaben für die Quelle, die sie mit 'ec mysource' angegeben haben.
Achten sie darauf, daß die Quelle und nicht die Kommandozeile auf '.e' endet.
- 'writing executable didn't succed'
Der Versuch, das eben generierte ausführbare Programm zu schreiben verursachte einen DOS-
Fehler. Unter umständen existierte das Programm bereits und konnte nicht überschrieben
werden.
- 'no args'
"GEBRAUCH: ec [-opts] <Quellcodedateiname> ('.e' wird hinzugefügt)"
Sie erhalten diese Meldung, wenn sie ec ohne Argumente verwenden.
- 'unknown/illegal addressing mode'
Dieser Fehler erscheint nur, wenn sie den inline Assembler verwenden. Mögliche Gründe:
* sie haben eine Addressierungsweise verwendet, die es für den 68000er nicht gibt.
* die Addressierungsmethode existiert, aber nicht für diesen Befehl. Nicht alle Assembler-
Befehle unterstützen alle Kombinationen der effektiven Addressen für Quelle und Ziel.
- 'unmatched parentheses'
Ihre Anweisung hat mehr "(" als ")" oder umgekehrt.
- 'double declaration'
Ein Identifier wird in zwei oder mehr Deklarationen verwendet.
- 'unknown'
Ein Identifier wird in keiner Deklaration verwendet; er ist unbekannt. Wahrscheinlich haben
sie vergessen, ihn in eine DEF-Anweisung zu setzen.
- 'incorrect # of args or use of ()'
* sie haben vergessen "(" oder ")" an die richtige Stelle zu setzen
* sie haben eine falsche Anzahl von Argumenten für eine Funktion verwendet
- 'unknown e/library function'
Sie haben einen Identifier mit einem Großbuchstaben begonnen und dann mit Kleinbuchstaben
fortgesetzt, aber der Compiler konnte keine Definition finden.
Mögliche Gründe:
* eine Funktion wurde falschgeschrieben
* sie haben das Modul miteinzuschließen, das diesen Bibliotheksaufruf enthält
- 'illegal function call'
Erscheint selten. Sie erhalten diesen Fehler, wenn sie seltsame Funktionsaufrufe starten,
wie z.B. verzweigte WriteF()'s :
WriteF(WriteF('hi'))
- 'unknown format code following ""'
Sie haben in einer String einen Formatcode verwendet, der unzulässig ist.
Siehe Kapitel 2F für eine Liste der Formatcodes.
- '/* not properly nested comment structure */'
Die Anzahl der '/*' stimmt nicht mit der Anzahl der '*/' überein, oder haben eine komische
Reihenfolge.
- 'could not load binary'
<filespec> innerhalb von INCBIN <filespec> konnte nicht gelesen werden.
- '"}" expected'
Sie haben einen Ausdruck mit "{<var>" begonnen, aber das "}" vergessen.
- 'immediate value expected'
Manche Konstruktione erfordern einen direkten Wert anstelle eines Ausdrucks.
Beispiel:
DEF s[x*y]:STRING /* falsch, nur etwas wie s[100]:STRING ist zulässig */
- 'incorrect size of value'
Sie haben einen unzulässig großen/kleinen Wert in einer Konstruktion verwendet.
Beispiel:
DEF s[-1]:STRING, +[1000000]:STRING /* muß 0 ... 32000 sein */
MOVEQ #1000,D2 /* muß -128 ... 127 sein */
- 'no e code allowed in assembly modus'
Sie haben den Compiler als Assembler arbeiten lassen, aber, aus Versehen, E-Code
geschrieben.
- 'illegal/inappropriate type'
An einer Stelle wo eine <type> Spezifikation notwendig gewesen wäre, haben sie etwas
unpassendes eingegeben. Beispiele:
DEF a:PTR TO ARRAY /* es gibt keinen solchen Typ */
[1,2,3]:STRING
- '"]" expected
Sie haben mit einem "[" begonnen, aber nie mit einem "]" aufgehört.
- ' statement out of local/global scope'
Ein wesentlicher Punkt bei der Kontrolle ist die erste PROC-Anweisung. Davor sind nur
globale Definitionen (DEF, CONST,MODULE etc.) erlaubt, und keinerlei Code. Im zweiten
Teil sind nur Code, aber keine globalen Definitionen erlaubt.
- 'could not read module correctly'
Es gab einen DOS-Fehler beim Versuch, ein Modul von einer MODULE-Anweisung einzulesen.
Gründe:
* emodules:wurden nciht korrekt zugewiesen (assign emodules: ...)
* der Modulname wurde falsch geschrieben, oder es existiert nicht
* sie haben MODULE 'bla.m' anstelle von MODULE 'bla'
- 'workspace full'
Erscheint selten. Wenn dieser Fehler erscheint, müssen sie EC mit der '-m' Option dazu
zwingen, die Schätzung über die benötigte Speichermenge höher anzusetzen. Versuchen sie
es zuerst mit '-m2', dann '-m3', bis der Fehler verschwindet. Sie müssen aber schon rie-
sige Anwendungsprogramme, mit einer Unmenge Daten schreiben, damit dieser Fehler er-
scheint.
- 'not enough memory while (re-)allocating'
Mögliche Lösungen für dieses Problem:
1. Sie haben andere Programme im Multitasking laufen. Stoppen sie diese und versuchen
sie es nocheinmal.
2. Sie haben akuten Speichermangel und der Speicher war fragmentiert. Rebooten sie.
3. Weder 1. noch 2., kaufen sie sich eine Speichererweiterung (hüstel).
- 'incorrect object definition'
Sie haben bei einer Definition zwischen OBJECT und ENDOBJECT Blödsinn geschrieben.
Siehe Kapitel 8F, um herauszufinden, wie's richtig geht.
- 'incomplete if-then-else expression'
Wenn sie IF als einen Operator verwenden, dann muß ELSE ein Teil dieses Ausdrucks sein:
ein Ausdruck mit einer IF-Anweisung muß immer einen Wert zurückgeben, aber wenn keine
ELSE-Anweisung da ist, kann IF im Prinzip nichts tun.
- 'unknown object identifier'
Sie haben einen Identifier verwendet, den der Compiler als einen Teil eines Objekts er-
kannt hat, aber sie haben vergessen, ihn zu deklarieren. Gründe:
* falsch geschriebener Name
* fehlendes Modul
* der Identifier innerhalb des Modules wird nicht so geschrieben, wie sie es aus den
Rom-Kernel-Manuals erwartet haben. Überprüfen sie es mit ShowModule.
Beachten sie, daß Amiga-System-Objekte auf Assembler Identifiern basieren und nicht auf
C. Zweitens: Identifier folgen dem E-Syntax.
- 'double declaration of object identifier'
Ein Identifier wurde in zwei Objekt Definitionen verwendet.
- 'reference(s) out of 32K range: switch to LARGE model'
Ihr Programm wird größer als 32K. Fügen sie einfach 'OPT LARGE' in ihren Quellcode mit
ein. Siehe Kapitel 16B.
- 'reference(s) out of 256 byte range'
Sie haben wahrscheinlich BRA.S oder Bcc.S über eine zu große Distanz geschrieben.
- 'too sizy expression'
Sie haben wahrscheinlich eine Liste von [], möglicherweise [[]], geschrieben, die zu groß
ist.
- 'incomplete exception handler definition'
Sie haben unter Umstaänden EXCEPT ohne HANDLE verwendet, oder aber auch anders herum.
Siehe Kapitel 13 für "exception handling".
Dinge über den Compiler
}16F.
-------------------------------------------------
Wenn sie den Fehler 'workspace full' (sehr unwahrscheinlich) erhalten, oder wissen wollen was
wirklich passiert, wenn ihr Programm compiliert wird, ist es wichtig, zu wissen, wie EC seine
Buffer organisiert.
Ein Compiler, und in diesem Fall EC, braucht Buffer, um alle möglichen Dinge, wie z.B. Identi-
fier nachverfolgen zu können. Es braucht diese auch, um darin den generierten Code zu speichern.
EC weiß nicht, wie groß diese Buffer sein müssen. Bei manchen Buffern, wie dem für Konstanten,
ist das kein Problem: wenn der Buffer voll ist, weißt EC einfach ein weiteres Stück Speicher zu
und arbeitet dann weiter. Andere Buffer, wie der für den generierten Code, müssen ein einziger
Speicherblock sein, der sich während des Compilierens nicht verändert: EC muß also den notwendigen
Speicher gut abschätzen, um große und kleine Quellcodes compilieren zu können. EC berechnet also
anhand des Quellcodes den benötigten Speicherplatz und fügt dazu nocheinmal eine ansehnliche Menge
hinzu. Somit reicht in 99% aller Fälle der Speicher aus, andern Falls erhalten sie eine Fehler-
meldung un müssen weiteren Speicher mit der '-m' Option hinzufügen.
Experimentieren sie mit unterschiedlichen Typen und Größen von Quellcoden in Verbindung mit der
'-b' Option um herauszufinden, wie es funktioniert.
Dinge über den Compiler
}16G.
--------------------------------------
E ist nicht einfach einen weitere Programmiersprache: sie wurde schrittweise und vorsichtig
vom Autor entwickelt, da er mit den existierenden Programmiersprachen nicht besonders glück-
lich war, speziell den langsamen und "schlabrige-Codes-erzeugenden" Compilern, die es für
diese gab. E hatte als primäres Ziel dem Autor für seine Entwickling von Amiga Programmen zu
dienen, und war dabei bisher sehr erfolgreich. E wurde in einen Zeitraum von 1½ Jahren in Ver-
bindung mit intensiver Arbeit entwickelt und war nicht der erste Compiler, den der Autor ge-
schrieben hat: manch einer erinnert sich vielleicht an den DEX-Compiler.
Dieser war langsam und nicht besonders mächtig und kann nur schwerlich mit dem Amiga E Com-
piler verglichen werden, aber er gab dem Autor wichtige Erfahrungen, die halfen, Amiga E zu
dem zu machen, was es heute ist. DEX Programierer werden feststellen, daß es sehr einfach ist
ihre Quellcodes in E umzuwandeln, und die Entwicklung mit der 10fachen Power und der 20fachen
Geschwindigkeit fortzusetzen. Eine witzige Sache an DEX ist, daß sich die Entwicklung von DEX
und E überschnitten hat: als DEX fertig war, war E V1.6 zur Hälfte geschrieben. Weil E schon
damals wesentlich besser war, wurden E Bibliotheken/Beispiele und Codes auf allgemeinen Wunsch
hin auf DEX übertragen, so daß der Vorgänger Teile seines Nachfolgers beinhaltete.
Der AUtor hat auch noch weitere Compiler und Interpreter geschrieben, die aber teilweise nie
veröffentlicht wurden.
Amiga E ist ein Produkt, das weiter entwickelt wird, bis es die ultimative Sprache und Amiga
Entwicklungssystem ist:
- indem diese, bisher fehlenden Teile, in die Sprache miteinbezogen werden
* Objektorientierung
* besseres Fließkomma Konzept
- indem am Compiler einige Veränderungen vorgenommen werden
* mögliche Genrierung von 020/030/881 Code
* Optimierung des Compilierungsprozesses, so daß unter Umstäden sich Zeile/Minute Figuren
verdoppeln
* es soll dem User ermöglicht werden, eigenen Code in Module zu wandeln, um somit große
Anwendungen modular aufbauen zu können
- indem wetvolle Elemente dem Packet hinzugefügt werden
* ein integrierte Editor ?
* source-level debugger ?
* CASE Werkzeuge, zum Beispiel
- indem Bugs entfernt werden (welche Bugs ??!!)
Das ENDE! Schnauf! Viel Spaß mit E!