Programmieren mit .ae
Die eigene Sprache von AetherOS hat deutsche Befehle. Diese Seite zeigt die Grundlagen – Schritt für Schritt, mit echter Schreibweise aus dem Compiler. Jeder Befehl, der hier vorkommt, steht in der Liste der 22 Schlüsselwörter in lexer.js – nur und und oder liest er als Rechenzeichen; wo der Übersetzer für den Kernel etwas noch nicht kann, steht es direkt dabei.
1 · Kommentare
Alles hinter // ist eine Notiz für Menschen. Der Compiler überliest es bis zum Ende der Zeile. Ein Kommentar darf auch hinter einer Anweisung stehen, wie im Beispiel auf der Sprachseite. Im Kernel erklären Kommentare oft Zahlen, die man sonst nachschlagen müsste – etwa „KBC Reset-Befehl an Port 0x64“ hinter einem Neustart-Befehl.
// Das ist ein Kommentar2 · Werte merken
variabel legt einen Wert an, der sich ändern darf. fest legt einen Wert an, der gleich bleibt. Beide brauchen sofort einen Anfangswert hinter dem Gleichheitszeichen. Namen dürfen Umlaute und ß enthalten, Ziffern aber erst ab der zweiten Stelle – ein Name wie 2te geht nicht, zweite2 schon. Feste Werte schreibt der Kernel groß, damit man sie auf einen Blick erkennt – alle 132, gezählt am 27. September 2026. Der Compiler verlangt das nicht, es ist Absprache.
fest MAXIMUM = 10
variabel zähler = 0
zähler = zähler + 13 · Rechnen und vergleichen
Gerechnet wird mit + - * / %, verglichen mit == != < > <= >=. Für einzelne Bits gibt es & | ^ ~ << >>. Bedingungen verbindet man mit und und oder. Zahlen dürfen auch hexadezimal stehen, etwa 0xB8000. % liefert den Rest einer Teilung, & mit 255 behält nur das unterste Byte – beides braucht der Kernel ständig, wenn er Zahlen für den Bildschirm zerlegt. Geteilt wird ganzzahlig: 17 / 5 ergibt 3, der Rest 2 geht verloren.
variabel fläche = breite * höhe
variabel rest = 17 % 5
variabel unten = wert & 255Im Kernel sind Zahlen 16 Bit groß: von 0 bis 65.535. Was darüber hinausgeht, fängt wieder unten an. Vergleiche rechnen dabei mit Vorzeichen: Ab 32.768 gilt eine Zahl in < und > als negativ und damit als kleiner als 1. Große Adressen besser nicht mit < prüfen – mehr dazu auf der Sprachseite.
4 · Entscheiden
wenn prüft eine Bedingung, sonst sagt, was andernfalls passiert, ende schließt ab. Ein ende gehört immer zum ganzen Block, auch wenn es einen sonst-Teil gibt – es sind also nie zwei. Die Einrückung ist nur für Menschen da; der Compiler schaut allein auf die Wörter.
wenn zähler >= MAXIMUM
zähler = 0
sonst
zähler = zähler + 1
ende
Zeilenumbrüche zählen nicht: Der Lexer wirft sie weg und merkt sich nur die Zeilennummer für Fehlermeldungen. Deshalb darf ein ganzer Block auch in einer Zeile stehen. Diese Zeile steht genau so am Anfang des Kernels – sie sorgt dafür, dass er nur einmal startet:
wenn kernel_booted == 1 rueckgabe 0 endeVorsicht mit und und oder: Der Übersetzer für den Kernel prüft verknüpfte Bedingungen bisher nicht – der Teil dahinter läuft dann immer. Sicher ist heute ein wenn im wenn, je mit einem einzelnen Vergleich. Im Kernel betrifft das 130 von 1.193 Bedingungen, gezählt am 23. September 2026 – ein bekannter Fehler, kein Stil. Warum das so ist
5 · Wiederholen
solange wiederholt, solange eine Bedingung stimmt. Geprüft wird vor jedem Durchgang – stimmt sie schon am Anfang nicht, läuft der Rumpf kein einziges Mal. wiederhole … mal wiederholt eine feste Anzahl. Es liest sich leichter, doch der Übersetzer für den Kernel kann es noch nicht; dort zählt man mit solange und einer eigenen Variable, wie im ersten Beispiel.
variabel i = 0
solange i < 10
i = i + 1
ende
wiederhole 3 mal
zähler = zähler + 1
ende6 · Funktionen
funktion gibt einem Stück Code einen Namen. rueckgabe liefert ein Ergebnis zurück – dahinter muss immer ein Wert stehen, ein leeres rueckgabe kennt der Parser nicht. Mehrere Werte in der Klammer trennt ein Komma. Im Kernel liegen die Werte einer Funktion an festen Stellen im Speicher: Eine Funktion, die sich selbst aufruft, würde ihre eigenen Werte überschreiben.
funktion quadrat(zahl)
rueckgabe zahl * zahl
ende
variabel neun = quadrat(3)7 · Andere Dateien einbinden
lade bindet eine andere .ae-Datei ein – so teilt sich der Kernel auf viele Dateien auf. Der Name steht in Anführungszeichen und gilt vom Ordner der ladenden Datei aus. Jede Datei kommt nur einmal hinein, auch wenn sie mehrfach geladen wird. So bleibt jede der 64 .ae-Dateien im Kernel-Ordner unter der 300-Zeilen-Grenze des Regelwerks; die längste hat am 27. September 2026 298 Zeilen.
lade "kernel_string.ae"8 · Nah an der Hardware
Zeiger
zeiger zeigt auf eine Adresse im Speicher. So schreibt der Kernel zum Beispiel direkt in den Bildschirmspeicher. Mit eckigen Klammern wählt man eine Stelle dahinter, etwa vga[index * 2]. Unterhalb der Adresse 1024 lässt der Übersetzer nichts schreiben – dort liegt die Tabelle für Unterbrechungen.
Ports
Mit eigenen Befehlen lassen sich Hardware-Ports lesen und beschreiben: lese_port und schreibe_port für 8 Bit, dazu je eine Fassung mit 16 am Ende. Über Ports fragt der Kernel die Tastatur ab, liest die Uhr und schaltet den Lautsprecher.
Maschinencode
asm bettet Befehle für den Prozessor direkt ein – nur für Fortgeschrittene. Der Befehl steht als Text dahinter, etwa asm "cli". Rund 80 Befehle kennt der Übersetzer beim Namen; ein Tippfehler darin fällt ohne Warnung weg.
Diese Befehle braucht ein Betriebssystem, weil unter ihm niemand mehr ist, der die Arbeit mit der Hardware abnimmt. Für die ersten Schritte sind sie nicht nötig.
9 · Auf den Bildschirm schreiben
text_setzen schreibt einen Text an eine Stelle des Bildschirms. Die Reihenfolge ist Spalte, Zeile, Text, Farbe. zahl_setzen macht dasselbe mit einer Zahl. Beide schreiben direkt in den Textbildschirm – es gibt kein Fenster und keine Konsole dazwischen, die mitscrollt. Was an einer Stelle stand, wird einfach überschrieben.
fest WEISS = 15
fest GELB = 14
text_setzen(0, 0, "Hallo Aerona", WEISS)
zahl_setzen(0, 1, zähler, GELB)
- Der Bildschirm hat 80 Spalten und 25 Zeilen, gezählt wird ab 0. Liegt die Stelle außerhalb, wird nichts geschrieben.
- Der Text muss direkt in Anführungszeichen stehen. Eine Variable ist an dieser Stelle nicht erlaubt – der Parser verlangt hier ausdrücklich einen Text und meldet sonst „Erwartet TEXT …, aber fand …“.
- Die Farbe ist ein Byte: Hintergrund mal 16 plus Schrift. Die 16 Farben heißen im Kernel
COLOR_BLACK(0) bisCOLOR_WHITE(15) – 1 ist Blau, 4 Rot, 14 Gelb. 15 ist also Weiß auf Schwarz, und 112 (7 × 16) ist Schwarz auf Hellgrau: So zeichnet der Kernel seine Uhr. - Der x86-Übersetzer zeigt von der Zahl das unterste Byte als zwei hexadezimale Ziffern: Aus 26 wird
1A.
10 · Die Reihenfolge beim Rechnen
Zuerst rechnet der Compiler *, / und %. Alles andere liest er streng von links nach rechts – auch Vergleiche, und und oder. Das ist anders als in den meisten Sprachen, in denen ein Vergleich erst nach dem Rechnen kommt. Der Parser kennt nur diese zwei Stufen, nachzulesen am Anfang von parser-expr.js; auch die Bit-Zeichen &, | und << stehen auf der unteren.
// wird gelesen als (a == b) - 1
wenn a == b - 1
a = 0
ende
// so ist es eindeutig
wenn a == (b - 1)
a = 0
endeIm Zweifel Klammern setzen. Sie machen die Absicht klar und erzeugen keinen zusätzlichen Code. Das Beispiel oben baut der Compiler ohne Meldung – der Fehler zeigt sich erst beim Laufen.
11 · Wenn der Compiler sich meldet
Findet der Compiler einen Fehler, bricht er ab und nennt meist die Zeile. Lexer und Parser kennen vier Meldungen. Eine Vorsicht vorweg: Die Zeilennummer zählt im zusammengesetzten Text, nachdem alle lade-Anweisungen aufgelöst sind – beim Kernel ist das nicht die Zeile in der einzelnen Datei. Und das Bauskript bauen.bat schreibt am Ende immer „FERTIG!“, auch nach einem Fehler; die Meldung steht in den Zeilen darüber.
| Meldung | was sie meist bedeutet |
|---|---|
| Unbekanntes Zeichen | Im Quelltext steht ein Zeichen, das .ae nicht kennt – etwa ein Semikolon oder ein Punkt. |
| Unerwarteter Befehl | Wo eine Anweisung beginnen müsste, steht etwas anderes. |
| Erwarte Faktor | An dieser Stelle fehlt ein Wert, zum Beispiel nach einem Rechenzeichen. |
| Erwartet …, aber fand … | Ein bestimmtes Wort oder Zeichen fehlt, etwa eine Klammer. Steht dort „Dateiende“, fehlt oft ein ende. |
Dazu kommen drei Meldungen außerhalb von Lexer und Parser:
- „Konnte die Datei … nicht finden“ – die Startdatei fehlt.
- „Enthaltene Datei … existiert nicht“ – eine
lade-Anweisung zeigt ins Leere. - „Code-Bereich überschneidet sich mit String-Bereich“ – das Programm ist zu groß geworden: Der Code wächst von vorn, die Texte von hinten, und irgendwo stoßen sie zusammen. Die Meldung nennt die Funktion, in der es passiert ist.
12 · Ein echtes Stück Kernel, Zeile für Zeile
Alles bisher Gezeigte steckt in dieser Funktion aus kernel_main.ae. Sie schreibt auf den Bildschirm, wie viel Speicher der Buddy-Verwalter in jeder seiner fünf Größenstufen noch frei hat – wörtlich aus dem Kernel:
funktion print_buddy_lists()
variabel o = 0
solange o <= 4
variabel val = buddy_get_free_list(o)
text_setzen(0, 12 + o, "ORDER ", 15)
zahl_setzen(6, 12 + o, o, 15)
text_setzen(8, 12 + o, ": ", 15)
zahl_setzen(10, 12 + o, val / 256, 15)
zahl_setzen(12, 12 + o, val & 255, 15)
o = o + 1
ende
ende- Zählen.
oläuft von 0 bis 4 – eine Zeile je Größenstufe. - Fragen.
buddy_get_free_list(o)liefert, was in dieser Stufe frei ist. - Hinschreiben. Ab Zeile 12 des Bildschirms, jede Stufe eine Zeile tiefer, in Weiß (15).
- Zerlegen.
zahl_setzenzeigt nur ein Byte als zwei Ziffern. Deshalb schreibt die Funktion die obere Hälfte (val / 256) und daneben die untere (val & 255) – zusammen vier Ziffern für eine 16-Bit-Zahl.
13 · Was es noch nicht gibt
- Nur ganze Zahlen: Einen Punkt wie in 3.5 kennt der Compiler nicht. Der Lexer bricht beim Punkt mit „Unbekanntes Zeichen“ ab.
- Ein Anführungszeichen innerhalb eines Textes geht nicht – der Text endet dort. Einen Ausweg wie
\"gibt es nicht; umgekehrt läuft ein vergessenes schließendes Zeichen bis zum nächsten Anführungszeichen weiter, auch über Zeilen hinweg. - Kommentare gibt es nur mit
//, für jede Zeile einzeln. Einen längeren Abschnitt stilllegen heißt also, vor jede Zeile zwei Schrägstriche zu setzen. - Ruft man eine Funktion, die es nicht gibt, meldet der Übersetzer für den Kernel keinen Fehler: Es passiert schlicht nichts, und in einer Rechnung steht an ihrer Stelle 0.
- Ein
zeigerliest und schreibt immer genau ein Byte. Für eine 16-Bit-Zahl braucht es deshalb zwei Zugriffe, wie beim Zerlegen im Beispiel oben. wiederhole … malversteht der Parser. Der x86-Übersetzer für den Kernel erzeugt dafür aber noch keinen Code, und der Kernel selbst kommt ohnewiederholeaus.- Ein eigenes „sonst wenn“ fehlt. Ein zweites
wennsteht imsonst-Teil und braucht sein eigenesende:
wenn zähler == 0
zähler = 1
sonst
wenn zähler == 1
zähler = 2
ende
ende





