OpenSpec: phase-2-bytecode-vm archiviert, Delta-Specs in Hauptspecs gesynct
- Neue Hauptspecs: bytecode-kompilat, vm-ausfuehrung, vm-fehlerbehandlung, konsolen-basisbibliothek - Erweitert: sprach-frontend (Typisiertes HIR als Sema-Ausgabe), kompat-testkorpus (Laufzeitvergleich, Phase-2-Korpusabdeckung) - Change nach openspec/changes/archive/2026-09-02-phase-2-bytecode-vm verschoben; openspec validate --all: 9/9 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f7e57b0bd8
commit
a6f005d023
16 files changed
+364
No files matched your search
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,65 @@
|
||||
# bytecode-kompilat Specification
|
||||
|
||||
## Purpose
|
||||
Das Bytecode-Kompilat ist das serialisierbare Ergebnis der Übersetzung:
|
||||
Der Codegenerator senkt das typisierte HIR in einen monomorphen
|
||||
Opcode-Satz ab, der `.tbc`-Container hält es als stabiles, dokumentiertes
|
||||
Format, und das Instant-Compile-Budget sichert den schnellen
|
||||
Edit-Run-Zyklus.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Monomorpher Opcode-Satz
|
||||
Der Codegenerator SHALL jedes HIR-Konstrukt in typisierte, monomorphe
|
||||
Opcodes übersetzen: Arithmetik, Vergleiche und Konvertierungen tragen den
|
||||
Operandentyp im Opcode (kein Tag-Dispatch über Werte zur Laufzeit);
|
||||
implizite Konvertierungen erscheinen als explizite Konvertierungs-Opcodes
|
||||
an den vom HIR bestimmten Stellen. Der Opcode-Satz SHALL in
|
||||
docs/tbvm-design.md vollständig dokumentiert sein.
|
||||
|
||||
#### Scenario: Gemischter Ausdruck wird monomorph
|
||||
- **WHEN** `d# = i% + 1.5#` übersetzt wird (INTEGER-Variable, DOUBLE-Ziel)
|
||||
- **THEN** enthält der Bytecode einen Konvertierungs-Opcode INTEGER→DOUBLE und eine DOUBLE-Addition, keinen generischen Additions-Opcode
|
||||
|
||||
#### Scenario: Namen sind zur Laufzeit aufgelöst
|
||||
- **WHEN** eine Variable oder Prozedur im Bytecode referenziert wird
|
||||
- **THEN** geschieht das über Slot- bzw. Tabellenindizes, nicht über Namens-Lookups
|
||||
|
||||
### Requirement: `.tbc`-Containerformat
|
||||
Das Kompilat SHALL als `.tbc`-Datei serialisierbar und wieder ladbar sein:
|
||||
Magic `TBC\0`, Formatversion, Abschnittstabelle mit den Abschnitten
|
||||
CONSTS (deduplizierter Konstantenpool), TYPES (TYPE-Layouts), PROCS
|
||||
(modul-qualifizierte Prozedurtabelle mit Signatur, Locals-Anzahl,
|
||||
Code-Offset), CODE, DATA (`READ`/`RESTORE`-Segment) und LINES
|
||||
(Zeilentabelle). Laden und erneutes Serialisieren MUST verlustfrei sein;
|
||||
eine unbekannte Formatversion MUST mit einer klaren Fehlermeldung
|
||||
abgewiesen werden.
|
||||
|
||||
#### Scenario: Roundtrip
|
||||
- **WHEN** ein kompiliertes Modul als `.tbc` geschrieben und wieder geladen wird
|
||||
- **THEN** ist das geladene Kompilat funktional identisch (gleiche Ausführung, gleiche Zeilenzuordnung)
|
||||
|
||||
#### Scenario: Unbekannte Version
|
||||
- **WHEN** eine `.tbc`-Datei mit höherer Formatversion geladen wird
|
||||
- **THEN** wird das Laden mit einer Meldung abgelehnt, die die Version nennt
|
||||
|
||||
### Requirement: Zeilentabelle für Fehlerortung
|
||||
Der Bytecode SHALL jede Anweisung ihrem Ursprung (Moduldatei, Zeile)
|
||||
zuordnen, sodass Laufzeitfehlermeldungen, `ERL`, Breakpoints und
|
||||
Einzelschritt die Quellzeile exakt benennen können.
|
||||
|
||||
#### Scenario: Fehler nennt Zeile
|
||||
- **WHEN** in Zeile 42 eines Programms ein Laufzeitfehler ohne Handler auftritt
|
||||
- **THEN** nennt die Fehlermeldung Zeile 42
|
||||
|
||||
### Requirement: Instant-Compile-Budget
|
||||
Die Übersetzung (Lexen bis Bytecode) SHALL ohne globale Analysepasses
|
||||
auskommen; Vorwärtsreferenzen werden über Fixups aufgelöst. Ein
|
||||
Benchmark MUST das Budget nachweisbar machen: ein Projekt von ~50.000
|
||||
Zeilen kompiliert in unter 1 s, ein einzelnes Modul in unter 50 ms
|
||||
(Release-Build, Referenzrechner); die Messwerte werden in
|
||||
docs/tbvm-design.md festgehalten.
|
||||
|
||||
#### Scenario: Budget wird gemessen
|
||||
- **WHEN** die Benchmarks in `benches/` laufen
|
||||
- **THEN** wird die Kompilierzeit für das ~50k-Zeilen-Projekt und für ein Einzelmodul ausgewiesen und gegen das Budget verglichen
|
||||
@@ -29,3 +29,29 @@ hinzu.)
|
||||
#### Scenario: Korpus bleibt kompilierbar
|
||||
- **WHEN** die Frontend-Testsuite läuft
|
||||
- **THEN** parsen alle Korpusdateien diagnose-frei und der Test nennt andernfalls Datei und Diagnose
|
||||
|
||||
### Requirement: Laufzeitvergleich über den Korpus
|
||||
Ein automatischer Test SHALL jede Korpusdatei `tests/compat/*.bas`
|
||||
kompilieren, über die VM mit Capture-Host ausführen und die Ausgabe
|
||||
byte-genau (inklusive nachgestellter Leerzeichen und LF-Zeilenenden)
|
||||
gegen die zugehörige `.out`-Datei vergleichen. Bei Abweichung MUST der
|
||||
Test Datei, erste abweichende Zeile sowie Soll und Ist nennen.
|
||||
|
||||
#### Scenario: Korpus läuft mit korrekter Ausgabe
|
||||
- **WHEN** die Laufzeit-Testsuite läuft
|
||||
- **THEN** stimmt die Ausgabe jeder Korpusdatei byte-genau mit ihrer `.out` überein
|
||||
|
||||
#### Scenario: Abweichung wird benannt
|
||||
- **WHEN** ein Korpusprogramm eine abweichende Ausgabe erzeugt
|
||||
- **THEN** schlägt der Test fehl und nennt Datei, Zeilennummer, Soll- und Ist-Zeile
|
||||
|
||||
### Requirement: Korpusabdeckung der Phase-2-Semantik
|
||||
Der Korpus SHALL um Referenzprogramme mit dokumentierter Sollausgabe für
|
||||
die Zahlenkonvertierungs-Matrix (Rundung, Ganzzahldivision, logische
|
||||
Operatoren, Überlauf-Randfälle über Fehlerbehandlung), die
|
||||
Fehlerbehandlung (`ON ERROR`, `RESUME`-Varianten, `ERR`/`ERL`) sowie
|
||||
Prozeduraufrufe mit BYREF-/BYVAL-Wirkung erweitert werden.
|
||||
|
||||
#### Scenario: Konvertierungsmatrix als Korpustest
|
||||
- **WHEN** die Laufzeit-Testsuite läuft
|
||||
- **THEN** existiert ein Korpusprogramm, das die Matrix-Randfälle ausgibt, und seine Ausgabe entspricht der dokumentierten Sollausgabe
|
||||
@@ -0,0 +1,67 @@
|
||||
# konsolen-basisbibliothek Specification
|
||||
|
||||
## Purpose
|
||||
Die Konsolen-Basisbibliothek ist die in Phase 2 vorgezogene Scheibe der
|
||||
Laufzeitbibliothek: die Builtin-Aufrufschnittstelle der VM, ein
|
||||
`Host`-Abstraktion für Konsolen-E/A sowie PRINT-Formatierung und die vom
|
||||
Testkorpus benötigten Stringfunktionen.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Builtin-Aufrufschnittstelle
|
||||
Die VM SHALL Bibliotheksfunktionen und -anweisungen über eine indizierte
|
||||
Dispatch-Tabelle aufrufen (Argumente auf dem Operandenstack, Index im
|
||||
Opcode); die Tabelle lebt in der Laufzeitbibliothek und ist ohne
|
||||
Änderung am Opcode-Satz erweiterbar (Phase 3 füllt sie auf).
|
||||
|
||||
#### Scenario: Builtin über Tabelle
|
||||
- **WHEN** `PRINT LEN("abc")` ausgeführt wird
|
||||
- **THEN** wird `LEN` über seinen Tabellenindex aufgerufen und liefert 3
|
||||
|
||||
### Requirement: Host-Abstraktion für Konsolen-E/A
|
||||
Alle Konsolenwirkungen der VM SHALL über eine austauschbare
|
||||
Host-Schnittstelle laufen (Textausgabe, zeilenweises Lesen für `INPUT`,
|
||||
Abbruchprüfung). Host-Aufrufe dürfen blockieren; die Abbruchprüfung
|
||||
(Strg+Untbr) obliegt dem Host. `tbc run` verwendet einen Konsolen-Host
|
||||
(stdout/stdin); Tests MUST einen Capture-Host verwenden können, der die
|
||||
Ausgabe byte-genau aufzeichnet.
|
||||
|
||||
#### Scenario: Capture-Host im Test
|
||||
- **WHEN** ein Korpusprogramm im Test-Harness läuft
|
||||
- **THEN** entsteht die komplette Ausgabe im Capture-Host und ist byte-genau vergleichbar
|
||||
|
||||
### Requirement: PRINT-Formatierung
|
||||
`PRINT` SHALL Zahlen im Format des Vorbilds ausgeben: führendes
|
||||
Leerzeichen für nicht-negative bzw. `-` für negative Werte,
|
||||
nachgestelltes Leerzeichen (auch am Zeilenende); Zahlendarstellung je
|
||||
Typ wie beim Vorbild (u. a. kein Dezimalpunkt bei ganzzahligen Werten,
|
||||
signifikante Stellen je nach SINGLE/DOUBLE). `;` schließt direkt an,
|
||||
`,` springt zur nächsten 14-Zeichen-Druckzone (belegt ein Element die
|
||||
Zone ganz, zur übernächsten); ohne abschließendes `;`/`,` folgt ein
|
||||
Zeilenumbruch.
|
||||
|
||||
#### Scenario: Zahlen mit Vorzeichenspalte
|
||||
- **WHEN** `PRINT 1; -2; 3.5` ausgeführt wird
|
||||
- **THEN** lautet die Ausgabe ` 1 -2 3.5 ` mit Zeilenumbruch
|
||||
|
||||
#### Scenario: Druckzonen
|
||||
- **WHEN** `PRINT "12345678901234", "x"` ausgeführt wird
|
||||
- **THEN** beginnt `x` in Spalte 29 (Zone nach der belegten übersprungen)
|
||||
|
||||
### Requirement: Korpus-Stringfunktionen
|
||||
Die Bibliothek SHALL mindestens folgende Funktionen mit der Semantik des
|
||||
Vorbilds bereitstellen (Zeichen = Unicode-Codepoints, dokumentierte
|
||||
UTF-8-Abweichung): `LEN`, `LEFT$`, `RIGHT$`, `MID$` (Funktion),
|
||||
`INSTR`, `UCASE$`, `LCASE$`, `STRING$`, `SPACE$`, `CHR$`, `ASC`,
|
||||
`STR$`, `VAL`. Randfälle folgen dem Vorbild, u. a.: `VAL` liest das
|
||||
führende Zahlenpräfix und ignoriert Leerraum; `STR$` stellt
|
||||
nicht-negativen Zahlen ein Leerzeichen voran; `ASC("")` löst Fehler 5
|
||||
„Illegal function call" aus.
|
||||
|
||||
#### Scenario: Korpusdatei strings.bas
|
||||
- **WHEN** `tests/compat/strings.bas` ausgeführt wird
|
||||
- **THEN** entspricht die Ausgabe byte-genau `strings.out`
|
||||
|
||||
#### Scenario: VAL mit Restzeichen
|
||||
- **WHEN** `VAL(" 12.5abc")` ausgewertet wird
|
||||
- **THEN** ist das Ergebnis 12.5
|
||||
@@ -102,3 +102,21 @@ Entsprechung existiert (z. B. „Type mismatch", „Duplicate definition",
|
||||
#### Scenario: Position in der Diagnose
|
||||
- **WHEN** in Zeile 3 ein Typkonflikt auftritt
|
||||
- **THEN** nennt die Diagnose Zeile 3 und die Spalte des Ausdrucks
|
||||
|
||||
### Requirement: Typisiertes HIR als Sema-Ausgabe
|
||||
Die semantische Analyse SHALL neben den Diagnosen einen typisierten,
|
||||
abgesenkten Zwischenbaum (HIR) liefern, der die Codegen-Eingabe bildet:
|
||||
Namen sind zu Slot-/Tabellenindizes aufgelöst, jeder Ausdrucksknoten
|
||||
trägt seinen Ergebnistyp, `CONST`-Werte sind gefaltet, `DEFtype`-Regeln
|
||||
angewandt und implizite Konvertierungen als explizite
|
||||
Konvertierungsknoten materialisiert. Bei Diagnosen mit Fehlercharakter
|
||||
darf kein HIR für das betroffene Konstrukt garantiert werden; ein
|
||||
diagnose-freies Modul MUST ein vollständiges HIR ergeben.
|
||||
|
||||
#### Scenario: Konvertierung wird materialisiert
|
||||
- **WHEN** `d# = i% + 1.5#` semantisch analysiert wird
|
||||
- **THEN** enthält das HIR einen expliziten Konvertierungsknoten INTEGER→DOUBLE unter dem Additionsknoten und die Zuweisung trägt den Zieltyp DOUBLE
|
||||
|
||||
#### Scenario: Diagnose-freies Modul liefert HIR
|
||||
- **WHEN** ein Korpusmodul ohne Diagnosen analysiert wird
|
||||
- **THEN** liefert das Frontend ein HIR, aus dem der Codegen ohne erneute Namens- oder Typauflösung Bytecode erzeugen kann
|
||||
@@ -0,0 +1,116 @@
|
||||
# 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
|
||||
@@ -0,0 +1,72 @@
|
||||
# vm-fehlerbehandlung Specification
|
||||
|
||||
## Purpose
|
||||
Die BASIC-Fehlersemantik (`ON ERROR GOTO`, `ON LOCAL ERROR`, `RESUME`,
|
||||
`ERR`/`ERL`) ist Teil des Kompatibilitätsvertrags: Programme des Vorbilds
|
||||
verlassen sich auf Handler-Scoping, Propagation und Wiederaufnahme exakt
|
||||
wie dokumentiert.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Handler-Scoping nach Vorbild
|
||||
`ON ERROR GOTO label` SHALL einen modulweiten Handler aktivieren (auch
|
||||
wenn die Anweisung in einer Prozedur steht); `ON LOCAL ERROR GOTO label`
|
||||
SHALL einen prozedurlokalen Handler aktivieren, der den modulweiten für
|
||||
die Dauer des Prozedurlaufs verdeckt. `ON [LOCAL] ERROR GOTO 0`
|
||||
deaktiviert den jeweiligen Handler. Tritt ein Fehler in einer Prozedur
|
||||
ohne zuständigen Handler auf, SHALL er die Aufrufkette hochpropagieren,
|
||||
bis ein aktiver Handler gefunden ist; ohne Handler bricht das Programm
|
||||
mit der Fehlermeldung und der Quellzeile ab.
|
||||
|
||||
#### Scenario: Modulweiter Handler fängt Prozedurfehler
|
||||
- **WHEN** das Hauptprogramm `ON ERROR GOTO Fehler` gesetzt hat und eine gerufene SUB Fehler 6 auslöst
|
||||
- **THEN** springt die Ausführung in den Handler `Fehler` und `ERR` ist 6
|
||||
|
||||
#### Scenario: Lokaler Handler verdeckt modulweiten
|
||||
- **WHEN** eine Prozedur `ON LOCAL ERROR GOTO L` gesetzt hat und in ihr ein Fehler auftritt
|
||||
- **THEN** behandelt `L` den Fehler, nicht der modulweite Handler
|
||||
|
||||
#### Scenario: Ohne Handler bricht das Programm ab
|
||||
- **WHEN** Fehler 9 ohne aktiven Handler auftritt
|
||||
- **THEN** endet das Programm mit der Meldung „Subscript out of range" und der Quellzeile
|
||||
|
||||
### Requirement: ERR und ERL
|
||||
Beim Eintritt in einen Handler SHALL `ERR` den Fehlercode liefern und
|
||||
`ERL` die zuletzt vor dem Fehler ausgeführte **numerische** Zeilennummer
|
||||
(0, wenn keine numerischen Zeilennummern durchlaufen wurden —
|
||||
alphanumerische Labels zählen nicht). `ERROR n` SHALL Fehler `n`
|
||||
künstlich auslösen und dieselbe Maschinerie durchlaufen.
|
||||
|
||||
#### Scenario: ERL bei Label-Programm
|
||||
- **WHEN** ein Programm ohne numerische Zeilennummern einen Fehler behandelt
|
||||
- **THEN** liefert `ERL` 0
|
||||
|
||||
#### Scenario: ERROR-Anweisung
|
||||
- **WHEN** `ERROR 53` bei aktivem Handler ausgeführt wird
|
||||
- **THEN** wird der Handler mit `ERR` = 53 betreten
|
||||
|
||||
### Requirement: RESUME-Semantik
|
||||
Im Handler SHALL `RESUME` (bzw. `RESUME 0`) die fehlerauslösende
|
||||
Anweisung wiederholen, `RESUME NEXT` mit der Anweisung danach
|
||||
fortfahren und `RESUME label` an das Ziel springen. `RESUME` außerhalb
|
||||
einer aktiven Fehlerbehandlung MUST Fehler 20 „RESUME without error"
|
||||
auslösen. Nach `RESUME` gilt die Fehlerbehandlung als abgeschlossen
|
||||
(`ERR` wird zurückgesetzt).
|
||||
|
||||
#### Scenario: RESUME NEXT
|
||||
- **WHEN** ein Handler nach Fehler 11 (`Division by zero`) `RESUME NEXT` ausführt
|
||||
- **THEN** wird die auf die Division folgende Anweisung ausgeführt
|
||||
|
||||
#### Scenario: RESUME ohne Fehler
|
||||
- **WHEN** `RESUME` außerhalb eines Handlers ausgeführt wird
|
||||
- **THEN** tritt Laufzeitfehler 20 auf
|
||||
|
||||
### Requirement: Fehler im Handler ist fatal
|
||||
Tritt ein Fehler auf, während die Fehlerbehandlung aktiv ist (zwischen
|
||||
Handler-Eintritt und `RESUME`), SHALL das Programm ohne erneute
|
||||
Handler-Suche mit der Fehlermeldung abbrechen (keine Fehlerkaskaden,
|
||||
Verhalten des Vorbilds).
|
||||
|
||||
#### Scenario: Kein Kaskadieren
|
||||
- **WHEN** im aktiven Handler selbst Fehler 6 auftritt
|
||||
- **THEN** bricht das Programm mit „Overflow" ab, auch wenn ein Handler registriert ist
|
||||
Reference in new issue
Block a user