Setzt den OpenSpec-Change phase-3-runtime-bildschirm um (77/77 Aufgaben). Abdeckung laut Inventar: 195 implementiert, 37 offen, 53 Non-Feature. Vollstaendigkeits-Inventar - docs/inventar.md mit 285 Eintraegen aus den Themenlisten von bas7advr.hlp und qb45advr.hlp, je mit Status und Fundstelle - crates/tb-frontend/tests/inventar.rs haelt die Tabelle in beide Richtungen gegen den Code; der Abdeckungsstand kann nicht veralten Bruchschritt (Puffer, Host, Korpus) - Cell/TextScreen ziehen ratatui-frei nach tb-runtime::screen; tb-ui behaelt Farbabbildung, Widget und den neuen Terminal-Host - Host wechselt vom Zeichenstrom auf Anzeige des Zellenpuffers plus Ereignisse (Taste, Groessenaenderung, Abbruch) - Korpusvergleich auf getrimmten Bildschirm-Snapshot; die acht bestehenden Sollausgaben blieben dabei unveraendert Groessenunabhaengigkeit - 80x25 ist nirgends mehr eine feste Grenze; Groessenaenderungen waehrend der Ausfuehrung werden zugestellt (Inhalt oben links erhalten, Cursor und VIEW PRINT geklemmt) - Korpusnachweis: dasselbe Programm bei 80x25 und 120x40 mit je eigener Sollausgabe, plus ein Programm mit Groessenwechsel mitten im Lauf Bibliothek - Breite Unicode-Zeichen belegen zwei Zellen (Cursor, POS, Randumbruch) - Bildschirm: CLS, COLOR, LOCATE, WIDTH, VIEW PRINT, SCREEN, CSRLIN, POS - Tastatur: INKEY$, INPUT$, Funktionstasten-Makros (KEY n / LIST / ON) - PRINT USING, LPRINT USING, FORMAT$, SetFormatCC - Mathematik mit kompatiblem PRNG (gleiche Saat, gleiche Folge) - Datum und Zeit mit Serienwerten ab 1899 - Finanzmathematik: FV#, PV#, Pmt#, IPmt#, PPmt#, NPer#, Rate#, NPV#, IRR#, MIRR#, SLN#, SYD#, DDB# - Datei-E/A: sequenziell, RANDOM (Recordpuffer und UDT-Variablen), BINARY, FIELD/LSET/RSET, Statusfunktionen, Dateisystem, MK$/CV - System: ENVIRON, FRE, CLEAR, TRON/TROFF, STACK, ERDEV, ERR-Anweisung Altlasten aus Phase 2 - ON ERROR GOTO auf Modulebene ist aus Prozeduren ansprechbar (prozeduruebergreifender Fixup im Codegenerator) - DATA behaelt seinen Rohtext (Gross-/Kleinschreibung, innerer Leerraum) - Die vier TODO-verify-Zellen der Konvertierungsmatrix sind aufgeloest Vom Inventar aufgedeckte Fehler - Zwoelf Non-Features wies der Compiler entgegen der Phase-1-Spec nicht ab (CALLS, SSEG, POINT, VIEW, COM, PEN, STRIG, STICK, die String*-Routinen, LINE und OPEN "COMn:") -- geschlossen - Drei Gruppen fehlten im urspruenglichen Umfang: Finanzmathematik, Record-Konvertierung, Rest der Dateisystemfunktionen - bas7advr.hlp allein ist keine vollstaendige Quelle; das Inventar bildet die Vereinigung mit qb45advr.hlp Neue Changes - phase-3-isam: schliesst Phase 3 ab (Speicherschicht redb) - phase-3-ortszeit: zieht die UTC-Abweichung zurueck Neue Abhaengigkeit: unicode-width. Dokumentiert: sprachreferenz.md und tbvm-design.md sind TODO-frei, docs/bibliothek.md neu, PLAN.md fortgeschrieben. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
17 KiB
TBVM — Designentwurf
Eigene Stack-basierte Bytecode-VM (Entscheidung siehe PLAN.md, 0.2).
Die VM ist in tb (IDE) und in von tbc erzeugte Executables
eingebettet — identischer Code, identisches Verhalten, schneller Turnaround.
Werte-Modell
Tagged Enum, kein NaN-Boxing (Einfachheit und Debugbarkeit vor Mikro- performance):
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) →
Rcgenü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: Zwei Ebenen (Scoping geklärt 2026-09-04).
ON LOCAL ERROR GOTO xsetzt einen Handler im aktuellen Frame; sein Sprungziel muss im selben Rumpf liegen.ON ERROR GOTO xohneLOCALsetzt den modulweiten Handler — auch aus einer Prozedur heraus, und sein Sprungziel liegt dann im Modulrumpf (der Codegenerator löst es über Prozedur 0 auf, die zuerst übersetzt wird). Ein Laufzeitfehler sucht zuerst lokale Handler die Aufrufkette hinauf, dann den modulweiten; beim modulweiten wird bis Frame 0 abgewickelt, weshalbRESUME NEXTdort hinter dem Prozeduraufruf fortsetzt. Der Handler setztERR/ERL;RESUMEnutzt den gemerkten Anweisungs-Offset. Ein Fehler im Handler ist fatal (keine Kaskaden).
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 (Stand Phase 2, Formatversion 1)
Magic "TBC\0" · Formatversion u16 · Flags u16 · Abschnittsanzahl u32
Abschnittstabelle: [ (Kennung 4 Byte, Offset u32, Länge u32) ]
Abschnitte:
MODN Modulname + OPTION BASE
CONS deduplizierter Stringpool
TYPS TYPE-Layouts (Feld-Initialisierungstypen)
GLOB globale Slots (Initialisierungstyp + Name für Debugger)
PROC Prozedurtabelle: Name, Parameteranzahl, Frame-Slots, Code
(Zeileninfo liegt inline im Code: Stmt-/SetErl-Instruktionen —
ersetzt den früher geplanten separaten LINES-Abschnitt)
DATA DATA-Konstanten (Rohtext + Quellzeile)
JMPT Sprungtabellen für ON n GOTO/GOSUB
FORMS (ab Phase 4: serialisierte .FRM-Beschreibungen)
Serialisierung mit einfachem eigenem Writer/Reader (kein serde nötig,
Format bleibt stabil und dokumentiert); unbekannte Formatversionen
werden mit Meldung abgewiesen. Instruktions-Encoding: 1 Opcode-Byte +
Operanden little-endian, Opcode-Bytes gruppenweise mit Lücken vergeben
(crates/tb-vm/src/bytecode.rs ist die normative Liste).
Eigenständige Executables
tbc 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.
Performance
Compiler (Instant-Compile, Anforderung siehe PLAN.md):
- Single-Pass pro Modul: Lexen, Parsen und Codegen in einem Durchlauf; Vorwärtsreferenzen (Prozeduren, Labels) über Fixup-Listen statt zweitem Pass. Die Sprache ist dafür gemacht — das Vorbild kompilierte auf 1992er-Hardware gefühlt sofort.
- Modulweise inkrementell:
.BAS/.FRMwerden unabhängig zu Bytecode- Einheiten übersetzt und beim Build nur zusammengebunden; die IDE recompiliert nur geänderte Module (Hash über Quelltext). - Keine Optimierungspasses. Erlaubt sind nur Gratis-Optimierungen im Codegen (Konstantenfaltung im Ausdruck, Peephole beim Emit).
- Budget als Test verankern (Phase 2): Benchmark-Projekt (~50k Zeilen) muss unter 1 s kompilieren (Release-Build der Toolchain, Referenzrechner); einzelnes Modul < 50 ms.
VM-Ausführung:
- Alle Namen werden zur Compilezeit aufgelöst: Variablen/Parameter sind Slot-Indizes, Prozeduren Tabellenindizes — zur Laufzeit keine Hash-Lookups.
- Statische Typen des Dialekts ausnutzen: typisierte Opcodes
(
ADD_I16,ADD_F64,CONCAT…) statt generischem Dispatch überValue-Tags in heißen Pfaden. - Dichte Opcodes,
match-Dispatch in einer engen Schleife; Tick-Prüfung (Events/Breakpoints) nur an Anweisungsgrenzen über ein einzelnes Flag-Wort, nicht pro Opcode. - Strings immutabel via
Rc<str>(Kopien sind Pointer-Kopien); Konstantenpool dedupliziert. - Messlatte (Phase 2, Benchmarks in
benches/): typische Schleifen-/String-Lasten mindestens ~100× schneller als das Vorbild auf Originalhardware; Richtwert grob Lua-Interpreter-Klasse, gemessen und dokumentiert statt geraten.
Benchmark-Ergebnisse (2026-09-02, Release-Build, Entwicklerrechner
Windows 11, cargo bench -p tb-vm):
-
Compile-Budget (
benches/compile.rs):- Einzelmodul, 508 Zeilen: 1,2 ms (Budget 50 ms — eingehalten)
- Projekt, 49 760 Zeilen über 20 Module: 124 ms (Budget 1 000 ms — eingehalten); Durchsatz ≈ 400 000 Zeilen/s
-
VM-Durchsatz (
benches/vm.rs):- INTEGER-Schleife (Arithmetik + MOD): ≈ 4,8 Mio Iterationen/s
- DOUBLE-Schleife: ≈ 5,2 Mio Iterationen/s
- SUB-Aufrufe mit BYREF: ≈ 5,2 Mio Aufrufe/s
- String-Lasten (MID$/INSTR/Verkettung): ≈ 0,8 Mio Runden/s
Nachmessung nach Phase 3 (2026-09-04, macOS, Apple Silicon,
cargo bench -p tb-vm) — die Zustellpunkte des neuenHost(Anzeige nur bei geändertem Bildschirm, Ereignisabholung alle 1024 Anweisungen) kosten nichts Messbares:
-
Compile-Budget: Einzelmodul 508 Zeilen 0,77 ms; Projekt 49 760 Zeilen 53 ms (≈ 950 000 Zeilen/s)
-
VM-Durchsatz: INTEGER-Schleife 11,0 Mio/s, DOUBLE 12,2 Mio/s, SUB-Aufrufe 10,7 Mio/s, String-Lasten 2,4 Mio Runden/s
(Die höheren Zahlen gegenüber 2026-09-02 gehen auf die andere Maschine zurück, nicht auf eine Optimierung — gemessen wurde beide Male derselbe Benchmark.)
- Einordnung: bei ≈ 13 Instruktionen je Schleifeniteration entspricht das ≈ 60 Mio Instruktionen/s — Vorbild-Programme auf 1992er-Hardware werden um weit mehr als den Faktor 100 übertroffen; für 80×25- Terminalprogramme mehr als ausreichend. Ein Performance-Pass ist erst bei Bedarf vorgesehen (Phase 6).
Zahlenkonvertierungs-Matrix (Feindesign, 2026-09-02)
Grundlage: Original-Hilfe (Topics „Arithmetic Operators", „CINT/CLNG",
„MOD", „Numeric Types"). Vier Punkte sind dort nicht geregelt; sie
wurden am 2026-09-04 entschieden und sind unten als Projektentscheidung
gekennzeichnet — sie gelten damit als bewusste Festlegung, nicht als
rekonstruiertes Vorbildverhalten. Der Korpustest konvertierung.bas
verankert die Matrix ausführbar.
Rangfolge für Promotion: INTEGER < LONG < CURRENCY < SINGLE < DOUBLE. Ausnahme: CURRENCY gemischt mit SINGLE oder DOUBLE ergibt DOUBLE (nicht SINGLE). Projektentscheidung 2026-09-04: Die Original-Hilfe regelt diesen Fall nicht. CURRENCY trägt 19 signifikante Stellen, SINGLE nur 7 — eine Promotion nach SINGLE zerstörte genau die Genauigkeit, für die es den Typ gibt. DOUBLE (16 Stellen) ist die nächstbeste Wahl.
Ergebnistyp binärer Operatoren (l op r; T = promoteter Typ):
| Operator | Ergebnistyp | Besonderheiten |
|---|---|---|
+ - * |
T; gleiche Typen bleiben erhalten | Ganzzahl-/CURRENCY-Überlauf → Fehler 6 (auch INTEGER+INTEGER promotet nicht) |
/ |
DOUBLE, wenn ein Operand DOUBLE oder CURRENCY, sonst SINGLE | Division durch 0 → Fehler 11 |
\ MOD |
INTEGER, wenn beide Operanden INTEGER, sonst LONG | Operanden werden vorher kaufmännisch (banker's) auf Ganzzahl gerundet; außerhalb LONG → Fehler 6; Divisor 0 → Fehler 11; MOD-Vorzeichen wie Dividend |
^ |
DOUBLE, wenn ein Operand DOUBLE oder CURRENCY, sonst SINGLE (Projektentscheidung 2026-09-04) | Rechnung intern in DOUBLE; 0 ^ negativ → Fehler 11; negative Basis mit nicht-ganzem Exponent → Fehler 5 |
= <> < <= > >= |
INTEGER (−1/0) | Vergleich im promoteten Typ; Strings codepoint-weise |
NOT AND OR XOR EQV IMP |
INTEGER, wenn alle Operanden INTEGER, sonst LONG | bitweise; Operanden vorher banker's-gerundet auf Ganzzahl, außerhalb LONG → Fehler 6 |
unäres - |
Typ des Operanden | −(−32768) INTEGER → Fehler 6 |
Konvertierung Quelle → Ziel (implizit bei Zuweisung/Argument, explizit
via CINT/CLNG/CSNG/CDBL/CCUR — identische Semantik):
| von \ nach | INTEGER | LONG | SINGLE | DOUBLE | CURRENCY |
|---|---|---|---|---|---|
| INTEGER | — | exakt | exakt | exakt | ×10 000 |
| LONG | Bereich prüfen → 6 | — | nächstgelegener f32 | exakt | ×10 000 |
| SINGLE | banker's + Bereich → 6 | banker's + Bereich → 6 | — | exakt (Widening) | banker's auf 4 Nachkommastellen + Bereich → 6 |
| DOUBLE | banker's + Bereich → 6 | banker's + Bereich → 6 | Bereich prüfen → 6, sonst nächstgelegener f32 | — | banker's auf 4 Nachkommastellen + Bereich → 6 |
| CURRENCY | ÷10 000, banker's + Bereich → 6 | ÷10 000, banker's + Bereich → 6 | ÷10 000.0 | ÷10 000.0 | — |
- Banker's Rounding: zur nächsten Ganzzahl, bei .5 zur geraden
(Original-Hilfe: CINT). Gilt für alle Gleitkomma→Ganzzahl-Übergänge
inklusive
\/MOD/Logik-Operanden und CURRENCY-Skalierung. - Zahl ↔ String nie implizit (Compile-Zeit „Type mismatch"); explizit nur
über
STR$/VAL.
Textdarstellung (PRINT und STR$):
- INTEGER/LONG: dezimal ohne Dezimalpunkt.
- SINGLE: bis 7 signifikante Stellen, kürzeste Darstellung, keine
führende Null vor dem Dezimalpunkt (
.5), keine nachgestellten Nullen; außerhalb des Festformat-Bereichs ExponentialformmE±xx. Projektentscheidung 2026-09-04: Die Original-Hilfe nennt keine Schwelle. Gewählt ist der Dezimalexponent < −7 oder ≥ 7 — damit bleibt jeder Wert im Festformat, der sich mit den 7 signifikanten Stellen des Typs verlustfrei schreiben lässt (9999999fest,1E+07exponentiell;.0000001fest,1E-08exponentiell). - DOUBLE: wie SINGLE mit bis 16 signifikanten Stellen und
D±xxals Exponentmarke. - CURRENCY: Festformat mit bis zu 4 Nachkommastellen, nachgestellte
Nullen entfallen (
2.5000@→2.5,1.10@→1.1). Projektentscheidung 2026-09-04: Die Original-Hilfe nennt kein Ausgabeformat. Gewählt ist dieselbe Regel wie bei den übrigen Zahlentypen — nachgestellte Nullen entfallen —, damitPRINTüber alle Typen einheitlich wirkt. Wer feste Nachkommastellen braucht, nutztPRINT USING. PRINTstellt nicht-negativen Zahlen ein Leerzeichen, negativen ein-voran und hängt stets ein Leerzeichen an;STR$nur das führende Leerzeichen/-, kein nachgestelltes.
Opcode-Satz (Feindesign, 2026-09-02)
In-Memory führt die VM dekodierte Instruktionen (Vec<Instr>, ein Rust-
Enum mit eingebetteten Operanden — Wort-Dispatch, keine Byte-Dekodierung
im heißen Pfad); die .tbc-Serialisierung bildet jede Instruktion auf
1 Opcode-Byte + Operanden (little-endian) ab. Typkürzel: I2=INTEGER,
I4=LONG, R4=SINGLE, R8=DOUBLE, CY=CURRENCY, STR=STRING.
| Gruppe | Instruktionen | Bemerkung |
|---|---|---|
| Anweisungsgrenze | Stmt(line:u32) · SetErl(n:u32) |
Stmt prüft das Tick-Flag-Wort (Breakpoint/Einzelschritt/Abbruch), aktualisiert Zeile und Resume-Punkt; SetErl bei numerischen Zeilennummern |
| Konstanten/Stack | PushInt(i16) PushLng(i32) PushSng(f32) PushDbl(f64) PushCur(i64) PushStr(pool:u16) · Dup Pop |
Stringpool dedupliziert |
| Variablen | LoadGlobal/StoreGlobal(u16) · LoadLocal/StoreLocal(u16) · MakeRefGlobal/MakeRefLocal(u16) · LoadRef/StoreRef(u16) |
Slots statisch aufgelöst; *Ref bedienen BYREF-Parameter (Referenz-Werte) |
| Arrays | DimGlobal/DimLocal{slot,dims,elem} RedimGlobal/RedimLocal{…} EraseGlobal/EraseLocal(u16) · LoadElem/StoreElem{dims:u8} · MakeRefElem{dims:u8} |
Grenzen auf dem Stack (lo/hi je Dimension als LONG); Indexprüfung → Fehler 9 |
| UDT | LoadField/StoreField(u16) · MakeRefField(u16) |
Feldindex aus Typtabelle; verschachtelt durch Verkettung |
| Arithmetik | Add/Sub/Mul{I2,I4,R4,R8,CY} · Neg{…} · Div{R4,R8} · IDiv/Mod{I2,I4} · PowR8 (^ rechnet in DOUBLE, SINGLE-Ergebnis per Conv) |
monomorph; Ganzzahl-/CY-Überlauf → Fehler 6, Division durch 0 → Fehler 11 |
| Konvertierung | Conv_<src>_<dst> für alle 20 geordneten Paare aus {I2,I4,R4,R8,CY} |
Semantik exakt nach Matrix (Rundung/Überlauf) |
| Logik | Not/And/Or/Xor/Eqv/Imp{I2,I4} |
bitweise |
| Vergleich | Cmp{Eq,Ne,Lt,Le,Gt,Ge}{I2,I4,R4,R8,CY,STR} |
Ergebnis INTEGER −1/0 |
| Strings | Concat |
Rc<str>, Kopien sind Pointer-Kopien |
| Kontrollfluss | Jump(u32) JumpIfFalse(u32) JumpIfTrue(u32) |
Ziele absolut (Instruktionsindex) innerhalb der Code-Einheit; Fixups beim Emit |
| GOSUB | Gosub(u32) RetGosub RetGosubTo(u32) |
GOSUB-Stack pro Frame; leer → Fehler 3 |
| Berechnete Sprünge | OnJump{table:u16,gosub:bool} |
Sprungtabellen im Modul; 0/zu groß: kein Sprung; negativ/>255 → Fehler 5 |
| Prozeduren | Call(proc:u16) RetProc RetFn CallBuiltin{id:u16,argc:u8} |
Argumente links→rechts auf dem Stack (Werte oder Referenzen); RetFn transportiert den Funktionswert über den Frame-Abbau |
| Fehler | OnErrorGoto(u32) OnErrorLocal(u32) OnErrorDisable OnErrorLocalDisable · Resume0 ResumeNext ResumeLabel(u32) · RaiseError |
Scoping siehe unten |
| DATA | ReadData(art) Restore(u32) |
art 0 = String, 1 = Zahl (DOUBLE, dann Conv nach Matrix); Ende → Fehler 4, unkonvertierbar → Fehler 13 |
| E/A | Input{…} sowie Builtins (PRINT-Familie über CallBuiltin) |
Konsolenwirkung ausschließlich über das Host-Trait |
| Ende | End StopInstr SystemInstr |
Verhalten siehe Runner |
FOR/NEXT wird ohne Spezial-Opcodes kompiliert: Grenz-/Schrittwert einmal
in versteckte Slots ausgewertet; bei konstantem STEP wählt der Codegen
die Vergleichsrichtung zur Compilezeit, sonst verzweigt ein einmalig
berechnetes Vorzeichen-Flag auf zwei Vergleichssequenzen. Inkrement mit
regulärer typisierter Addition (Überlauf → Fehler 6, wie Vorbild).
SELECT CASE wertet den Selektor in einen versteckten Slot aus und wird
als Vergleichs-/Sprungkette abgesenkt.
Fehlerbehandlung: Scoping (Feindesign, 2026-09-02)
ON ERROR GOTO xsetzt den modulweiten Handler — auch aus einer Prozedur heraus.ON LOCAL ERROR GOTO xsetzt einen Frame-lokalen Handler, der den modulweiten für die Dauer des Prozedurlaufs verdeckt.… GOTO 0deaktiviert den jeweiligen Handler.- Fehlerfall: erst die Frame-Kette von innen nach außen nach
LOCAL-Handlern absuchen, sonst modulweiter Handler; Stack wird bis zum
Handler-Frame abgewickelt, Anweisungs-Offset und Frame für
RESUMEgemerkt,ERR/ERLgesetzt. Ohne Handler: Abbruch mit Meldung und Quellzeile. - Fehler während aktiver Behandlung (zwischen Handler-Eintritt und
RESUME): sofortiger Abbruch, keine Kaskade (Vorbild). ERLliefert die zuletzt durchlaufene numerische Zeilennummer (Labels zählen nicht; ohne numerische Zeilen: 0).
Runner-Verhalten STOP/CONT (Entscheidung 2026-09-02)
END,SYSTEMund das Erreichen des Programmendes beenden den Prozess mit Exit-Code 0.STOPaußerhalb der IDE terminiert mit der MeldungSTOP in line n(bzw. Modul/Zeile) und Exit-Code ≠ 0. Offene Dateien werden wie beiENDgeschlossen.CONTist ein Direktmodus-Konzept der IDE (Phase 5): dort suspendiertSTOPdie VM (step()-Architektur),CONTsetzt fort. Im Kompilat existiert keinCONT.
Offene Punkte
Keine — die Punkte aus Phase 0 (Opcode-Satz, Konvertierungsmatrix,
STOP/CONT im Runner) sind oben ausgearbeitet. Die vier Stellen, zu
denen die Original-Hilfe schweigt, sind am 2026-09-04 als
Projektentscheidung festgelegt, an Ort und Stelle begründet und über
tests/compat/konvertierung.bas ausführbar verankert. Sollte je eine
belastbare Fundstelle auftauchen, die ihnen widerspricht, gilt sie —
die Entscheidungen sind Lückenfüller, keine Setzungen gegen das Vorbild.