Files
TerminalBasic/openspec/specs/vm-ausfuehrung/spec.md

7.9 KiB
Raw Blame History

vm-ausfuehrung Specification

Purpose

Die TBVM führt das Bytecode-Kompilat mit der exakten Semantik des Dialekts aus: Ausdrücke mit der Zahlenkonvertierungs-Matrix des Vorbilds, Kontrollfluss, Prozeduraufrufe mit BYREF, GOSUB, unterbrechbare step()-Ausführung als Grundlage für Debugger und Ereignisschleife.

Requirements

Requirement: Zahlenkonvertierungs-Matrix

Die VM SHALL implizite und explizite Zahlenkonvertierungen nach der in docs/tbvm-design.md dokumentierten Matrix ausführen, insbesondere: Gleitkomma→Ganzzahl rundet kaufmännisch zur nächsten geraden Zahl (Banker's Rounding); Bereichsüberschreitung löst Fehler 6 „Overflow" aus; / liefert stets Gleitkomma, \ und MOD konvertieren ihre Operanden vorab zu Ganzzahlen; logische Operatoren (AND, OR, XOR, EQV, IMP) arbeiten bitweise auf zu Ganzzahlen konvertierten Operanden; CURRENCY rechnet als Festkomma ×10 000. Die Matrix SHALL durch ein Korpusprogramm mit dokumentierter Sollausgabe abgedeckt sein.

Scenario: Banker's Rounding

  • WHEN PRINT CINT(0.5); CINT(1.5); CINT(2.5) ausgeführt wird
  • THEN lautet die Ausgabe 0 2 2

Scenario: Überlauf bei Konvertierung

  • WHEN einer INTEGER-Variablen der Wert 40000 zugewiesen wird
  • THEN tritt Laufzeitfehler 6 „Overflow" auf

Scenario: Ganzzahldivision rundet Operanden vor

  • WHEN PRINT 7.5 \ 2 ausgeführt wird
  • THEN wird 7.5 zuerst zu 8 gerundet und die Ausgabe ist 4

Requirement: Kontrollfluss

Die VM SHALL IF/ELSEIF/ELSE, SELECT CASE (Werte, Bereiche, IS-Vergleiche, CASE ELSE), FOR/NEXT (inkl. STEP, null Durchläufen bei unpassender Grenze), DO/LOOP (alle vier Bedingungsformen), WHILE/WEND, GOTO, ON expr GOTO/GOSUB und EXIT FOR/DO mit der Semantik des Vorbilds ausführen.

Scenario: FOR ohne Durchlauf

  • WHEN FOR i% = 3 TO 1: PRINT i%: NEXT ausgeführt wird
  • THEN wird der Schleifenkörper nicht betreten

Scenario: Korpus Kontrollfluss

  • WHEN tests/compat/kontrollfluss.bas ausgeführt wird
  • THEN entspricht die Ausgabe byte-genau kontrollfluss.out

Requirement: GOSUB/RETURN neben Prozeduraufrufen

GOSUB SHALL die Rücksprungadresse auf einem GOSUB-Stack im aktuellen Frame ablegen (kein eigener Frame); RETURN kehrt dorthin zurück, RETURN label an das benannte Ziel. Ein RETURN ohne anhängigen GOSUB MUST Fehler 3 „RETURN without GOSUB" auslösen.

Scenario: RETURN ohne GOSUB

  • WHEN ein Programm RETURN ohne vorangehendes GOSUB ausführt
  • THEN tritt Laufzeitfehler 3 auf

Requirement: Prozeduraufrufe mit BYREF-Semantik

SUB-/FUNCTION-Aufrufe SHALL eigene Frames mit Locals-Slots verwenden. Variablen, Arrayelemente und UDT-Felder werden BYREF übergeben (Änderungen im Rumpf wirken auf das Argument zurück); ein geklammertes Argument oder ein Ausdruck wird als temporärer Wert übergeben (BYVAL- Wirkung). STATIC-Prozeduren behalten ihre Locals zwischen Aufrufen; rekursive Aufrufe nicht-statischer Prozeduren erhalten frische Locals. DEF FN-Funktionen werten im Modulkontext aus (Zugriff auf Modulvariablen), ihre Parameter wirken lokal.

Scenario: BYREF wirkt zurück

  • WHEN SUB Inc(x%) : x% = x% + 1 : END SUB mit Inc n% aufgerufen wird
  • THEN ist n% danach um 1 erhöht

Scenario: Klammern erzwingen Wertübergabe

  • WHEN dieselbe SUB mit Inc (n%) aufgerufen wird
  • THEN bleibt n% unverändert

Requirement: DATA/READ/RESTORE

READ SHALL die DATA-Konstanten des Moduls in Deklarationsreihenfolge konsumieren und in den Zieltyp konvertieren; RESTORE [label] setzt den Lesezeiger auf den Anfang bzw. auf die erste DATA-Anweisung ab dem Label. Lesen hinter dem letzten Element MUST Fehler 4 „Out of DATA" auslösen; eine nicht konvertierbare Konstante MUST Fehler 13 „Type mismatch" auslösen.

Scenario: Out of DATA

  • WHEN ein Programm mehr Werte liest als DATA bereitstellt
  • THEN tritt Laufzeitfehler 4 auf

Requirement: Unterbrechbare step()-Ausführung

Die VM SHALL als zustandsbehaftete, vom Einbetter getriebene Struktur ausführbar sein: An Anweisungsgrenzen prüft sie ein Flag-Wort und kann anhalten (Breakpoint auf (Modul, Zeile), Einzelschritt, Abbruchwunsch). Im angehaltenen Zustand MUST der Einbetter Variableninhalte (Skalare, Arrayelemente, UDT-Felder) inspizieren und die Ausführung fortsetzen können. Die Tick-Prüfung erfolgt nur an Anweisungsgrenzen, nicht pro Opcode.

Scenario: Breakpoint hält an

  • WHEN ein Breakpoint auf Zeile 10 gesetzt ist und die Ausführung Zeile 10 erreicht
  • THEN hält die VM vor der Anweisung an und meldet Modul und Zeile

Scenario: Inspektion im Halt

  • WHEN die VM an einem Breakpoint steht
  • THEN liefert die Inspektions-API den aktuellen Wert einer benannten Variablen

Requirement: Programmende im Runner

Außerhalb der IDE SHALL END (und das Erreichen des Programmendes) den Prozess mit Exit-Code 0 beenden; STOP SHALL mit der Meldung STOP in line n (bzw. Modul/Zeile) und einem Exit-Code ungleich 0 terminieren (Projektentscheidung 2026-09-02). SYSTEM verhält sich wie END. CONT existiert nur als IDE-Konzept (Phase 5) und ist kein Programmbestandteil.

Scenario: STOP im Runner

  • WHEN ein per tbc run gestartetes Programm STOP in Zeile 7 ausführt
  • THEN endet der Prozess mit Exit-Code ungleich 0 und die Meldung nennt Zeile 7

Requirement: Ereigniszustellung an Anweisungsgrenzen

Die VM SHALL an Anweisungsgrenzen prüfen, ob ein Ereignis zuzustellen ist, und in diesem Fall das GOSUB-Ziel des zugehörigen Traps ausführen. Der unterbrochene Zustand — Aufrufkette, Schleifen, Locals, GOSUB-Stapel und Fehlerzustand — MUST dabei erhalten bleiben; mit RETURN SHALL die Ausführung an der unterbrochenen Stelle fortfahren. Die Prüfung MUST NOT pro Opcode erfolgen; solange kein Trap definiert ist, MUST sie auf einen einzelnen Test hinauslaufen und MUST NOT die Uhr lesen.

Ohne klassische Traps, aktive Forms-Timer oder zeitabhängige Mausauswertung SHALL auch die Forms-Integration keine Hostzeit abfragen.

Scenario: Trap aus einer Prozedur heraus

  • WHEN ein Ereignis zugestellt wird, während eine SUB läuft, und das Trap-Ziel im Modulrumpf liegt
  • THEN läuft der Handler und nach RETURN setzt die SUB an der unterbrochenen Anweisung fort

Scenario: Ohne aktiven Trap wird die Uhr nicht gelesen

  • WHEN ein Programm ohne jede ON …-Trap-Definition ausgeführt wird
  • THEN fragt die Ausführung an keiner Anweisungsgrenze die Zeit ab, und der Durchsatz bleibt im Rahmen der Messgenauigkeit unverändert

Scenario: Einfaches Programm liest keine Ereigniszeit

  • WHEN ein Programm nur Zuweisungen und END ausführt und ein Testhost Zeitabfragen zählt
  • THEN ist der Zähler am Ende 0

Requirement: Jede Schleife trägt eine Anweisungsgrenze im Kreis

Der zurückspringende Zweig jeder Schleife (FOR/NEXT, WHILE/WEND, DO/LOOP in allen Bedingungsformen) MUST über mindestens eine Anweisungsgrenze führen, auch wenn der Schleifenrumpf leer ist. Andernfalls gäbe es in einer Warteschleife keinen Zustellpunkt: kein Ereignis, kein Breakpoint und kein Abbruch würden dort wirken.

Scenario: Leere Warteschleife

  • WHEN FOR i% = 1 TO 10000 unmittelbar von NEXT gefolgt wird
  • THEN führt der Rücksprung über eine Anweisungsgrenze und ein aktiver Zeit-Trap wird darin zugestellt

Scenario: Leere Schleife in jeder Form

  • WHEN eine WHILE/WEND-, DO WHILE/LOOP- oder DO/LOOP UNTIL-Schleife ohne Rumpf übersetzt wird
  • THEN liegt zwischen Rücksprungziel und Rücksprung eine Anweisungsgrenze

Requirement: DOEVENTS gibt die Kontrolle ab

DOEVENTS SHALL anstehende Ereignisse zustellen und danach einen Wert liefern. Solange keine Formulare geladen werden können, SHALL der Wert 0 sein.

Scenario: DOEVENTS in einer Warteschleife

  • WHEN ein Programm in einer Schleife DOEVENTS aufruft und ein Trap fällig wird
  • THEN läuft der Handler innerhalb dieser Schleife