Setzt den OpenSpec-Change phase-3-isam um (49/49 Aufgaben) und schliesst damit Phase 3 ab. Alle 22 ISAM-Elemente des Inventars sind implementiert; der Abdeckungsstand steigt auf 217 implementiert / 15 offen / 53 Non-Feature. Frontend - ISAM-Anweisungen als eigener Zweig im Parser: NAME [#]n [, arg ...], Sonderform ROLLBACK ALL ueber eine Sentinel-Kennung - 22 Signaturen in builtin_stmt/builtin_fn, neue Argumentart R (Satzvariable eines benutzerdefinierten Typs) - Satzargumente von INSERT/RETRIEVE/UPDATE werden gegen den Typ der Dateinummer geprueft, sofern beide literal bekannt sind - Die Unsupported-Absenkung von OPEN ... FOR ISAM entfaellt Speicherschicht (tb-runtime::isam, einziger Ort mit redb) - Je Tabelle eine Satztabelle satz-id -> Satzbytes, je Index eine Tabelle Schluesselbytes -> satz-id. Satz-IDs sind monoton und werden nie wiederverwendet: der Cursor merkt sich eine ID, eine neu vergebene koennte still auf einen fremden Satz zeigen - Satzbytes entstehen mit fileio::wert_schreiben/wert_lesen, also mit den Recordpuffern und der UTF-32-Festtextkodierung aus datei-eio - Ordnungserhaltende Schluesselkodierung je Spaltentyp; Text als UTF-8, dessen Bytereihenfolge die Codepoint-Reihenfolge ist und damit dieselbe Ordnung wie CmpStr der VM. Ein Eigenschaftstest ueber 5000 zufaellige Wertepaare je Typ haelt fest, dass der Bytevergleich dem fachlichen Vergleich entspricht -- eine Ordnungsverletzung faellt sonst erst bei bestimmten Datenwerten auf - Cursor als Wert (aktiver Index, letzte Satz-ID, unpositioniert), nicht als gehaltener Iterator: er ueberlebt Satzaenderungen und Transaktionsgrenzen - Sicherungspunkte ueber ein eigenes Ruecknahmeprotokoll; ROLLBACK ALL bricht die Bibliothekstransaktion direkt ab Semantik durchweg aus der Original-Hilfe - Die Argumentformen stammen erstmals aus den Einzelseiten, nicht nur aus der Themenliste. Das korrigierte eine Annahme des Entwurfs: die Spaltenliste von CREATEINDEX ist keine Zeichenkette mit Trennzeichen, sondern eine Folge einzelner Stringargumente - SEEKEQ mit unvollstaendigem Schluessel schlaegt immer fehl, SEEKGT mit Teilschluessel positioniert wie SEEKGE - Nach SETINDEX ist der erste Satz der neuen Ordnung aktuell, nach DELETE der folgende - Suche ueber den NULL-Index meldet 87, nicht 83; damit hat jeder Code von 81 bis 89 einen Ausloeser - Einzige Erweiterung: ein - vor dem Spaltennamen ordnet absteigend. Die Original-Hilfe kennt bei CREATEINDEX keine Sortierrichtung, die Anforderung verlangt sie. Kollisionsfrei, weil ein TYPE-Feldname nie mit - beginnen kann CLOSE beendet keine Transaktion - Erst schrieb es sie fest, womit das Schliessen irgendeiner Dateinummer die Transaktion aller anderen mit beendete und ein folgendes ROLLBACK ALL ins Leere lief. Ausstehende Aenderungen sind ohnehin festgeschrieben, weil jede Operation ausserhalb einer Transaktion fuer sich eine ist - Ueber das Ende entscheiden allein COMMITTRANS und ROLLBACK ALL; eine beim Programmende offene Transaktion verfaellt, in beiden Wegen gleich SETMEM und Fehler 89 - Ohne DOS-Speichermodell ist SETMEM die Obergrenze des ISAM-Puffers (Vorgabe 65536 Bytes); ohne echte Grenze waere Code 89 nie erreichbar und die Anweisung eine Attrappe Tests - 18 Einheitentests (Kodierung, Formatversion, Satz-IDs, Roundtrip ueber alle Feldtypen, Indexordnung, Cursor, Protokoll) - 6 Korpusprogramme: Tabellen, Indizes, Cursor, Saetze, Transaktionen, Puffer und Vergleichsordnung -- je in einem temporaeren Arbeits- verzeichnis, der Projektbaum bleibt sauber - Der VM-Test zu Fehler 73 prueft ISAM nicht mehr, sondern SETUEVENT; dafuer belegt ein neuer Test, dass OPEN ... FOR ISAM arbeitet Dokumentation: Datenbankdateiformat in dateiformate.md, Abschnitt 10a samt Sortierordnung und SETMEM-Abweichung in sprachreferenz.md, ISAM-Abschnitt in bibliothek.md, Inventar auf implementiert, PLAN.md schaerft die Leitplanke Referenzverhalten -- sie gilt auch gegenueber den eigenen Spezifikationen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.9 KiB
Dateiformate
Terminal Basic liest und schreibt die Textformate des Vorbilds, durchgängig in UTF-8 (Abweichung: das Vorbild nutzte die DOS-Codepage). Binäre „Fast-Load"-Varianten des Vorbilds sind Nicht-Ziel — nur Textformate.
Quelltext: .BAS
Reiner Text, eine Anweisung(sfolge) pro Zeile. Optionale Kopfzeilen der IDE
(DECLARE-Prototypen) werden beim Speichern erzeugt/aktualisiert.
Metabefehle in Kommentaren: '$INCLUDE: 'datei.bi', '$STATIC, '$DYNAMIC.
Formular: .FRM
Das Vorbild kannte zwei Speicherformate: binär („Fast load and save", Standard) und Text („Readable by other programs"). Terminal Basic implementiert nur das Textformat; das Binärformat ist Nicht-Ziel (FT.EXE des Vorbilds konvertierte zwischen beiden).
Textformat, zwei Abschnitte: Formular-Beschreibung, dann Code. Schema wie
beim Windows-Schwesterprodukt: VERSION-Zeile, verschachtelte
Begin <Klassenname> <Name> … End-Blöcke (Klassennamen siehe
forms-referenz.md), Eigenschaft = Wert-Zeilen. Der Parser des Vorbilds
akzeptiert Version 1.00 und 2.00 (Import aus dem Windows-Produkt via
Übersetzer).
VERSION 1.00
Begin Form Form1
Caption = "Beispiel"
Height = 15
Left = 10
Top = 4
Width = 50
Begin CommandButton cmdOK
Caption = "&OK"
Height = 1
Left = 18
Top = 11
Width = 10
End
End
SUB cmdOK_Click ()
UNLOAD Form1
END SUB
VERSION-Zeile, dann verschachtelteBegin <Typ> <Name> … End-Blöcke mitEigenschaft = Wert-Zeilen (Strings in"…").- Danach normaler BASIC-Code des Formular-Moduls.
- TODO: Ein wörtliches Original-Beispiel einer Text-
.FRMwar online nicht auffindbar (Beispieldateien des Originalpakets liegen alle binär vor). Exakte Serialisierung (Kopfzeile, Einrückung, welche Eigenschaften geschrieben werden) ist daher festzulegen: wir folgen dem Windows-1.0-Schema und dokumentieren unsere Fassung als Referenz.
Projekt: .MAK
Reine Textdatei ohne Kopfzeile, eine Projektdatei pro Zeile
(.BAS/.FRM; belegt durch die Originalbeispiele). Terminal Basic
akzeptiert zusätzlich Kommentarzeilen mit '.
Record-Dateien (GET/PUT, OPEN … FOR RANDOM)
Feste Strings (STRING * n) in Records werden als UTF-32LE gespeichert
(4 Bytes pro Zeichen → feste Record-Länge bleibt erhalten). Entscheidung
2026-09-02: Die Binärdateien sind damit bewusst inkompatibel zu Dateien
des Vorbilds; numerische Felder behalten ihr klassisches Layout
(INTEGER i16, LONG i32, SINGLE f32, DOUBLE f64, CURRENCY i64, little-endian).
ISAM-Datenbank (OPEN … FOR ISAM)
Eigenes Format, bewusst nicht binärkompatibel zu Datenbankdateien des Vorbilds — dieselbe Linie wie bei den UTF-32-Records oben. Ein Konvertierungswerkzeug ist Nicht-Ziel; das Vorbildformat wird weder gelesen noch geschrieben.
Träger. Die Datei ist eine redb-Datei
(eingebetteter transaktionaler B-Baum). redb liefert Seitenverwaltung,
Transaktionen und Crash-Sicherheit; die ISAM-Semantik darüber ist eigener
Code (siehe tb-runtime::isam).
Formatversion. Die Datei trägt in ihrer Metatabelle unter version
eine 32-Bit-Formatversion (little-endian), derzeit 1. Eine Datei mit
höherer Version wird beim Öffnen mit Laufzeitfehler 88 („ISAM - Database
inconsistent") abgewiesen, statt fehlinterpretiert zu werden. Ebenso
abgewiesen wird eine bestehende Datei ohne Versionsmarke sowie jede
strukturell unlesbare Datei.
Tabellen in der Datei. Je Datenbankdatei:
redb-Tabelle |
Schlüssel → Wert | Inhalt |
|---|---|---|
tb_meta |
&str → Bytes |
Formatversion, Layout, Indexdefinitionen, ID-Zähler |
satz/<tabelle> |
u64 → Bytes |
ein Satz je Eintrag, Schlüssel ist die Satz-ID |
idx/<tabelle>/<index> |
Bytes → u64 |
Indexeintrag: Schlüsselbytes → Satz-ID |
Die Einträge in tb_meta je Tabelle T:
tab:T— Layoutkurzformspalte:typ;…mit den TypkürzelnI2,I4,R4,R8,CY,T<n>(fester Text mitnZeichen). Beim Öffnen einer bestehenden Tabelle wird sie gegen den angegebenen Satztyp geprüft; Abweichung ist Fehler 88.idx:T— eine Zeile je Index,name<TAB>eindeutig<TAB>spalten, Spalten als Feldnummern mit-für absteigend.seq:T— nächste Satz-ID (u64, little-endian). IDs werden monoton vergeben und nie wiederverwendet: ein Cursor merkt sich eine Satz-ID, und eine nachDELETEneu vergebene ID ließe ihn still auf einen fremden Satz zeigen.
Satzbytes. Ein Satz liegt genau so im Speicher wie ein Record bei
PUT auf eine RANDOM-Datei: numerische Felder klassisch und
little-endian, feste Strings als UTF-32LE. Daher gilt die Inkompatibilität
zum Vorbild aus demselben Grund wie oben.
Indexschlüssel. Die Schlüsselbytes sind ordnungserhaltend kodiert —
ihr Byte-Vergleich entspricht dem fachlichen Vergleich, weil redb nach
Bytes ordnet:
- Ganzzahlen: Big-Endian fester Breite mit gekipptem Vorzeichenbit.
- Gleitkommazahlen: Big-Endian der Bitdarstellung; bei negativem Vorzeichen alle Bits invertiert, sonst das oberste Bit gesetzt.
- Text: UTF-8 (dessen Bytereihenfolge ist die Codepoint-Reihenfolge, siehe
„Sortierordnung" der Sprachreferenz).
00im Text wird zu00 FFverdoppelt, den Abschluss bildet00 00— damit ordnet ein echtes Präfix vor jedem längeren Text. - Absteigende Spalten: alle Bytes dieser Spalte invertiert.
- Mehrspaltig: Verkettung in Spaltenreihenfolge.
An jeden Indexschlüssel sind acht Bytes Satz-ID (Big-Endian) angehängt. Das macht auch Einträge eines mehrdeutigen Index eindeutig, hält Dubletten in Einfügereihenfolge und macht die Präfixsuche zur Bereichsabfrage.
Kompilat: .tbc (neu, eigenes Format)
Container für TBVM-Bytecode, Entwurf in tbvm-design.md.
tbc build erzeugt wahlweise .tbc oder ein eigenständiges Executable
(Runner + eingebettetes .tbc).