Phase 0: Referenzdokumente, Fehlerkatalog, Testkorpus, Ratatui-Spike
Entscheidungen festgehalten: TBVM bestaetigt und eingebettet in die Executables; durchgaengig UTF-8 statt CP437 (dokumentierte Abweichung). - docs/: Sprachreferenz, Forms-Referenz, Dateiformate, TBVM-Design - tb-runtime::errors: klassischer Laufzeitfehler-Katalog (implementiert) - tb-ui::screen: 80x25-Unicode-Zellenpuffer mit 16-Farben-Abbildung, Scrollbereich (VIEW PRINT), Letterboxing; Ratatui-Widget + Tests - Spike: cargo run -p tb-ui --example spike (Farben, Unicode, Tasten, Maus) - tests/compat/: erste Referenzprogramme mit byte-genauer Sollausgabe Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
85
docs/tbvm-design.md
Normal file
85
docs/tbvm-design.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# TBVM — Designentwurf
|
||||
|
||||
Eigene Stack-basierte Bytecode-VM (Entscheidung siehe PLAN.md, 0.2).
|
||||
Die VM ist in `tbdos` (IDE) und in von `tbdosc` erzeugte Executables
|
||||
eingebettet — identischer Code, identisches Verhalten, schneller Turnaround.
|
||||
|
||||
## Werte-Modell
|
||||
|
||||
Tagged Enum, kein NaN-Boxing (Einfachheit und Debugbarkeit vor Mikro-
|
||||
performance):
|
||||
|
||||
```rust
|
||||
enum Value {
|
||||
Int(i16), // INTEGER
|
||||
Long(i32), // LONG
|
||||
Single(f32), // SINGLE
|
||||
Double(f64), // DOUBLE
|
||||
Currency(i64), // CURRENCY, Festkomma ×10 000
|
||||
Str(Rc<str>), // STRING (immutabel geteilt; Copy-on-Write bei MID$-Anweisung)
|
||||
// Arrays und TYPE-Instanzen leben im Heap-Bereich der VM,
|
||||
// Variablen-Slots referenzieren sie per Handle (Rc<RefCell<…>>).
|
||||
}
|
||||
```
|
||||
|
||||
- Kein GC nötig: der Dialekt kennt keine Zyklen (keine Objektreferenzen in
|
||||
TYPEs, keine Closures) → `Rc` genügt.
|
||||
- Feste Strings (`STRING * n`) und TYPE-Records werden als eigene
|
||||
Speicherobjekte mit fester Zeichen-/Elementstruktur geführt.
|
||||
|
||||
## Bytecode
|
||||
|
||||
- Stack-Maschine, Opcodes 1 Byte + Operanden variabler Länge (u8/u16/u32,
|
||||
little-endian).
|
||||
- **Modul-Struktur:** Konstantenpool (Strings, Zahlen), Typtabelle
|
||||
(TYPE-Layouts), Prozedurtabelle (Signatur, Locals-Anzahl, Code-Offset),
|
||||
globale Slots, DATA-Segment (für READ/RESTORE), Zeilentabelle.
|
||||
- **Zeilentabelle:** Abbildung Code-Offset → (Moduldatei, Zeile). Grundlage
|
||||
für `ERL`, Fehlermeldungen, Breakpoints und Einzelschritt.
|
||||
- **Aufrufkonventionen:**
|
||||
- SUB/FUNCTION: eigener Frame (Locals-Slots, Operandenstack-Basis);
|
||||
BYREF-Parameter als Referenz-Slots (Handle auf Variablen-Slot).
|
||||
- GOSUB: **kein** Frame — Rücksprungadresse auf separatem GOSUB-Stack im
|
||||
aktuellen Frame (RETURN prüft diesen zuerst).
|
||||
- **Fehlerbehandlung:** Pro Frame ein Handler-Zustand (`ON ERROR GOTO x`).
|
||||
Laufzeitfehler → VM sucht aktiven Handler im aktuellen Modulkontext
|
||||
(Vorbild: Handler sind modul-/prozedurlokal, TODO: exakte Scoping-Regel
|
||||
testen), setzt `ERR`/`ERL`, springt. `RESUME` nutzt gemerkten
|
||||
Anweisungs-Offset.
|
||||
|
||||
## Ausführungsmodell / Unterbrechbarkeit
|
||||
|
||||
- Die Interpreterschleife läuft in **Ticks**: nach jeder Anweisung (Grenze
|
||||
aus der Zeilentabelle) prüft sie ein Flag-Set: Breakpoint? Einzelschritt?
|
||||
Strg+Untbr? Ereignis-Queue nicht leer und Zustellung erlaubt?
|
||||
- Ereigniszustellung (Forms, Timer) erfolgt kooperativ: nur an
|
||||
Zustellpunkten (`DOEVENTS`, `SLEEP`, blockierende Eingabe, Ende einer
|
||||
Ereignisprozedur) — wie im Vorbild.
|
||||
- Die VM ist eine gewöhnliche zustandsbehaftete Struktur, `step()`-basiert;
|
||||
die einbettende Schleife (IDE-Debugger oder Runner) treibt sie. Kein
|
||||
eigener Thread nötig; Terminal-Events werden zwischen Ticks gepollt.
|
||||
|
||||
## `.tbc`-Container (Entwurf)
|
||||
|
||||
```
|
||||
Magic "TBC\0" · Formatversion u16 · Flags
|
||||
Abschnittstabelle: [ (Kennung, Offset, Länge) ]
|
||||
Abschnitte: CONSTS, TYPES, PROCS, CODE, DATA, LINES, FORMS (serialisierte .FRM-Beschreibungen)
|
||||
```
|
||||
|
||||
Serialisierung mit einfachem eigenem Writer/Reader (kein serde nötig,
|
||||
Format bleibt stabil und dokumentiert).
|
||||
|
||||
## Eigenständige Executables
|
||||
|
||||
`tbdosc build --exe` kopiert den vorkompilierten Runner (dieselbe
|
||||
tb-vm/tb-runtime/tb-ui-Bibliothek wie die IDE) und hängt das `.tbc` als
|
||||
Ressource an (Anhängen ans Binary + Fußzeile mit Offset/Magic; portabel für
|
||||
alle drei Plattformen). Alternative — `include_bytes!` + Cargo-Build beim
|
||||
Nutzer — verworfen: erfordert Rust-Toolchain beim Anwender.
|
||||
|
||||
## Offene Punkte
|
||||
|
||||
- Opcode-Satz konkret ausformulieren (mit Phase 2)
|
||||
- Zahlenkonvertierungs-Matrix (implizite Casts, Rundung, Überlauf) als Tabelle
|
||||
- Verhalten von `STOP`/`CONT` im Runner (ohne IDE): Abbruch mit Meldung?
|
||||
Reference in New Issue
Block a user