OpenSpec: phase-3-runtime-bildschirm archiviert, Delta-Specs gesynct

Zwei neue Capabilities in den Hauptspecs:
- datei-eio: Dateiverwaltung, drei Zugriffsarten, UTF-32-Festtextfelder,
  Recordkonvertierung, Sperren, Dateisystem-Anweisungen
- sprachinventar: das Vollstaendigkeits-Inventar als pruefbares Artefakt

Fortgeschrieben: textbildschirm (Doppelzellen, Groessenunabhaengigkeit,
Bildschirmanweisungen), konsolen-basisbibliothek (Host-Neuschnitt, volle
String-/Format-/Datums-/Finanzbibliothek), kompat-testkorpus
(Snapshot-Vergleich, Nachweis der Groessenunabhaengigkeit),
sprach-frontend (Signaturpflicht, ON-ERROR-Scoping, DATA-Rohtext).

Bilanz: +32 Anforderungen, 6 geaendert, 1 ersetzt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-04 06:55:02 +02:00
parent 52ccbb5848
commit d0461bea34
17 changed files with 700 additions and 40 deletions

View File

@@ -0,0 +1,175 @@
# datei-eio Specification
## Purpose
Die Datei-E/A stellt die Dateiverwaltung des Dialekts bereit: sequenzieller,
wahlfreier und binärer Zugriff über Dateinummern, Record-Puffer mit
Festtextfeldern, Positions- und Statusfunktionen sowie die
Dateisystem-Anweisungen — plattformübergreifend und mit den
Laufzeitfehlern des Vorbilds.
## Requirements
### Requirement: Dateinummern und Öffnen in drei Zugriffsarten
`OPEN` SHALL in beiden Syntaxen des Vorbilds (Klausel- und Kurzform) die
Zugriffsarten sequenziell (`INPUT`, `OUTPUT`, `APPEND`), wahlfrei
(`RANDOM`) und binär (`BINARY`) unterstützen und die Datei an eine
Dateinummer binden. `FREEFILE` SHALL die kleinste freie Dateinummer
liefern. `CLOSE` ohne Argument SHALL alle offenen Dateien schließen,
`RESET` ebenso. Eine bereits belegte Dateinummer MUST Laufzeitfehler 55
„File already open" auslösen, eine nicht geöffnete Nummer Fehler 52
„Bad file name or number", eine fehlende Datei bei `INPUT` Fehler 53
„File not found".
#### Scenario: Sequenzielles Schreiben und Lesen
- **WHEN** eine Datei mit `OPEN "d.txt" FOR OUTPUT AS #1` beschrieben, geschlossen und mit `FOR INPUT` wieder geöffnet wird
- **THEN** liefert das Lesen genau die geschriebenen Zeilen
#### Scenario: Doppeltes Öffnen derselben Nummer
- **WHEN** `OPEN` eine bereits offene Dateinummer verwendet
- **THEN** tritt Laufzeitfehler 55 auf
#### Scenario: Freie Dateinummer
- **WHEN** `#1` offen ist und `FREEFILE` aufgerufen wird
- **THEN** liefert `FREEFILE` eine Nummer, die noch nicht belegt ist
### Requirement: Sequenzielle Datenübertragung
`PRINT #` SHALL wie `PRINT` formatieren (Druckzonen, Zahlendarstellung mit
Vorzeichenspalte), `WRITE #` SHALL Elemente komma-getrennt mit Strings in
Anführungszeichen schreiben. `INPUT #` SHALL komma-getrennte Felder lesen
und dabei Anführungszeichen auswerten, `LINE INPUT #` die ganze Zeile ohne
Zeilenende. `EOF` SHALL das Erreichen des Dateiendes melden; Lesen über das
Dateiende hinaus MUST Laufzeitfehler 62 „Input past end of file" auslösen.
#### Scenario: WRITE # und INPUT # sind gegenläufig
- **WHEN** `WRITE #1, "a,b", 5` geschrieben und die Zeile mit `INPUT #1, s$, n` gelesen wird
- **THEN** enthält `s$` den Text `a,b` und `n` den Wert 5
#### Scenario: Lesen über das Dateiende
- **WHEN** `INPUT #1, x` nach dem letzten Datensatz ausgeführt wird
- **THEN** tritt Laufzeitfehler 62 auf
### Requirement: Wahlfreier Zugriff mit Record-Puffern
`OPEN … FOR RANDOM … LEN = n` SHALL Datensätze fester Länge bereitstellen.
`GET` und `PUT` SHALL einen Datensatz an einer 1-basierten Recordnummer
lesen bzw. schreiben; ohne Nummer gilt der Satz nach der letzten Operation.
`FIELD` SHALL den Recordpuffer in benannte Festtextfelder aufteilen,
`LSET`/`RSET` SHALL links- bzw. rechtsbündig in ein Feld schreiben und
überlange Werte abschneiden. Alternativ SHALL `GET`/`PUT` mit einer
Variablen eines benutzerdefinierten Typs arbeiten.
#### Scenario: Datensatz schreiben und an gleicher Stelle lesen
- **WHEN** ein Record an Position 3 geschrieben und anschließend von Position 3 gelesen wird
- **THEN** stimmen alle Feldwerte mit den geschriebenen überein
#### Scenario: RSET schneidet ab
- **WHEN** in ein Feld der Länge 5 mit `RSET` der Text `ABCDEFG` geschrieben wird
- **THEN** enthält das Feld genau 5 Zeichen
### Requirement: Record-Konvertierungsfunktionen
Die Bibliothek SHALL die Konvertierungsfunktionen für Recordpuffer
bereitstellen: `MKI$`, `MKL$`, `MKS$`, `MKD$` und `MKC$` wandeln einen
numerischen Wert in seine Byte-Darstellung als String, `CVI`, `CVL`,
`CVS`, `CVD` und `CVC` wandeln zurück. Jedes Paar MUST gegenläufig sein.
Ein Argument, dessen Länge nicht zur Zielbreite passt, MUST
Laufzeitfehler 5 „Illegal function call" auslösen. `MKSMBF$`, `MKDMBF$`,
`CVSMBF` und `CVDMBF` SHALL dieselbe Rolle für das
Microsoft-Binärformat älterer BASIC-Versionen erfüllen; ist dieses
Format ein deklariertes Non-Feature, MUST die Ablehnung namentlich
erfolgen und in der Sprachreferenz unter „Abweichungen" stehen.
#### Scenario: MK und CV sind gegenläufig
- **WHEN** `CVL(MKL$(123456))` ausgewertet wird
- **THEN** ist das Ergebnis 123456
#### Scenario: Falsche Argumentlänge
- **WHEN** `CVI("x")` mit einem ein Zeichen langen String ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: Festtextfelder als UTF-32 mit fester Recordlänge
Feste Strings (`STRING * n`) in Recordpuffern SHALL als UTF-32 gespeichert
werden — 4 Bytes je Zeichen, damit `STRING * n` stets genau `4 * n` Bytes
belegt und die Recordlänge unabhängig vom Zeicheninhalt konstant bleibt.
Die daraus folgende Binär-Inkompatibilität zu Dateien des Vorbilds ist
beschlossen (2026-09-02) und MUST in der Sprachreferenz unter
„Abweichungen" dokumentiert sein.
#### Scenario: Recordlänge unabhängig vom Inhalt
- **WHEN** in ein Feld `STRING * 10` einmal `abc` und einmal `äöüßÄÖÜ` geschrieben wird
- **THEN** belegt der Datensatz in beiden Fällen dieselbe Byteanzahl und der Folgesatz beginnt an derselben Position
### Requirement: Binärzugriff auf Byteebene
`OPEN … FOR BINARY` SHALL byteweise Positionierung erlauben. `GET`/`PUT`
SHALL an einer 1-basierten Byteposition lesen bzw. schreiben, wobei die
übertragene Länge der Größe der Zielvariablen entspricht. `SEEK` als
Anweisung SHALL die Position setzen, `SEEK` als Funktion sie liefern.
#### Scenario: Positioniertes Byte überschreiben
- **WHEN** in einer Binärdatei an Position 4 ein Byte geschrieben und anschließend gelesen wird
- **THEN** liefert das Lesen den geschriebenen Wert und die übrigen Bytes bleiben unverändert
### Requirement: Positions- und Statusfunktionen
`LOF` SHALL die Dateigröße in Bytes liefern, `LOC` die aktuelle Position
in der Einheit der Zugriffsart (Datensatz bei `RANDOM`, Byte bei
`BINARY`), `SEEK` die nächste Lese-/Schreibposition und `FILEATTR` den
Modus bzw. das Betriebssystem-Handle. Alle Funktionen MUST bei einer nicht
geöffneten Dateinummer Laufzeitfehler 52 auslösen.
#### Scenario: Größe nach dem Schreiben
- **WHEN** 100 Bytes geschrieben wurden und `LOF(1)` aufgerufen wird
- **THEN** liefert `LOF(1)` den Wert 100
#### Scenario: Statusfunktion auf geschlossener Datei
- **WHEN** `LOF(9)` ohne offene Datei 9 aufgerufen wird
- **THEN** tritt Laufzeitfehler 52 auf
### Requirement: Satzsperren
`LOCK` und `UNLOCK` SHALL einen Datensatz-, Byte- oder den gesamten
Dateibereich sperren und wieder freigeben. Auf Plattformen ohne
entsprechende Sperrmechanik MUST das Verhalten in der Sprachreferenz unter
„Abweichungen" dokumentiert sein statt still abzuweichen.
#### Scenario: Sperren und Freigeben
- **WHEN** ein Datensatzbereich gesperrt und anschließend mit denselben Grenzen freigegeben wird
- **THEN** läuft die Folgeoperation auf diesem Bereich ohne Fehler
### Requirement: Dateisystem-Anweisungen mit plattformübergreifender Pfadsemantik
`KILL`, `NAME … AS`, `FILES`, `CHDIR`, `CHDRIVE`, `MKDIR`, `RMDIR`,
`CURDIR$`, `DIR$` sowie `SHELL` als Anweisung **und** als Funktion SHALL
verfügbar sein. `CURDIR$` SHALL das aktuelle Verzeichnis liefern, `DIR$`
den ersten bzw. — bei leerem Argument — den nächsten Treffer eines
Suchmusters und den leeren String, wenn keiner mehr folgt. Die
`SHELL`-Funktion SHALL den Beendigungsstatus des aufgerufenen Prozesses
liefern. `CHDRIVE` SHALL auf Plattformen ohne Laufwerksbuchstaben
namentlich abgewiesen oder als Non-Feature dokumentiert werden. Pfade SHALL sowohl `\` als auch `/` als Trennzeichen
akzeptieren und auf die Konvention der laufenden Plattform abgebildet
werden; Laufwerksbuchstaben SHALL auf Nicht-Windows-Plattformen als
gewöhnlicher Namensbestandteil behandelt oder mit benannter Ablehnung
abgewiesen werden. Fehlende Dateien MUST Fehler 53 auslösen, fehlende
Pfade Fehler 76 „Path not found".
#### Scenario: Rückwärts-Schrägstrich auf Unix
- **WHEN** `OPEN "unter\d.txt" FOR OUTPUT AS #1` auf einer Unix-Plattform ausgeführt wird
- **THEN** entsteht die Datei `d.txt` im Verzeichnis `unter`
#### Scenario: Verzeichnis durchlaufen
- **WHEN** `DIR$("*.txt")` und danach `DIR$("")` wiederholt ausgewertet werden
- **THEN** liefern sie nacheinander alle passenden Namen und zuletzt den leeren String
#### Scenario: Fehlender Pfad
- **WHEN** `MKDIR` in einem nicht existierenden Elternverzeichnis aufgerufen wird
- **THEN** tritt Laufzeitfehler 76 auf
### Requirement: LPRINT als Druckausgabe
`LPRINT` und `LPRINT USING` SHALL wie `PRINT` formatieren und in einen
Druckerkanal schreiben. `LPOS` SHALL die aktuelle Spalte im
Druckerpuffer liefern. Existiert auf der Plattform kein Druckerkanal,
MUST das Ziel (Datei, Standardausgabe oder Ablehnung) in der
Sprachreferenz unter „Abweichungen" dokumentiert sein.
#### Scenario: LPRINT formatiert wie PRINT
- **WHEN** `LPRINT 1; 2` ausgeführt wird
- **THEN** entspricht der erzeugte Text der Ausgabe von `PRINT 1; 2`
#### Scenario: Druckerspalte
- **WHEN** nach `LPRINT "abc";` die Funktion `LPOS(0)` ausgewertet wird
- **THEN** liefert sie die Spalte hinter dem ausgegebenen Text

View File

@@ -10,16 +10,28 @@ geprüft werden.
### Requirement: Korpusdateien mit byte-genauer Sollausgabe
Jedes Korpusprogramm `tests/compat/<name>.bas` SHALL eine `<name>.out`
mit der exakten Konsolenausgabe besitzen (UTF-8, LF-Zeilenenden).
Nachgestellte Leerzeichen sind signifikant — `PRINT` gibt Zahlen mit
führendem Vorzeichen-/Leerzeichen und nachgestelltem Leerzeichen aus,
auch am Zeilenende; `.gitattributes` MUST die `.out`-Dateien vor
mit dem exakten Sollzustand des Bildschirms besitzen (UTF-8,
LF-Zeilenenden). Die Sollausgabe SHALL den Zellenpuffer als Textbild
abbilden, getrimmt bis zur letzten belegten Zeile und Spalte; nachgestellte
Leerzeichen innerhalb einer Zeile sind signifikant — `PRINT` gibt Zahlen
mit führendem Vorzeichen-/Leerzeichen und nachgestelltem Leerzeichen aus.
Verwendet ein Programm `COLOR`, SHALL die Sollausgabe zusätzlich eine
Attributebene gleicher Abmessung enthalten; ohne `COLOR` MUST sie
entfallen. `.gitattributes` MUST die `.out`-Dateien vor
Zeilenenden-Konvertierung schützen.
#### Scenario: Zahlformatierung in der Sollausgabe
- **WHEN** ein Korpusprogramm `PRINT 1; 2; 3` enthält
- **THEN** lautet die Sollzeile ` 1 2 3 ` (mit nachgestelltem Leerzeichen)
#### Scenario: Getrimmter Snapshot
- **WHEN** ein Korpusprogramm nur zwei Zeilen ausgibt
- **THEN** umfasst die Sollausgabe genau diese zwei Zeilen und keine leeren Folgezeilen
#### Scenario: Attributebene nur bei COLOR
- **WHEN** ein Korpusprogramm ohne `COLOR` läuft
- **THEN** enthält seine `.out` keine Attributebene
### Requirement: Frontend-Meilenstein über den Korpus
Ein automatischer Test SHALL alle `tests/compat/*.bas` durch das
Sprach-Frontend führen und fehlschlagen, sobald eine Datei Diagnosen
@@ -32,19 +44,26 @@ hinzu.)
### 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.
kompilieren, über die VM mit einem Host ohne Terminal ausführen und den
resultierenden Bildschirmzustand gegen die zugehörige `.out`-Datei
vergleichen — getrimmt, mit signifikanten Leerzeichen innerhalb der
Zeilen und, sofern vorhanden, einschließlich der Attributebene. Bei
Abweichung MUST der Test Datei, erste abweichende Zeile sowie Soll und
Ist nennen; weicht nur die Attributebene ab, MUST er Zeile, Spalte, Soll-
und Ist-Attribut 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
- **THEN** stimmt der Bildschirmzustand jeder Korpusdatei 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
#### Scenario: Abweichendes Farbattribut
- **WHEN** ein Korpusprogramm dasselbe Textbild, aber ein abweichendes Attribut erzeugt
- **THEN** schlägt der Test fehl und nennt Zeile, Spalte, Soll- und Ist-Attribut
### Requirement: Korpusabdeckung der Phase-2-Semantik
Der Korpus SHALL um Referenzprogramme mit dokumentierter Sollausgabe für
die Zahlenkonvertierungs-Matrix (Rundung, Ganzzahldivision, logische
@@ -55,3 +74,39 @@ 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
### Requirement: Korpusabdeckung der Phase-3-Semantik
Der Korpus SHALL um Referenzprogramme mit dokumentierter Sollausgabe für
die Bildschirmsteuerung (`LOCATE`, `COLOR`, `CLS`, `VIEW PRINT`-Scrollen,
`CSRLIN`/`POS`, Zurücklesen per `SCREEN`), die Formatierung
(`PRINT USING` inklusive Feldüberlauf), breite Unicode-Zeichen
(Doppelzellen, Umbruch am rechten Rand), Datum und Zeit sowie die
Datei-E/A in allen drei Zugriffsarten erweitert werden. Dateiprogramme
MUST in einem temporären Arbeitsverzeichnis laufen und dürfen keine
Artefakte im Projektbaum hinterlassen.
#### Scenario: Bildschirmsteuerung als Korpustest
- **WHEN** die Testsuite läuft
- **THEN** existiert ein Korpusprogramm, das mit `LOCATE` und `COLOR` an definierten Positionen ausgibt, und sein Snapshot entspricht der Sollausgabe
#### Scenario: Datei-Korpustest hinterlässt nichts
- **WHEN** ein Datei-E/A-Korpusprogramm gelaufen ist
- **THEN** ist das Arbeitsverzeichnis wieder entfernt und der Projektbaum unverändert
### Requirement: Nachweis der Größenunabhängigkeit
Die Bildschirmgröße des Test-Hosts SHALL je Korpusprogramm explizit
festgelegt und in der Sollausgabe vermerkt sein; ein Vorgabewert MUST NOT
stillschweigend gelten. Mindestens ein Korpusprogramm SHALL bei zwei
verschiedenen Bildschirmgrößen laufen und je Größe eine eigene
Sollausgabe besitzen, um nachzuweisen, dass Löschen, Umbruch, Scrollen
und Cursorgrenzen der jeweiligen Größe folgen. Mindestens ein
Korpusprogramm SHALL eine Größenänderung während der Ausführung
durchlaufen und danach die neuen Grenzen ausnutzen.
#### Scenario: Gleiches Programm bei zwei Größen
- **WHEN** dasselbe Bildschirm-Korpusprogramm bei 80×25 und bei 120×40 läuft
- **THEN** stimmt jede Ausgabe mit der Sollausgabe ihrer Größe überein und die Sollausgaben unterscheiden sich in Umbruch- und Scrollverhalten
#### Scenario: Größenänderung mitten im Programm
- **WHEN** der Test-Host während der Ausführung von 80×25 auf 120×40 wechselt
- **THEN** bleibt der bisherige Inhalt oben links erhalten und die anschließende Ausgabe nutzt die neuen Grenzen

View File

@@ -19,16 +19,30 @@ Opcode); die Tabelle lebt in der Laufzeitbibliothek und ist ohne
- **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.
Alle Konsolenwirkungen der Ausführungsschicht SHALL über eine
austauschbare Host-Schnittstelle laufen, die einen Bildschirmzustand
darstellt statt eines Zeichenstroms: Übergabe des Zellenpuffers zur
Anzeige, Abholen von Tastatur- und Größenänderungsereignissen sowie die
Abbruchprüfung (Strg+Untbr). Host-Aufrufe dürfen blockieren.
`tbc run` SHALL einen Konsolen-Host verwenden, der den Puffer im Terminal
darstellt und Tastendrücke liefert. Tests MUST einen Host verwenden
können, der ohne Terminal arbeitet, den Bildschirmzustand nach jedem
Schritt festhält und vorbereitete Tastendrücke einspeist. Eine
Bildschirmwirkung, die nur über einen Zeichenstrom ausdrückbar wäre, MUST
NOT vorkommen: `LOCATE`, `COLOR`, `CSRLIN`, `POS` und die Funktionsform
von `SCREEN` MUST über diese Schnittstelle vollständig abgebildet sein.
#### 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
- **THEN** entsteht der vollständige Bildschirmzustand im Capture-Host und ist vergleichbar, ohne dass ein Terminal vorhanden ist
#### Scenario: Cursorbewegung über die Schnittstelle
- **WHEN** ein Programm `LOCATE 5, 10 : PRINT "x"` ausführt
- **THEN** meldet der Host-Bildschirmzustand das Zeichen `x` an Position (5, 10)
#### Scenario: Tastendruck aus dem Host
- **WHEN** der Test-Host einen vorbereiteten Tastendruck liefert und das Programm `INKEY$` auswertet
- **THEN** erhält das Programm diese Taste
### Requirement: PRINT-Formatierung
`PRINT` SHALL Zahlen im Format des Vorbilds ausgeben: führendes
@@ -48,20 +62,171 @@ Zeilenumbruch.
- **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`
### Requirement: Vollständige Stringbibliothek
Die Bibliothek SHALL sämtliche in der Original-Hilfe dokumentierten
Stringfunktionen und -anweisungen mit der Semantik des Vorbilds
bereitstellen — darunter `LEN`, `LEFT$`, `RIGHT$`, `MID$` (Funktion und
Anweisung), `INSTR`, `UCASE$`, `LCASE$`, `LTRIM$`, `RTRIM$`, `STRING$`,
`SPACE$`, `CHR$`, `ASC`, `STR$`, `VAL`, `HEX$`, `OCT$` und `SWAP` für
Strings. Zeichen sind Unicode-Codepoints (dokumentierte Abweichung).
Randfälle folgen dem Vorbild: `VAL` liest das führende Zahlenpräfix und
überspringt Leerraum, `STR$` stellt nicht-negativen Zahlen ein Leerzeichen
voran, `ASC("")` löst Laufzeitfehler 5 aus, eine Startposition kleiner 1
bei `MID$`/`INSTR` ebenso, `LEFT$`/`RIGHT$` mit Länge über der Stringlänge
liefern den ganzen String. Welche Elemente die Liste umfasst, MUST das
Sprachinventar bestimmen; ein dort als `implementiert` geführtes Element
MUST verfügbar sein.
#### Scenario: VAL mit Restzeichen
- **WHEN** `VAL(" 12.5abc")` ausgewertet wird
- **THEN** ist das Ergebnis 12.5
#### Scenario: Länge über Stringende
- **WHEN** `LEFT$("ab", 10)` ausgewertet wird
- **THEN** ist das Ergebnis `ab`
#### Scenario: Ungültige Startposition
- **WHEN** `MID$("abc", 0)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: PRINT USING und FORMAT$
`PRINT USING`, `LPRINT USING` und `FORMAT$` SHALL die Formatzeichen des
Vorbilds unterstützen: numerische Platzhalter (`#`), Dezimalpunkt,
Tausendertrennung (`,`), Vorzeichenführung (`+`, `-`), Währungs- und
Füllzeichen (`$$`, `**`, `**$`), Exponentialform (`^^^^`) sowie die
String-Platzhalter `&`, `!` und `\ \`. Literale Zeichen SHALL unverändert
übernommen werden, `_` SHALL das Folgezeichen literal machen. Passt ein
Wert nicht in das Feld, SHALL die Ausgabe mit einem `%`-Präfix erfolgen
und der Wert vollständig dargestellt werden; dieses Überlaufverhalten MUST
in der Sprachreferenz festgehalten sein. Eine Formatzeichenkette ohne
Platzhalter bei vorhandenen Argumenten MUST Laufzeitfehler 5 auslösen.
`SetFormatCC` SHALL das für `$$` verwendete Währungszeichen und die
zugehörige Stellung setzen; ohne Aufruf gilt ein dokumentierter
Vorgabewert.
#### Scenario: Numerisches Feld mit Nachkommastellen
- **WHEN** `PRINT USING "###.##"; 3.14159` ausgeführt wird
- **THEN** lautet die Ausgabe ` 3.14`
#### Scenario: Feldüberlauf
- **WHEN** `PRINT USING "##"; 12345` ausgeführt wird
- **THEN** beginnt die Ausgabe mit `%` und enthält den vollständigen Wert
#### Scenario: Formatzeichenkette wird wiederverwendet
- **WHEN** `PRINT USING "## "; 1; 2; 3` ausgeführt wird
- **THEN** wird die Formatzeichenkette für jeden Wert erneut angewandt
### Requirement: Datums- und Zeitbibliothek
Die Bibliothek SHALL die Datums- und Zeitfunktionen des Vorbilds
bereitstellen: `DATE$` und `TIME$` als Funktion und als Anweisung, `TIMER`,
`NOW`, `DATESERIAL`, `TIMESERIAL`, `DATEVALUE`, `TIMEVALUE`, `DAY`,
`MONTH`, `YEAR`, `WEEKDAY`, `HOUR`, `MINUTE`, `SECOND`. Serielle Datumswerte
SHALL der Zählweise des Vorbilds folgen (ganzzahliger Anteil = Tag,
Nachkommaanteil = Tageszeit). `WEEKDAY` SHALL 1 für Sonntag liefern.
Ungültige Datums- oder Zeitangaben MUST Laufzeitfehler 5 auslösen.
#### Scenario: Serienwert und Rückumwandlung
- **WHEN** `d = DATESERIAL(1992, 3, 15)` gebildet und `YEAR(d)`, `MONTH(d)`, `DAY(d)` ausgewertet werden
- **THEN** liefern sie 1992, 3 und 15
#### Scenario: Wochentagszählung
- **WHEN** `WEEKDAY` auf einen Sonntag angewandt wird
- **THEN** ist das Ergebnis 1
#### Scenario: Ungültiges Datum
- **WHEN** `DATESERIAL(1992, 13, 1)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: Kompatibler Zufallszahlengenerator
`RND` und `RANDOMIZE` SHALL die Zahlenfolge des Vorbilds reproduzieren:
gleicher Startwert MUST dieselbe Folge liefern. `RND` ohne Argument und
mit positivem Argument SHALL die nächste Zahl liefern, mit Argument 0 die
zuletzt gelieferte wiederholen, mit negativem Argument die Folge auf einen
aus dem Argument abgeleiteten Startwert setzen. `RANDOMIZE` ohne Argument
SHALL einen Startwert erfragen, `RANDOMIZE TIMER` einen zeitabhängigen
setzen. Der verwendete Algorithmus MUST in der Sprachreferenz dokumentiert
sein.
#### Scenario: Reproduzierbare Folge
- **WHEN** zweimal `RANDOMIZE 42` gefolgt von drei `RND`-Aufrufen ausgeführt wird
- **THEN** sind beide Dreierfolgen identisch
#### Scenario: RND(0) wiederholt
- **WHEN** nach einem `RND`-Aufruf `RND(0)` ausgewertet wird
- **THEN** liefert es denselben Wert wie der vorangegangene Aufruf
### Requirement: Mathematikbibliothek mit Überlaufverhalten
Die Bibliothek SHALL die numerischen Funktionen des Vorbilds
bereitstellen (`ABS`, `SGN`, `INT`, `FIX`, `SQR`, `EXP`, `LOG`, `SIN`,
`COS`, `TAN`, `ATN`, `CINT`, `CLNG`, `CSNG`, `CDBL`, `CCUR`). Rundung
SHALL kaufmännisch-symmetrisch zur geraden Zahl erfolgen (Banker's
Rounding). Überschreitet ein Ergebnis den Wertebereich des Zieltyps, MUST
Laufzeitfehler 6 „Overflow" auftreten; `SQR` und `LOG` mit unzulässigem
Argument MUST Laufzeitfehler 5 auslösen, Division durch null Fehler 11.
#### Scenario: Rundung zur geraden Zahl
- **WHEN** `CINT(0.5)` und `CINT(1.5)` ausgewertet werden
- **THEN** liefern sie 0 und 2
#### Scenario: Überlauf bei Konvertierung
- **WHEN** `CINT(40000)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 6 auf
#### Scenario: Wurzel aus negativer Zahl
- **WHEN** `SQR(-1)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: Finanzmathematische Funktionen
Die Bibliothek SHALL die finanzmathematischen Funktionen des Vorbilds
bereitstellen: `FV#` (Endwert), `PV#` (Barwert), `Pmt#` (Zahlung),
`IPmt#` (Zinsanteil), `PPmt#` (Tilgungsanteil), `NPer#` (Anzahl
Zahlungsperioden), `Rate#` (Zinssatz), `NPV#` (Kapitalwert), `IRR#`
(interner Zinsfuß), `MIRR#` (modifizierter interner Zinsfuß), `SLN#`
(lineare Abschreibung), `SYD#` (arithmetisch-degressive Abschreibung) und
`DDB#` (geometrisch-degressive Abschreibung). Alle SHALL in DOUBLE
rechnen. Das Argument für die Fälligkeit SHALL zwischen nachschüssiger
und vorschüssiger Zahlung unterscheiden. Ungültige Argumente — etwa ein
Zinssatz von null bei `NPer#` oder eine Periode außerhalb der Laufzeit
bei `IPmt#`/`PPmt#` — MUST Laufzeitfehler 5 auslösen. `Rate#` und `IRR#`
nähern sich iterativ; findet die Näherung keine Lösung, MUST
Laufzeitfehler 5 auftreten statt eines stillen Ersatzwerts. Die
Abbruchbedingung der Näherung MUST in docs/bibliothek.md dokumentiert
sein.
#### Scenario: Endwert einer Rentenzahlung
- **WHEN** `FV#` für 10 Perioden, 5 % Zins und eine Zahlung von 100 nachschüssig ausgewertet wird
- **THEN** entspricht das Ergebnis dem dokumentierten Sollwert der Bibliotheksreferenz
#### Scenario: Zins- und Tilgungsanteil ergänzen sich
- **WHEN** `IPmt#` und `PPmt#` für dieselbe Periode desselben Darlehens ausgewertet werden
- **THEN** ist ihre Summe gleich `Pmt#` für dieses Darlehen
#### Scenario: Näherung ohne Lösung
- **WHEN** `IRR#` mit einer Zahlungsreihe ohne Vorzeichenwechsel ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: System- und Umgebungsanweisungen
`ENVIRON$` SHALL Umgebungsvariablen nach Namen oder Position liefern,
`ENVIRON` sie setzen. `COMMAND$` SHALL die Aufrufargumente ohne
Programmnamen liefern. `FRE` SHALL einen Speicherwert liefern, `CLEAR`
Variablen zurücksetzen, `TRON`/`TROFF` die Ablaufverfolgung schalten.
`STACK` SHALL als Anweisung die Stapelgröße setzen und als Funktion die
verfügbare Stapelgröße liefern. `SYSTEM` SHALL das Programm beenden und
die Kontrolle an das Betriebssystem zurückgeben. `ERDEV` und `ERDEV$`
SHALL den Fehlercode bzw. den Namen des zuletzt meldenden Geräts
liefern. Nicht abbildbare Größen (Speicher- und Stapelwerte, Gerätefehler)
MUST einen definierten, dokumentierten Ersatzwert liefern statt still zu
variieren; der Ersatzwert MUST in docs/sprachreferenz.md unter
„Abweichungen" stehen.
#### Scenario: Umgebungsvariable lesen
- **WHEN** eine Umgebungsvariable gesetzt ist und `ENVIRON$("NAME")` ausgewertet wird
- **THEN** liefert es deren Wert
#### Scenario: SYSTEM beendet das Programm
- **WHEN** ein Programm `SYSTEM` ausführt
- **THEN** endet es mit demselben Beendigungsstatus wie bei `END`
#### Scenario: Unbekannte Umgebungsvariable
- **WHEN** `ENVIRON$` für einen nicht gesetzten Namen ausgewertet wird
- **THEN** ist das Ergebnis der leere String

View File

@@ -120,3 +120,56 @@ diagnose-freies Modul MUST ein vollständiges HIR ergeben.
#### 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
### Requirement: Jedes dokumentierte Element besitzt eine Signatur
Die Semantik SHALL für jedes im Sprachinventar geführte Element eine
Signatur besitzen (Argumentanzahl und -typen) — auch für Elemente, deren
Laufzeitverhalten noch aussteht. Ein im Inventar geführtes Element MUST
NOT als unbekannter Bezeichner oder mit einem generischen Syntaxfehler
abgewiesen werden; die Diagnose bzw. der Laufzeitfehler MUST es
namentlich nennen (Guiding Principle). Das gilt insbesondere für die
Gruppen, die bisher gar keine Signatur haben: die finanzmathematischen
Funktionen, die Record-Konvertierungsfunktionen (`MK…$`/`CV…`), die
Dateisystem-Funktionen `CURDIR$`, `DIR$`, `CHDRIVE`, sowie `LPOS`,
`STACK`, `SYSTEM`, `ERDEV`/`ERDEV$` und `SetFormatCC`.
#### Scenario: Element ohne Laufzeitverhalten wird namentlich abgewiesen
- **WHEN** ein Modul eine im Inventar als `offen` geführte Funktion verwendet
- **THEN** nennt die Ablehnung deren Namen und nicht „unbekannter Bezeichner"
#### Scenario: Argumentprüfung ohne Laufzeitverhalten
- **WHEN** ein Modul `MKL$()` ohne Argument enthält
- **THEN** meldet die Semantik eine Argumentanzahl-Diagnose, die `MKL$` nennt
### Requirement: Modulweites ON ERROR ist aus Prozeduren ansprechbar
`ON ERROR GOTO label` ohne `LOCAL` SHALL einen modulweiten Fehlerhandler
setzen, dessen Sprungziel auch dann aufgelöst wird, wenn die Anweisung in
einer Prozedur steht und das Label auf Modulebene liegt. Nur
`ON LOCAL ERROR GOTO label` SHALL prozedurlokale Handler-Auflösung
verlangen. Ein modulweites `ON ERROR` in einer Prozedur MUST NOT wie
`ON LOCAL ERROR` behandelt werden, und ein auf Modulebene vorhandenes
Label MUST NOT als „Label not defined" gemeldet werden.
#### Scenario: Handler auf Modulebene aus einer Prozedur
- **WHEN** ein Modul das Label `Fehler:` auf Modulebene führt und eine `SUB` die Anweisung `ON ERROR GOTO Fehler` enthält
- **THEN** wird das Label aufgelöst und es entsteht keine Diagnose
#### Scenario: ON LOCAL ERROR bleibt prozedurlokal
- **WHEN** eine `SUB` die Anweisung `ON LOCAL ERROR GOTO Fehler` enthält und `Fehler:` nur auf Modulebene existiert
- **THEN** wird „Label not defined" gemeldet
### Requirement: DATA-Elemente behalten ihren Rohtext
Unquotierte Elemente einer `DATA`-Anweisung SHALL exakt so erhalten
bleiben, wie sie im Quelltext stehen — insbesondere in ihrer Groß- und
Kleinschreibung. Die Normalisierung von Bezeichnern MUST NOT auf
`DATA`-Elemente wirken. Führender und nachgestellter Leerraum eines
unquotierten Elements SHALL entfernt werden, innenliegender erhalten
bleiben.
#### Scenario: Gemischte Schreibweise bleibt erhalten
- **WHEN** ein Modul `DATA Hallo Welt` enthält und `READ s$` ausgeführt wird
- **THEN** enthält `s$` den Text `Hallo Welt` mit unveränderter Groß- und Kleinschreibung
#### Scenario: Leerraum an den Rändern
- **WHEN** ein Modul `DATA ab cd ` enthält und gelesen wird
- **THEN** lautet der Wert `ab cd`

View File

@@ -0,0 +1,76 @@
# sprachinventar Specification
## Purpose
Das Sprachinventar ist das Messinstrument für die Leitplanke
„Vollständigkeit ist das Soll": eine gepflegte Liste aller in der
Original-Hilfe des Vorbilds dokumentierten Anweisungen, Funktionen und
Metabefehle mit Abdeckungsstatus, gegen die sich der Implementierungsstand
jederzeit prüfen lässt.
## Requirements
### Requirement: Vollständiges Inventar der Original-Hilfe
`docs/inventar.md` SHALL jede in der Original-Hilfe des Vorbilds
dokumentierte Anweisung, Funktion, Metabefehl, Operator-Schlüsselwort und
Klausel als eigenen Eintrag führen. Ein dokumentiertes Element MUST NOT
fehlen; Vollständigkeit gegenüber der Quelle geht der Kürze vor. Jeder
Eintrag SHALL Name, Art (Anweisung/Funktion/Metabefehl), Themengruppe,
Status und Fundstelle tragen.
#### Scenario: Dokumentiertes Element ist erfasst
- **WHEN** die Original-Hilfe die Anweisung `VIEW PRINT` dokumentiert
- **THEN** enthält das Inventar einen Eintrag `VIEW PRINT` mit Art, Gruppe, Status und Fundstelle
#### Scenario: Non-Feature ist erfasst, nicht weggelassen
- **WHEN** `PEEK` als Non-Feature deklariert ist
- **THEN** steht `PEEK` mit Status `Non-Feature` im Inventar und die Fundstelle verweist auf den Abschnitt „Abweichungen" der Sprachreferenz
### Requirement: Festes Statusvokabular
Der Status eines Eintrags SHALL genau einen von drei Werten tragen:
`implementiert` (Frontend senkt ab und die Laufzeit führt aus),
`offen` (dokumentiert, noch nicht verfügbar) oder `Non-Feature`
(vom Projektinhaber abgelehnt und in der Sprachreferenz unter
„Abweichungen" gelistet). Ein Eintrag mit Status `Non-Feature` MUST eine
Fundstelle in der Sprachreferenz nennen.
#### Scenario: Unzulässiger Status
- **WHEN** ein Eintrag den Status `teilweise` trägt
- **THEN** schlägt die Inventarprüfung mit Nennung des Eintrags fehl
#### Scenario: Non-Feature ohne Fundstelle
- **WHEN** ein Eintrag den Status `Non-Feature` trägt, aber keine Fundstelle nennt
- **THEN** schlägt die Inventarprüfung mit Nennung des Eintrags fehl
### Requirement: Automatischer Abgleich Inventar gegen Implementierung
Ein automatischer Test SHALL das Inventar gegen den tatsächlichen
Implementierungsstand prüfen und bei jeder Divergenz fehlschlagen. Als
`implementiert` markierte Elemente MUST im Frontend eine Signatur besitzen
und MUST NOT auf einen „nicht verfügbar"-Marker absenken; als `offen`
markierte Elemente MUST auf einen solchen Marker absenken oder ohne
Signatur sein; als `Non-Feature` markierte Elemente MUST zur Compile-Zeit
mit „Feature unavailable" abgewiesen werden. Der Test MUST das
divergierende Element, seinen Inventarstatus und den vorgefundenen
Zustand benennen.
#### Scenario: Inventar hinkt der Implementierung hinterher
- **WHEN** `LOCATE` implementiert wurde, im Inventar aber noch `offen` steht
- **THEN** schlägt der Abgleich fehl und nennt `LOCATE`, Status `offen` und den Befund „implementiert"
#### Scenario: Inventar behauptet zu viel
- **WHEN** ein Eintrag `implementiert` trägt, das Element aber weiterhin auf den „nicht verfügbar"-Marker absenkt
- **THEN** schlägt der Abgleich fehl und nennt das Element
#### Scenario: Abdeckungsstand ist abrufbar
- **WHEN** der Abgleich läuft
- **THEN** nennt er die Zahl der Einträge je Status als Abdeckungsstand
### Requirement: Keine stillen Lücken bei dokumentierten Elementen
Ein Element mit Status `offen` MUST bei Verwendung eine benannte
Ablehnung erzeugen — entweder eine Compile-Diagnose oder den Laufzeitfehler
für nicht verfügbare Funktionen —, die das Element namentlich nennt. Ein
generischer Syntaxfehler oder „unbekannter Bezeichner" für ein
dokumentiertes Element MUST NOT auftreten (Guiding Principle).
#### Scenario: Offenes Element wird namentlich abgewiesen
- **WHEN** ein Programm eine im Inventar als `offen` geführte Anweisung verwendet
- **THEN** nennt die Ablehnung den Namen der Anweisung, nicht nur „Syntaxfehler"

View File

@@ -11,9 +11,13 @@ Ratatui.
### Requirement: Dynamische Terminalgröße mit Mindestmaß
Der Bildschirm SHALL der Terminalgröße folgen (Puffer per `resize`
anpassbar; Inhalt bleibt oben links erhalten, Cursor wird geklemmt).
Die Mindestgröße ist 80×25: kleinere Werte werden auf 80×25 geklemmt,
und ist die Render-Fläche kleiner als 80×25, SHALL nur ein Hinweis
„Terminal zu klein" mit Ist- und Mindestgröße gerendert werden.
Die Größe SHALL zu jedem Zeitpunkt aus der Darstellungsfläche abgeleitet
und nicht fest vorgegeben werden. Die Mindestgröße ist 80×25: kleinere
Werte werden auf 80×25 geklemmt, und ist die Render-Fläche kleiner als
80×25, SHALL nur ein Hinweis „Terminal zu klein" mit Ist- und
Mindestgröße gerendert werden. Dieses Mindestmaß ist ausschließlich eine
untere Schranke der Darstellung; es MUST NOT als Bildschirmgröße im
Verhalten des Programms auftreten, solange die Fläche größer ist.
#### Scenario: Vergrößertes Terminal
- **WHEN** der Bildschirm auf 120×40 gesetzt wird
@@ -35,13 +39,20 @@ ohne eigene Einstellung folgt der Scrollbereich der Bildschirmgröße.
- **THEN** scrollen nur die Zeilen 35; Kopfzeilen außerhalb bleiben unverändert
### Requirement: 1-basierte Cursor-API mit Bereichsprüfung
`LOCATE`, `CSRLIN` und `POS` SHALL 1-basiert arbeiten; `LOCATE`
außerhalb der aktuellen Bildschirmgrenzen SHALL als Fehler abgewiesen
werden (Basis für Laufzeitfehler 5).
`LOCATE`, `CSRLIN` und `POS` SHALL 1-basiert arbeiten. `LOCATE`
außerhalb der aktuellen Bildschirmgrenzen SHALL Laufzeitfehler 5
„Illegal function call" auslösen. Ausgelassene Argumente von `LOCATE`
SHALL den jeweiligen Wert unverändert lassen; die Argumente für
Cursorsichtbarkeit und Cursorform SHALL entgegengenommen und, soweit das
Terminal sie nicht abbilden kann, folgenlos bleiben.
#### Scenario: Grenzprüfung
- **WHEN** bei 80×25 `LOCATE 26, 1` aufgerufen wird
- **THEN** wird der Aufruf abgewiesen
- **THEN** tritt Laufzeitfehler 5 auf
#### Scenario: Ausgelassenes LOCATE-Argument
- **WHEN** der Cursor auf (5, 9) steht und `LOCATE , 3` ausgeführt wird
- **THEN** steht der Cursor auf (5, 3)
### Requirement: Klassische Farbpalette und Blink-Simulation
Der Bildschirm SHALL die klassische Palette abbilden (Vordergrund 015,
@@ -55,11 +66,136 @@ Terminal-Blinken.
- **THEN** wird mit heller Vordergrundfarbe 9 gerendert
### Requirement: Unicode-Zellenmodell
Der Puffer SHALL Unicode-Zeichen speichern (keine CP437-Emulation);
aktuell gilt strikt 1 Zeichen = 1 Zelle. (Zeichen mit Darstellungsbreite
2 belegen künftig zwei Zellen — beschlossene Änderung, Umsetzung in
Phase 3 als eigenes Change.)
Der Puffer SHALL Unicode-Zeichen speichern (keine CP437-Emulation).
Zeichen mit Darstellungsbreite 2 (u. a. Emoji, CJK) SHALL zwei
nebeneinanderliegende Zellen belegen (Entscheidung 2026-09-02): die erste
trägt das Zeichen, die zweite ist als Fortsetzung markiert und MUST NOT
eigenständig beschrieben werden. Der Cursor SHALL nach der Ausgabe eines
breiten Zeichens um zwei Spalten vorrücken; `POS` SHALL die Spalte des
Zeichenanfangs zählen. Passt ein breites Zeichen nicht mehr in die letzte
Spalte, SHALL es vollständig in die nächste Zeile umgebrochen werden und
die letzte Spalte leer bleiben. `LOCATE` auf die Fortsetzungszelle SHALL
auf den Zeichenanfang wirken.
#### Scenario: Umlaute und Symbole
- **WHEN** `Ä☃` ausgegeben wird
- **THEN** belegen `Ä` und `☃` je genau eine Zelle
#### Scenario: Breites Zeichen belegt zwei Zellen
- **WHEN** an Spalte 1 ein CJK-Zeichen ausgegeben wird
- **THEN** ist Spalte 2 als Fortsetzung belegt und der Cursor steht auf Spalte 3
#### Scenario: Breites Zeichen am rechten Rand
- **WHEN** bei 80 Spalten der Cursor auf Spalte 80 steht und ein breites Zeichen ausgegeben wird
- **THEN** bleibt Spalte 80 leer und das Zeichen steht in Spalte 1 der Folgezeile
### Requirement: Zellenpuffer ohne Terminalabhängigkeit
Der Zellenpuffer mit der vollständigen Bildschirmsemantik (Cursor,
Farbattribute, Umbruch, Scrollen, Scrollbereich, Größenänderung) SHALL
ohne Terminal instanziierbar, veränderbar und auslesbar sein. Die
Anbindung an ein konkretes Terminal SHALL ausschließlich in der
Darstellungsschicht liegen. Damit MUST jedes Bildschirmverhalten in
automatischen Tests ohne Terminal prüfbar sein, und die Ausführungsschicht
MUST NOT von einer Terminal-Bibliothek abhängen.
#### Scenario: Bildschirmverhalten im Test ohne Terminal
- **WHEN** ein Testprogramm in einer Umgebung ohne Terminal `LOCATE 5, 10 : PRINT "x"` ausführt
- **THEN** trägt die Zelle (5, 10) das Zeichen `x` und der Test benötigt kein Terminal
### Requirement: Bildschirmanweisungen des Dialekts
`CLS`, `COLOR`, `LOCATE`, `WIDTH`, `VIEW PRINT` und die Anweisungsform von
`SCREEN` SHALL auf dem Zellenpuffer wirken. `CLS` SHALL den Scrollbereich
löschen und den Cursor an dessen Anfang setzen; `CLS 2` SHALL nur den
Textbereich löschen. `COLOR` SHALL Vordergrund und Hintergrund für
nachfolgende Ausgaben setzen, ausgelassene Argumente lassen den bisherigen
Wert unverändert. `WIDTH` SHALL die Spalten- und Zeilenzahl setzen, soweit
die Darstellungsfläche es zulässt. `VIEW PRINT oben TO unten` SHALL den
Scrollbereich begrenzen, `VIEW PRINT` ohne Argumente ihn auf den ganzen
Bildschirm zurücksetzen.
#### Scenario: CLS setzt Cursor zurück
- **WHEN** nach Ausgaben in Zeile 10 `CLS` ausgeführt wird
- **THEN** ist der Puffer leer und `CSRLIN` liefert 1, `POS(0)` liefert 1
#### Scenario: COLOR wirkt nur auf Folgeausgaben
- **WHEN** `PRINT "a" : COLOR 14, 1 : PRINT "b"` ausgeführt wird
- **THEN** trägt die Zelle mit `a` das vorherige Attribut und die Zelle mit `b` Vordergrund 14 auf Hintergrund 1
#### Scenario: Ausgelassenes COLOR-Argument
- **WHEN** nach `COLOR 14, 1` die Anweisung `COLOR , 4` ausgeführt wird
- **THEN** bleibt der Vordergrund 14 und der Hintergrund wird 4
### Requirement: Bildschirm-Abfragefunktionen
`CSRLIN` SHALL die aktuelle Cursorzeile liefern, `POS(0)` die aktuelle
Cursorspalte, beide 1-basiert. Die Funktionsform `SCREEN(zeile, spalte
[, farbe])` SHALL das Zeichen an der genannten Position als Codepoint
liefern, bei gesetztem dritten Argument stattdessen dessen Farbattribut.
Positionen außerhalb des Bildschirms MUST Laufzeitfehler 5 „Illegal
function call" auslösen.
#### Scenario: Zeichen zurücklesen
- **WHEN** `LOCATE 3, 7 : PRINT "Q";` ausgeführt und danach `SCREEN(3, 7)` ausgewertet wird
- **THEN** liefert `SCREEN(3, 7)` den Codepoint von `Q`
#### Scenario: Abfrage außerhalb des Bildschirms
- **WHEN** bei 80×25 `SCREEN(30, 1)` ausgewertet wird
- **THEN** tritt Laufzeitfehler 5 auf
### Requirement: Tastatureingabe ohne Zeilenmodell
`INKEY$` SHALL ohne zu blockieren die nächste anstehende Taste liefern:
den leeren String bei leerem Puffer, ein Zeichen bei einer
Zeichentaste, eine zwei Zeichen lange Folge mit führendem Nullzeichen bei
einer Sondertaste. `INPUT$(n [, #dateinummer])` SHALL genau `n` Zeichen
lesen und dabei blockieren, ohne sie am Bildschirm zu wiederholen.
#### Scenario: INKEY$ bei leerem Tastaturpuffer
- **WHEN** `INKEY$` ohne anstehende Taste ausgewertet wird
- **THEN** liefert es den leeren String und blockiert nicht
#### Scenario: Sondertaste als zwei Zeichen
- **WHEN** F1 gedrückt wurde und `INKEY$` ausgewertet wird
- **THEN** hat das Ergebnis die Länge 2 und beginnt mit dem Nullzeichen
### Requirement: Keine feste Bildschirmgröße im Verhalten
Kein beobachtbares Verhalten SHALL eine feste Spalten- oder Zeilenzahl
voraussetzen. Wo die Referenz des Vorbilds von 80×25 spricht, ist stets
der volle aktuelle Bildschirm gemeint. Insbesondere SHALL `CLS` den
vollen aktuellen Bildschirm löschen, der Scrollbereich ohne eigene
`VIEW PRINT`-Einstellung den vollen aktuellen Bildschirm umfassen, der
Zeilenumbruch an der aktuell letzten Spalte erfolgen, das Scrollen an
der aktuell letzten Zeile des Bereichs auslösen und die Grenzprüfung von
`LOCATE` und der Funktionsform von `SCREEN` gegen die aktuellen
Abmessungen prüfen. Die Werte 80 und 25 MUST NOT als Grenze in
beobachtbarem Verhalten auftreten.
#### Scenario: Löschen und Scrollen auf großem Bildschirm
- **WHEN** der Bildschirm 120×40 misst, in Zeile 40 ein Umbruch erfolgt und danach `CLS` ausgeführt wird
- **THEN** scrollt der Bildschirm erst an Zeile 40 und `CLS` löscht alle 40 Zeilen
#### Scenario: Adressierbarkeit jenseits von 80×25
- **WHEN** der Bildschirm 120×40 misst und `LOCATE 40, 120` ausgeführt wird
- **THEN** entsteht kein Fehler und `CSRLIN` liefert 40, `POS(0)` liefert 120
### Requirement: Größenänderung zur Laufzeit
Ändert sich die Größe der Darstellungsfläche während ein Programm läuft,
SHALL die Größenänderung als Ereignis bis zum Bildschirmzustand
durchgereicht und der Zellenpuffer angepasst werden. Der Inhalt SHALL
oben links erhalten bleiben; der Cursor SHALL in die neuen Grenzen
geklemmt werden; ein `VIEW PRINT`-Bereich, der nicht mehr vollständig in
den Bildschirm passt, SHALL auf die neuen Grenzen geklemmt und, falls er
dadurch leer würde, auf den vollen Bildschirm zurückgesetzt werden. Alle
programmseitig sichtbaren Größen — `CSRLIN`, `POS`, die Grenzen von
`LOCATE` und der Funktionsform von `SCREEN` — MUST unmittelbar nach der
Änderung die neuen Abmessungen widerspiegeln.
#### Scenario: Vergrößerung während der Ausführung
- **WHEN** ein laufendes Programm bei 80×25 ausgibt und die Fläche auf 120×40 wächst
- **THEN** bleibt der bisherige Inhalt oben links stehen und `LOCATE 40, 120` ist danach zulässig
#### Scenario: Verkleinerung klemmt den Cursor
- **WHEN** der Cursor auf Zeile 40 steht und die Fläche auf 80×25 schrumpft
- **THEN** liegt der Cursor danach innerhalb der neuen Grenzen
#### Scenario: Scrollbereich überlebt die Verkleinerung
- **WHEN** `VIEW PRINT 30 TO 38` gesetzt ist und die Fläche auf 25 Zeilen schrumpft
- **THEN** ist der Scrollbereich danach gültig und liegt vollständig innerhalb des Bildschirms