THASM
Hier ist die Dokumentations-, Hilfe-, Readme- und Referenzdatei zum Thunder Assembler. Gleich zu Anfang möchte ich erwähnen, dass es sich um keinen echten Assembler handelt, sondern um einen Interpreter, dessen Syntax stark der einer Assemblersprache ähnelt. Ich habe ihn für den BCC entwickelt und mit dem Anfang der BCC-Abstimmung wird THASM unter GPL lizenziert!
Die Versionsnummer wird ausgegeben wenn thasm ohne Parameter oder nur mit dem Parameter „-v“ aufgerufen wird. Diese kann dann mit den hier genannten verglichen werden. Übrigens werden nicht alle Versionen online gestellt. Versionen die nie online gestellt waren, werden grau gekennzeichnet.
Wenn thasm.exe keine Angaben zur Versionsnummer macht ist das die Version 0.67 unstable. Es sind schon ziemlich viele Befehle implementiert, aber call, ret, mul, div, push und pop funktionieren noch nicht einwandfrei.
Die bekannten Fehler der letzten Version sind nun behoben. Es werden noch einige, sogar relativ wichtige, Funktionen eingebaut werden, daher nur „nearly stable“.
2 Fehler in push und pop behoben!
Version 0.73 nearly stable:
Programmkonstanten eingebaut. Neuen Bug entdeckt.
Version 0.74 nearly stable:
Laufzeitkonstanten und Compiletimerkonstante eingebaut, d.h. man kann jetzt abfragen wie lange das parsen/lexen dauert.
Schwere Fehler gefunden!
Version 0.75 nearly stable:
Schwere Fehler der letzten Version beseitigt.
Version 0.76 nearly stable:
Bedingte Funktionsaufrufe mit (ce=cz, cne=cnz, cg, cge, cl und cle) sind nun möglich. Diese funktionieren genauso wie (je=jz, jne=jnz, …), außer, dass sie eine Rücksprungadresse erstellen, die es erlaubt mit ret zurückzuspringen.
Version 0.765 nearly stable:
Timer eingebaut.
Version 0.78 Beta:
Alle mir bekannten Bugs wurden behoben. Außerdem wurden einige Funktionen eingebaut: sin(Sinuswert), cos(Cosinuswert), rnd(Zufallswert).
Version 0.8 stable:
-
Die Befehle werden hier in einer Tabelle aufgezählt und erklärt. Folgendes ist zu beachten:
- Wenn ein Parameter unter Verwendung in eckigen Klammern steht, kann er weggelassen werden.
- Wenn ein Befehl blau gefärbt ist, kann er nur im .text Sektor verwendet werden.
- Wenn ein Befehl rot gefärbt ist, kann er nur im .data Sektor verwendet werden.
- Wenn ein Befehl schwarz gefärbt ist, kann er in jedem Sektor verwendet werden.
- Wenn in der Beschreibung ein [STR] steht, dann kann diese Funktion auch für Stringvariablen verwendet werden.
Befehl |
Verwendung |
Beschreibung |
app |
app name |
Name muss ein String sein! Der Fenstertitel des Programms wird auf name gesetzt. |
mov |
mov op1,op2 |
Kopiert den Wert aus op2 nach op1 [STR] |
add |
add op1,op2 |
Addiert Wert aus op2 nach op1 [STR] |
sub |
sub op1,op2 |
Subtrahiert Wert aus op2 von op1 |
mul |
mul op1,op2 |
Multipliziert op1 mit op2 und speichert das Ergebnis in op1 |
div |
div op1,op2 |
Dividiert op1 durch op2 und speichert das Ergebnis in op1 |
inc |
inc op |
Erhöht Wert aus op um 1 |
dec |
dec op |
Verringert Wert aus op um 1 |
neg |
neg op |
Dreht das Vorzeichen des Wertes aus op um |
not |
not |
Ändert alle Bits im Wert von op |
push |
push op |
Kopiert den Wert aus op auf den Stack [STR] |
pop |
pop [op] |
Verschiebt Wert von Stack nach op. Wenn op nicht gegeben ist, wird nach dx verschoben. (Siehe Standardvariablen DX) [STR] |
jmp |
jmp label |
Springt zum Label label. (Siehe Hilfeabschnitt Deklaration eines Labels) |
int |
int name |
name muss in dem Fall ein String sein! (Siehe Hilfeabschnitt Interrupts) |
cmp |
cmp op1,op2 |
Vergleicht op1 mit op2 und speichert das Ergebnis Programmintern |
je = jz |
je label |
Springt zu label, wenn beim letzten cmp op1 und op2 gleich waren |
jne = jnz |
jne label |
Springt zu label, wenn beim letzten cmp op1 und op2 ungleich waren |
jl |
jl label |
Springt zu label, wenn beim letzten cmp op2 kleiner war als op1 |
jle |
jle label |
Springt zu label, wenn beim letzten cmp op2 kleiner oder gleich wie op1 war |
jg |
jg label |
Springt zu label, wenn beim letzten cmp op2 größer war als op1 |
jge |
jge label |
Springt zu label, wenn beim letzten cmp op2 größer oder gleich war wie op1 |
jcxz |
jcxz label |
Springt zu label, wenn cx 0 ist (Siehe Standardvariablen CX) |
call |
call function |
Ruft eine Funktion auf, die wie ein Label deklariert wurde |
ret |
ret |
Nur in Funktionen! Kehrt zu der Zeile zurück von der aus die Funktion aufgerufen wurde |
gfx |
gfx op1,op2 |
Erzeugt ein Grafikfenster mit op1 Mal op2 Pixel |
org |
org op1,op2 |
Setzt die beiden Originvariablen auf op1 und op2. Diese werden bei diversen Grafikbefehlen benötigt |
cls |
cls |
Löscht Bildschirminhalt |
flip |
flip |
Kopiert gezeichnetes vom Backbuffer auf den Frontbuffer |
rect |
rect op1,op2 |
Zeichnet ein Rechteck mit einer Breite von op1 und einer Höhe von op2 an den Koordinaten, die mit org gesetzt worden sind. |
text |
text op |
Schreibt Text op an die org-Koordinaten |
oval |
oval op1,op2 |
Zeichnet ein Oval mit einer Breite von op1 und einer Höhe von op2 an die org-Koordinaten |
dot |
dot op1,op2 |
Zeichnet einen Punkt an (op1|op2) |
and |
and op1,op2 |
Führt die logische And-Operation mit op1 und op2 aus und speichert das Ergebnis in op1 |
or |
or op1,op2 |
Führt die logische Or-Operation mit op1 und op2 aus und speichert das Ergebnis in op1 |
xor |
xor op1,op2 |
Führt die logische Xor-Operation mit op1 und op2 aus und speichert das Ergebnis in op1 |
cos |
cos op |
Errechnet den Cosinuswert für op und speichert ihn in op |
sin |
sin op |
Errechnet den Sinuswert für op und speichert ihn in op |
rnd |
rnd min,max |
Speichert eine Zufallszahl, die im durch min und max angegebenen Wertebereich liegt im AX. |
int |
op1 int op2 |
Erstellt eine Variable des Typs Int mit dem Namen op1 und dem Wert op2(muss konstant sein!) |
single |
op1 single op2 |
Erstellt eine Variable des Typs Single mit dem Namen op1 und dem Wert op2(muss konstant sein!) |
string |
op1 string op2 |
Erstellt eine Variable des Typs String mit dem Namen op1 und dem Wert op2(muss konstant sein!) |
|
|
|
Es sind (bis jetzt) nur 3 verschiedene Datentypen verfügbar.
Datentyp |
Name |
Minimum |
Maximum |
Int |
Ganzzahl |
-2147483648 |
2147483647 |
Single |
Gleitkommazahl |
1.17549e-38 |
3.40282e+38 |
String |
Zeichenkette |
- |
- |
Thasm definiert nicht nur die Variablen des Programmierers, sondern auch eigene. Hier ist die Tabelle:
Name |
Datentyp |
Verwendet von Funktion(en) |
ax |
Single |
rnd |
bx |
Single |
- |
cx |
Int |
jcxz |
dx |
String |
pop |
cmd |
String |
int print ; int input |
kbd |
Int |
int downkey ; int waitkey |
Ein Interrupt ist eine sogenannte Unterbrechungsroutine, das heißt es wird das laufende Programm unterbrochen und, zumindest bei Thasm, ein vordefiniertes „Miniprogramm“ ausgeführt. Folgende Interrupts existieren und funktionieren:
Interrupt |
Beschreibung |
int print |
Gibt den Wert aus der Standardvariablen cmd auf dem Bildschirm aus, sofern sich das Programm im Kommandozeilenmodus befindet. |
int input[,text] |
Gibt den Text text aus und wartet auf eine Eingabe. Diese wird dann in die Variable cmd verschoben. |
int waitkey |
Wartet auf einen Tastendruck. Verschiebt dann den Ascii-Wert der Taste in die Standardvariable kbd. ACHTUNG: Funktioniert nur im Grafikmodus! |
int downkey,k |
k ist eine KeyKonstante(siehe Hilfeabschnitt KeyKonstanten). Je nachdem ob die Taste gedrückt wird oder nicht, wird kbd auf 1 oder 0 gesetzt. |
int delay,zeit |
Wartet eine Zeit von zeit ab. Diese muss in Millisekunden gegeben werden. |
KeyKonstanten sind Konstanten, die von Thasm selbst erstellt werden und, mit dem Interrupt downkey, der Abfrage von Tastendrücken dienen.
Ein Beispiel wäre:
.text
main:
int downkey,ESC
jmp main
Hier wird die Standardvariable kbd auf 1 gesetzt wenn die Taste Escape gedrückt wird und 0 wenn sie nicht gedrückt wird. Es werden bis jetzt aber nur folgende Tasten unterstützt: A, S, D, W, LEFT, RIGHT, DOWN, UP, ESCAPE. Die Konstanten LEFT, RIGHT, DOWN und UP gehören zu den Pfeiltasten.
In Thasm müssen Variablendeklarationen von Befehlen getrennt werden. Bei diversen Hochsprachen macht dies der Compiler, hier muss der Programmierer anpacken. Dadurch werden alle Variablen global, also im gesamten Programm verwendbar, was Nachteile, aber auch gewisse Vorteile bringt. Ich habe beim Pong Programmieren ein völlig neues Programmiergefühl bekommen (war ein komisches Gefühl). Die Sektoren werden wie folgt eröffnet:
.data 'eröffnet den Datensektor
username string "Thunder"
.text 'eröffnet den Codesektor
main: 'Main-Funktion - hier setzt der Interpretiervorgang
'ein. Ist nicht notwendig wenn das Programm direkt
'nach der Codesektoreröffnung beginnt.
mov cmd,username 'Natürlich könnte man statt
'username auch "Thunder"
'schreiben
int print
end
Dieses Programm erstellt eine Variable namens username und gibt sie dann im Codesektor aus.
Kommentare können den Code übersichtlicher gestalten. Dies ist besonders wichtig, wenn man größere Programme schreibt, was in thasm schnell mal passieren kann.
Einzeilige Kommentare werden durch Apostroph eröffnet. Obiges Beispiel erklärt einzeilige Kommentare auch.
Mehrzeilige Kommentare beginnen mit / ' = Slash mit anschließendem Apostroph
und endet mit '/ = Apostroph mit anschließendem Slash.
Beispiel:
.text
int input,"Ihr Name: "
/'
KOMMENTARTEST
'/
int print
int delay,2000
end
Ein Label stellt eine Sprungmarke oder den Anfang einer Funktion dar. Es wird an einen Beliebigen Namen ein Doppelpunkt angeschlossen und fertig ist das Label. Wenn man eine Funktion erstellen will, muss man sie auch noch mit dem Schlüsselwort „ret“ beenden.
Ein Beispiel für eine Sprungmarke:
.text
main:
int downkey,ESC
jmp main
Ein Beispiel für eine Funktion:
.text
main:
mov cx,0
mov dx,"Etwas"
inc cx
push cx
push dx
call out
int delay,1500
end
out:
pop dx
pop cx
mov cmd,cx
add cmd,": "
add cmd,dx
int print
ret
Programmkonstanten (v0.74+)
Programmkonstanten sind da um einen Zustand oder eine „Besonderheit“ eines Programms zu ermitteln. Sie beginnen mit zwei Underlines( _ ) und enden auch mit zwei Underlines. Dazwischen steht der Name in Großbuchstaben. Ein Beispiel ist die Programmkonstante __LINE__ . Sie gibt die Zeilenzahl zurück.
Es gibt im Grunde 2 Arten von Programmkonstanten:
- Die, die während des Parsens durch einen Wert ersetzt werden(einfache Programmkonstante)
- Die, die während der Laufzeit durch einen Wert ersetzt werden(Laufzeitkonstante)
Hier eine Tabelle der bis jetzt vorhandenen Programmkonstanten:
Name |
Typ |
Wird ersetzt durch… |
__LINE__ |
Einfache Programmkonstante |
…die Nummer der Zeile in der sie steht |
__FUNC__ |
Einfache Programmkonstante |
…den Namen der Funktion in der sie steht |
__TIMER__ |
Laufzeitkonstante |
…durch die Zeit in Millisekunden die seit dem Prozessorstart vergangen ist. |
___WINDOWS__ |
Einfache Programmkonstante |
… 1 wenn das Programm unter Windows ausgeführt wird und sonst 0. |
__MACOS__ |
Einfache Programmkonstante |
… 1 wenn das Programm unter Mac OS ausgeführt wird und sonst 0. |
__LINUX__ |
Einfache Programmkonstante |
… 1 wenn das Programm unter Linux ausgeführt wird und sonst 0. |
__CTIMER__ |
Einfache Programmkonstante |
… die Zeit in Millisekunden die vom Prozessorstart bis zum Anfang des Parsens vergangen ist. |
Durch die Programmkonstanten __TIMER__ und __CTIMER__ lässt sich leicht die Zeit ermitteln, die thasm zum Parsen gebraucht hat:
.text
main:
mov cx,__TIMER__
sub cx,__CTIMER__
mov cmd,cx
int print
int delay,1500
end
Also bei mir ist das eine Millisekunde. Ob das für eine Scriptsprache wenig oder viel ist weiß ich nicht genau, aber sehr schlecht kann es ja nicht sein.
Arrays (v0.77+)
Endlich habe ich es geschafft Arrays zu implementieren. Sie werden auf eine ganz einfache Art und Weise definiert und modifiziert. Dieses Beispiel soll das verdeutlichen:
.data
ar[50] int 0 'setzt alle Elemente auf 0
.text
main:
mov cx,0
mainloop:
mov ar[cx],cx
add cmd,ar[cx]
add cmd," ,"
inc cx
cmp 49,cx
jl mainloop
int print
int delay,1500
end
Die Arrays sollten sich mit diesem Beispiel selbst erklären.
Arithmetische und logische Operationen
Achtung: logische Operationen werden erst ab Version 0.75 vollständig unterstützt!
Arithmetik:
Höhere Programmiersprache |
Thasm |
x = x + y |
add x,y |
x = x - y |
sub x,y |
x = x * y |
mul x,y |
x = x / y |
div x,y |
Logik:
Höhere Programmiersprache |
Thasm |
x = x and y oder x = x & y |
and x,y |
x = x or y oder x = x | y |
or x,y |
x = x xor y oder x = (x | y) - (x & y) |
xor x,y |
x = -x |
neg x |
x = not x oder x = !x |
not x |