Lyx – Syntax-Referenz
Diese Seite ist die vollständige Syntax-Referenz für Lyx. Sie beschreibt alle lexikalischen Regeln, Operatoren, Kontrollstrukturen und Deklarationsformen. Für konzeptuelle Erläuterungen und Code-Beispiele zu einzelnen Themen existieren eigene Unterseiten (verlinkt am Ende jedes Abschnitts).
1. Lexikalische Regeln
Kommentare
// Einzeiliger Kommentar – bis zum Zeilenende
/* Mehrzeiliger Kommentar
Nicht verschachtelbar: /* kein weiterer /* */ hier */
Identifier
Bezeichner folgen dem Muster [A-Za-z_][A-Za-z0-9_]*. Lyx ist case-sensitive: MyVar, myVar und MYVAR sind drei verschiedene Bezeichner.
| Gültig | Ungültig |
|---|---|
counter, _tmp, Vec2 | 2fast (beginnt mit Zahl) |
MAX_SPEED, isReady | my-var (Bindestrich) |
x64, uart0 | for (Schlüsselwort) |
Schlüsselwörter
Reservierte Wörter, die nicht als Identifier verwendet werden dürfen:
and as break case class co
con continue default dispose do downto
else enum extends false fn for
if impl import is let limit
match mod new nil not or
override pub repeat return self struct
super to trait true type unit
unsafe until var virtual when while
2. Literale
Integer-Literale
| Format | Beispiel | Typ |
|---|---|---|
| Dezimal (Standard) | 42, -7 | int64 |
| Dezimal mit Suffix | 42i8, 255u8, 1000i32 | wie Suffix |
| Hexadezimal | 0xFF, 0x3FF44000 | int64 (oder mit Suffix) |
| Hexadezimal mit Suffix | 0xFFu8, 0x80u32 | wie Suffix |
Integer-Suffixe:
| Suffix | Typ | Suffix | Typ |
|---|---|---|---|
| (keiner) | int64 | u8 | uint8 |
i8 | int8 | u16 | uint16 |
i16 | int16 | u32 | uint32 |
i32 | int32 | u64 | uint64 |
Float-Literale
| Format | Beispiel | Typ |
|---|---|---|
| Dezimal (Standard) | 3.14, -0.5, 1.0 | f64 |
| Mit Suffix | 3.14f32, 0.0f32 | f32 |
Sonstige Literale
| Typ | Literal | Anmerkung |
|---|---|---|
| bool | true, false | |
| qbool | 0.5q, 0.0q, 1.0q | Wahrscheinlichkeitswert 0.0–1.0 |
| char | 'a', '\n' | ASCII, ein Zeichen |
| pchar | „Hallo\n“ | Nullterminierter String, Typ pchar |
| nil | nil | Null-Pointer für jeden Pointer-Typ |
String-Escape-Sequenzen
| Sequenz | Bedeutung |
|---|---|
\n | Zeilenumbruch (LF) |
\t | Tabulator |
\r | Wagenrücklauf (CR) |
\\ | Backslash |
\„ | Anführungszeichen |
\0 | Null-Byte (String-Terminator) |
3. Speicherklassen & Variablen
Jede Variable in Lyx trägt eine explizite Speicherklasse. Die Klasse bestimmt Mutabilität und Lebenszeit.
| Keyword | Mutabilität | Speicherort | Beschreibung |
|---|---|---|---|
var | Veränderlich | Stack / Data-Segment | Standard-Variable; Wert kann jederzeit geändert werden |
let | Einmalig | Stack / Data-Segment | Wert wird einmalig zur Laufzeit gesetzt, danach read-only |
co | Read-only | Stack | Schreibgeschützter Stack-Slot; ähnlich wie let, aber ohne Heap-Zugriff |
con | Compile-Zeit | Code (Immediate) | Compile-Zeit-Konstante; wird direkt in den Maschinencode eingebettet |
Syntax
var counter: int64 := 0; // Typ explizit, Wert zugewiesen
var name := "Lyx"; // Typ inferiert: pchar
let max_val: int64 := ReadConfig(); // Einmalige Zuweisung
co PI: f64 := 3.14159265358979; // Stack-Konstante
con MAX_BUFFER := 4096; // Compile-Zeit-Konstante (int64 inferiert)
- Der Zuweisungsoperator ist immer
:=. - Typangabe ist optional wenn der Typ aus dem Initialisierer eindeutig inferierbar ist.
pubvor der Speicherklasse macht die Variable aus anderen Units sichtbar:pub var x: int64 := 0;
4. Typsystem
Primitive Typen
| Typ | Bits | Wertebereich |
|---|---|---|
int8 | 8 | −128 … 127 |
int16 | 16 | −32 768 … 32 767 |
int32 | 32 | −2 147 483 648 … 2 147 483 647 |
int64 / int | 64 | −9 223 372 036 854 775 808 … 9 223 372 036 854 775 807 |
uint8 | 8 | 0 … 255 |
uint16 | 16 | 0 … 65 535 |
uint32 | 32 | 0 … 4 294 967 295 |
uint64 | 64 | 0 … 18 446 744 073 709 551 615 |
isize | Plattform | Pointer-Größe (signiert) |
usize | Plattform | Pointer-Größe (unsigniert); Standard für Indizes |
f32 | 32 | IEEE 754 Single |
f64 | 64 | IEEE 754 Double |
bool | 1 (8 im Speicher) | true, false |
qbool | 64 (f64) | Probabilistischer Typ; 0.0 … 1.0 |
char | 8 | Ein ASCII-Zeichen |
pchar | 64 (Pointer) | Nullterminierter String (char*) |
Pointer-Typen
var p: ^int64 := ^x; // Pointer auf int64 (Address-of: ^x)
var pp: ^(^int64) := ^p; // Pointer auf Pointer auf int64
var v: ^uint8 := nil; // Null-Pointer
p^ := 42; // Dereferenz (Schreiben)
PrintInt(p^); // Dereferenz (Lesen)
Alle Pointer sind intern 64-Bit-Integer. Der Cast ptr as int64 und addr as ^T ist explizit möglich.
Nullable Typen
Das ?-Suffix markiert einen Typ als nullable (kann nil sein):
var name: pchar? := GetOptionalName(); // darf nil sein
var node: BSTNode? := FindNode(key);
Range-Typen
type Altitude = int64 range -1000..60000;
type Speed = int64 range 0..300;
Compile-Zeit: Literale außerhalb des Bereichs → Fehler. Laufzeit: Nicht-konstante Zuweisung → panic.
5. Operatoren
Arithmetik
| Operator | Operation | Beispiel |
|---|---|---|
+ | Addition | a + b |
- | Subtraktion / Negation | a - b, -x |
* | Multiplikation | a * b |
/ | Division (ganzzahlig bei int) | a / b |
mod | Modulo (Rest) | a mod b |
++ | Inkrement (postfix) | i++ |
– | Dekrement (postfix) | i– |
Vergleich
| Operator | Bedeutung |
|---|---|
= | Gleich |
!= | Ungleich |
< | Kleiner als |
> | Größer als |
⇐ | Kleiner oder gleich |
>= | Größer oder gleich |
Wichtig: In Lyx ist=der Vergleichsoperator. Der Zuweisungsoperator ist:=. Es gibt kein==.
Logisch & Bitweise
| Operator | Bedeutung | Anwendung |
|---|---|---|
& | Logisches / Bitweises AND | bool-Ausdrücke und Integer-Maskierung |
| | Logisches / Bitweises OR | bool-Ausdrücke und Integer-Flags |
! | Logisches NOT | Nur auf bool |
~ | Bitweises NOT (Komplement) | Nur auf Integer |
^ | Bitweises XOR (Infix) | a ^ b |
« | Bitshift links | 1 « 3 = 8 |
» | Bitshift rechts | 0x80 » 4 = 8 |
Pointer vs. XOR:
Das Zeichen^hat je nach Position unterschiedliche Bedeutungen:
Präfix (^x) = Address-of-Operator, Postfix (p^) = Dereferenz, Infix (a ^ b) = Bitweises XOR.
Spezialoperatoren
| Operator | Name | Beschreibung | Beispiel |
|---|---|---|---|
:= | Zuweisung | Weist einen Wert zu | x := 42 |
|> | Pipe | Ergebnis links als erstes Argument rechts | val |> Abs() |
?. | Safe Call | Memberzugriff nur wenn nicht nil | node?.Next |
?? | Null-Coalesce | Fallback wenn nil | name ?? „Gast“ |
as | Cast | Explizite Typkonvertierung | x as f64 |
is | Typ-Test | Prüft Laufzeit-Typ | obj is Circle |
.. | Bereich | In match-Mustern und Range-Typen | 100..199 |
Operator-Präzedenz (absteigend)
| Priorität | Operatoren | Assoziativität |
|---|---|---|
| 1 (höchste) | Unär: !, ~, -, ^x (Adresse), p^ (Deref) | Rechts |
| 2 | *, /, mod | Links |
| 3 | +, - | Links |
| 4 | <<, » | Links |
| 5 | & | Links |
| 6 | ^ (XOR) | Links |
| 7 | | | Links |
| 8 | =, !=, <, >, ⇐, >= | Nicht-assoziativ |
| 9 | as, is | Links |
| 10 | ?. | Links |
| 11 | ?? | Rechts |
| 12 | |> | Links |
| 13 (niedrigste) | := | Rechts |
6. Kontrollfluss
if / else
if (Bedingung) {
// ...
} else if (andere_Bedingung) {
// ...
} else {
// ...
}
if ist kein Ausdruck – es gibt keinen ternären Operator ?:. Bedingte Werte werden über match oder Hilfsfunktionen ausgedrückt.
while
while (Bedingung) {
// ...
}
// Bounded – garantierte Terminierung
while (Bedingung) limit(Konstante) {
// ...
}
for
// Aufwärts (inklusive Grenzen)
for i := Startwert to Endwert do {
// i läuft von Startwert bis einschließlich Endwert
}
// Abwärts
for i := Endwert downto Startwert do {
// i läuft von Endwert bis einschließlich Startwert
}
Die Laufvariable wird automatisch inkrementiert / dekrementiert. Ihr Typ wird vom Compiler inferiert. for-Schleifen sind immer bounded – kein limit erforderlich.
repeat-until
repeat {
// Körper wird mindestens einmal ausgeführt
} until (Abbruchbedingung);
// Mit Bounded-Limit
repeat {
// ...
} until (Bedingung) limit(Konstante);
break & continue
while (true) {
if (DoneCondition()) { break; } // verlässt die innerste Schleife
if (SkipCondition()) { continue; } // springt zum nächsten Durchlauf
}
break und continue wirken immer auf die innerste umgebende Schleife.
match
match (Ausdruck) {
case Wert => Anweisung;
case A | B => Anweisung; // OR-Muster
case lo..hi => Anweisung; // Bereichsmuster
case X when (Guard) => Anweisung; // mit Guard-Bedingung
default => Anweisung;
}
match kann als Ausdruck verwendet werden (Ergebnis einer Case-Arm-Anweisung). Alle Fälle müssen abgedeckt sein (Exhaustivität). Details: Pattern Matching.
7. Funktionen
Deklaration
fn FunktionsName(param1: Typ1, param2: Typ2): RückgabeTyp {
// Körper
return Wert;
}
- Kein Rückgabewert: Rückgabetyp und
returnwerden weggelassen (implizitvoid). - Mehrere Rückgabewerte: Tupel-Syntax
(Typ1, Typ2). - Öffentliche Sichtbarkeit:
pubvoranstellen.
Beispiele
// Einfache Funktion
fn Add(a: int64, b: int64): int64 {
return a + b;
}
// Keine Rückgabe (void)
fn Log(msg: pchar) {
PrintStr(msg);
}
// Tupel-Rückgabe (mehrere Werte)
fn Divide(a: int64, b: int64): (int64, bool) {
if (b = 0) { return (0, false); }
return (a / b, true);
}
// Öffentlich
pub fn GetVersion(): pchar {
return "1.0.0";
}
Aufruf
var result := Add(3, 4);
var (quotient, ok) := Divide(10, 3);
if (ok) { PrintInt(quotient); }
// Pipe-Operator: Wert als erstes Argument
var v := -3.14 |> Abs() |> Round();
→ Funktionen (vertieft) — Tupel-Rückgabe, anonyme Funktionen, Higher-Order Functions, Pipe-Operator
8. Units & Imports
Jede Lyx-Quelldatei beginnt mit einer unit-Deklaration. Sie definiert den Namensraum der Datei.
unit my_module;
import std.io;
import std.math;
import my_project.utils;
unit-Name und Dateiname müssen übereinstimmen (my_module.lyx→unit my_module;).importmacht allepub-Symbole der Ziel-Unit sichtbar.- Standard-Bibliothek:
std.io,std.math,std.string,std.alloc,std.result,std.error, …
9. Typdefinitionen
struct
Stack-allozierte Wertetypen. Zuweisung kopiert den gesamten Wert.
type Vec2 = struct {
x: f64;
y: f64;
fn Length(): f64 {
return Sqrt(self.x * self.x + self.y * self.y);
}
fn Scale(factor: f64) {
self.x := self.x * factor;
self.y := self.y * factor;
}
};
class
Heap-allozierte Referenztypen. new erzeugt, dispose gibt frei.
type Animal = class {
name: pchar;
fn Create(n: pchar) {
self.name := n;
}
fn Destroy() {
// Aufräum-Logik
}
virtual fn Speak() {
PrintStr(self.name);
}
};
type Dog = class extends Animal {
override fn Speak() {
PrintStr("Wuff!");
}
};
var d := new Dog("Bello");
d.Speak(); // "Wuff!"
dispose d;
Schlüsselwörter für Klassen:
| Keyword | Bedeutung |
|---|---|
extends | Einfachvererbung |
virtual fn | Überschreibbare Methode (V-Table-Eintrag) |
override fn | Überschreibt eine virtuelle Methode |
abstract fn | Muss in abgeleiteten Klassen implementiert werden |
super.Methode() | Aufruf der Eltern-Implementierung |
self | Referenz auf das aktuelle Objekt |
new T(args) | Heap-Allokation |
dispose ptr | Heap-Freigabe |
enum
enum Richtung { Nord, Sued, Ost, West }
enum StatusCode {
Ok = 200,
NotFound = 404,
Error = 500
}
// Zugriff über ::
var d := Richtung::Nord;
var s := StatusCode::Ok;
match über Enums prüft Exhaustivität: Fehlt ein Fall, erzeugt der Compiler einen Fehler.
trait & impl
trait Printable {
fn Print();
fn ToString(): pchar; // muss implementiert werden
}
type Point = struct { x: int64; y: int64; };
impl Printable for Point {
fn Print() {
PrintStr(self.ToString());
}
fn ToString(): pchar {
return FormatStr("(%d, %d)", self.x, self.y);
}
}
Generics mit Trait-Schranken:
fn PrintAll<T: Printable>(items: [16]T) {
for i := 0 to 15 do {
items[i].Print();
}
}
10. Generics
// Generische Funktion
fn Max<T: Comparable>(a: T, b: T): T {
if (a > b) { return a; }
return b;
}
// Generischer Struct
type Stack<T> = struct {
data: [64]T;
top: int64;
fn Push(val: T) {
self.data[self.top] := val;
self.top++;
}
fn Pop(): T {
self.top--;
return self.data[self.top];
}
};
// Mehrere Schranken mit +
fn Process<T: Printable + Comparable>(val: T) {
val.Print();
}
11. Attribute & Pragmas
Attribute beginnen mit @ und stehen unmittelbar vor dem annotierten Element (Unit, Funktion, Variable).
Sicherheit & Zertifizierung
| Attribut | Ziel | Beschreibung |
|---|---|---|
@flight_crit | Unit, Fn | Strikte Luftfahrt-Regeln: kein Heap, keine unsafe-Blöcke |
14. Vollständige Grammatik-Übersicht (kompakt)
Program → (Unit Import* Decl*)?
Unit → 'unit' Ident ';'
Import → 'import' QualIdent ';'
Decl → VarDecl | FnDecl | TypeDecl | TraitDecl | ImplDecl
VarDecl → Modifier? StorageClass Ident (':' Type)? ':=' Expr ';'
StorageClass → 'var' | 'let' | 'co' | 'con'
Modifier → 'pub'
FnDecl → Attr* Modifier? 'fn' Ident GenericParams? '(' Params ')' (':' Type)? Block
Params → (Ident ':' Type (',' Ident ':' Type)*)?
TypeDecl → 'type' Ident GenericParams? '=' ('struct' | 'class' ('extends' Ident)?) '{' Member* '}'
EnumDecl → 'enum' Ident '{' (Ident ('=' IntLit)? (',' Ident ('=' IntLit)?)*)? '}'
TraitDecl → 'trait' Ident '{' FnSignature* '}'
ImplDecl → 'impl' Ident 'for' Ident '{' FnDecl* '}'
Block → '{' Stmt* '}'
Stmt → VarDecl | ExprStmt | IfStmt | WhileStmt | ForStmt | RepeatStmt
| MatchStmt | ReturnStmt | BreakStmt | ContinueStmt | UnsafeBlock
IfStmt → 'if' '(' Expr ')' Block ('else' 'if' '(' Expr ')' Block)* ('else' Block)?
WhileStmt → 'while' '(' Expr ')' ('limit' '(' IntLit ')')? Block
ForStmt → 'for' Ident ':=' Expr ('to' | 'downto') Expr 'do' Block
RepeatStmt → 'repeat' Block 'until' '(' Expr ')' ('limit' '(' IntLit ')')? ';'
MatchStmt → 'match' '(' Expr ')' '{' MatchArm* '}'
MatchArm → ('case' Pattern ('when' '(' Expr ')')? | 'default') '=>' Stmt ';'
Expr → ... (vollständige Präzedenz-Hierarchie; siehe Abschnitt 5)
Weiterführende Seiten:
