Textadventures > Zeta

Inform

Inform ist wie Zeta ein Compiler für z-Code, und beide sind sich recht ähnlich, bei der Entwicklung von Zeta habe ich mich sehr stark an Inform orientiert. Dennoch gibt es einige Unterschiede in Syntax und Konzepten.


Syntax

Schlüsselwörter. Die Schlüsselwörter in Zeta sind auf Deutsch, was vielleicht etwas verwirrend ist. Wer dies nicht mag, kann sich mit #alias Synonyme definieren, die der Inform-Syntax entsprechen.

Textausgabe. Text, der ausgegeben werden soll, steht wie in Inform in Gänsefüßchen. Es gibt kein Äquivalent zu print. Um einen Text auszugeben, schreibt man einfach einen frei stehenden String in den Code. Um einen String auszugeben und dann die Routine zu verlassen, stellt man dem String oder dem Textausdruck ein stop voran.

Es gibt auch keine printing rules, es werden einfach Routinen aufgerufen, deren Rückgabewert nicht benutzt wird. Um eine Zahl auszugeben, verwendet man die Systemfunktion num(x).

Gänsefüßchen im Text werden doppelt geschrieben. Ein Zeilenumbruch wird mit \n erzielt, die Zeichen ^ und ~ haben keine spezielle Bedeutung. Statt mit dem Klammeraffen @ werden Steuersequenzen mit dem Backslash \ eingeleitet. Kurzstrings haben einen Namen, keine Nummer und werden in geschweiften Klammern angegeben.

Absätze sind zwei Zeilenumbrüche und können mit \p geschrieben werden. Eine leere Zeile innerhalb eines Strings bezeichnet ebenfalls einen Absatz.

print "Hier siehst du ", (einen) x, ".^";
print n;
stop "~So, genug f@:ur heute!~^";
print "@12 pfeift ein Lied.";
 
"Hier siehst du ", einen(x), ".\n";
num(n);
"""So, genug f\:ur heute!""\n";
"{Robert} pfeift ein Lied.";

Routinen und Rückgabewerte. Routinen werden in geschweiften Klammern angegeben wie Codeblöcke. Die Definition von globalen Routinen wird mit dem Schlüsselwort Routine eingeleitet, Parameter können in runden Klammern angegeben werden. Lokale Variablen werden mit dem Schlüsselwort lokal definiert. Trotz der Trennung der Syntax für Argumente und lokale Variablen unterscheidet Zeta allerdings nicht zwischen ihnen. Lokale Variablen können auch innerhalb von Codeblöcken definiert werden, sie gelten dann nur dort.

Wenn nichts anderes angegeben wird, geben alle Routinen, egal ob sie globale Routinen oder Methoden von Objekten sind, falsch zurück. Es gibt kein implizites Beenden der Routine wie in Inform bei print_ret oder einem freistehenden String, in Zeta kann die Routine nur vorzeitig verlassen werden, wenn explizit eine der Anweisungen antworte oder stop benutzt wird.

Abkürzungen wie rtrue oder rfalse gibt es nicht.

[ mach_was i j   k;
    k = i*j;
    while (k--) "x";
    return i*j;
];
 
Routine mach_was(i, j) {
    lokal k = i*j;
    solange (k--) "x";
    antworte i*j;
];

Felder. Feldeinträge werden mit eckigen Klammern [] angesprochen, der Typ des Felds wird erkannt. Die Operatoren -> und --> gibt es auch, um Mischfelder ansprechen zu können. Bei der Definition werden Werte nach einem Gleichzeichen und mit Kommas getrennt angegeben.

Array Karten --> 32;
Array Bäume --> "Fichte" "Birke" "Eberesche" "Ahorn";

Karten-->i = Karten-->(i+1);
 
Feld Karten [32];
Feld Bäume = "Fichte", "Birke", "Eberesche", "Ahorn";

Karten[i] = Karten[i+1];

Objekte. Objekte in Zeta und in Inform sind von ihrer Datenstruktur her sehr ähnlich, da beiden das Objektkonzept der z-Maschine zugrunde liegt. Unterschiede gibt es aber vor allem im Eingabeformat des Objektkörpers.

Inform schließt die gesamte Objektdefinition mit einem Semikolon ab, die einzelnen Einträge werden mit Kommas abgetrennt. Innerhalb eines Eintrags gibt es weder Trennzeichen oder Gleichheitszeichen, manche Einträge wie negative Zahlen müssen mit Klammern disamibguisiert werden.

In Zeta wird der gesamte Objektkörper, der auch fehlen darf, von geschweiften Klammern umschlossen, jeder Eintrag wird mit einem Semikolon abgeschlossen und Listeneinträge werden mit Kommas getrennt. Listen können auch wie Felder durch Angabe einer Dimension definiert werden. Wenn Eigenschaften Werte zugewiesen werden, wird ein Gleichheitszeichen gesetzt, die Angaben beerbt (Klasse) und ist (Attribute) haben kein Gleichzeichen. (»For consistency perhaps there should be an equals sign before the 5, but if that were the syntax, Inform programs would be horribly full of equals signs«, Inform Designer's Manual, Third Edition, Abschnitt 3.5. Gut, Zeta-Programme sind voller Gleichheitszeichen. Und voller Kommas. Dadurch sind die Definitionen weniger kompakt, aber hoffentlich konsistenter.)

In Zeta kann die anfängliche Lage des Objekts im Objektbaum wie in Inform durch Pfeile oder durch Angabe des Mutterobjekts definiert werden. Zeta erlaubt es nicht, den Namenstext des Objekts in der Kopfzeile anzugeben.

Object -> ein_Objekt "Beispiel"
ofclass eine_Objektklasse,
   with Routine_ohne_Args [; ... ],
        Routine_mit_Args [a1 a2 x; ... ],
        Farbliste "beige" "grau" "oliv" "umbra",
        Nummern 5 1 (-2) 13,
        Platzhalter 0 0 0 0 0 0 0 0 0 0 0 0,
    has geschuettelt ~geruehrt;
 
Objekt -> ein_Objekt {
    beerbt eine_Objektklasse;
    Name = "Beispiel";
    Routine_ohne_Args = { ... }
    Routine_mit_Args(a1, a2, x) = { ... }
    Farbliste = "beige", "grau", "oliv", "umbra";
    Nummern = 5, 1, -2, 13;
    Platzhalter[12];
    ist geschüttelt, nicht gerührt;
}

Befehle und Verben. Verben werden ähnlich wie in Inform als Satzmuster angegeben. Anders als in Inform bestehen Befehle nicht nur aus einer Routine, sondern sind Objekten ähnliche, wenngleich statische, Gebilde, die mehrere Einträge haben können.

Die Satzbausteine (tokens) sind in Zeta nicht vorgegeben, sie müssen vom Benutzer definiert werden. (Die Zeta-Lib macht dies aber, so dass ein Autor sich nicht darum kümmern muss. In Zeta beschreiben Satzbausteine die Grammatik, die Sichtbarkeit und Erreichbarkeit (scope) sowie implizit ausgeführte Befehle werden durch zusätzliche Einträge im Befehl geregelt.

Die Syntax ##Befehl entfällt, Befehle sind eindeutige Konstanten wie Routinen, Objekte, Attribute und Eigenschaften. Es gibt auch kein Äquivalent zur speziellen Syntax <...> und <<...>>, dies ist in der Zeta-Lib ein Funktionsaufruf von Ausf.

    Verb 'ruehre'
        * noun                  -> Stir
        * noun 'um'             -> Stir;

    [ StirSub;
        print "Dort gibt es nichts zu rühren."
    ];

    <Stir Martini>;
    <<Stir Martini>>;
 
    Verb 'rühre'
        * dasObjekt                -> rühren;
        * dasObjekt    'um'        -> rühren;

    Befehl rühren {
        Infinitiv = "rühren";
        ungültig = nicht_erreichbar;
        Aktion = {
            "Dort gibt es nichts zu rühren."
        }
    }

    Ausf(rühren, Martini);
    stop Ausf(rühren, Martini);

Arithmetik und Operatoren. Da Zeta und Inform die Arithmetik der Z-Maschine zugrunde liegt, gibt es hier keine allzu großen Unterschiede. Für das logische Nicht verwendet Zeta das Ausrufezeichen ! oder das Schlüsselwort nicht und Inform zwei Tilden ~~. Das bitweise Nicht (Einerkomplement) ist in Zeta ein Zirkumflex ^ und in Inform eine Tilde ~.

Zeta kennt zusammengezogene Zuweisungsoperatoren wie += oder &=, bei denen die linke Seite Operand und Wertezuweisung ist. Außerdem gibt es bitweise Verschiebungsoperatoren wie in C, << und >>.

Die Notation für Hexzahlen ($CD08) und Binärzahlen ($$01100011) sowie für ZSCII-Konstanten ('x') ist in Inform und in Zeta gleich.

    a = a*2;
    if (~~b) a++;
    z = ~$$01001101;
 
    a *= 2;
    wenn (!b) a++;
    z = ^$$01001101;

Kommentare. Zeta kennt zwei Arten von Kommentaren: Zeilenkommentare, die mit einem doppelten Schrägstrich // beginnen und am Ende der Zeile aufhören und Blockkommentare, die über mehrere Zeilen gehen können und die wie in C mit /* begonnen und mit */ beendet werden. Inform kennt nur Zeilenkommentare, die mit einem Ausrufezeichen ! beginnen. (Achtung! Das Ausrufezeichen hat in Zeta eine Bedeutung, es ist der nicht-Operator.)

Assembler. Die Assemblersprache der Z-Maschine ist in Zeta nicht implementiert. Zeta kann nur Spieldateien der Versionen 5 und 8 erstellen. Die wichtigsten Opcodes werden durch Systemfunktionen abgebildet, es gibt keine Interrupt-Routinen.


Konzepte der Bibliothek

Aufbau der Spielwelt. Der Objektbaum ist eine Datenstruktur der Z-Maschine und als solche sowohl in Zeta als auch in Inform vorhanden und zur Beschreibung der Spielwelt verwendet. Hier gibt es viele Ähnlichkeiten: Räume sind Objekte, die keine Mutter haben (und die in Zeta zur Klasse Raum gehören, um sie von anderen Objekten ohne Mutter zu unterscheiden). Es gibt Behälter und Ablagen, ein Objekt kann nicht beides sein. Behälter und Personen können transparent sein oder nicht. Objekte können andere Objekte besitzen, die nicht ihre Kinder im Objektbaum sind, sondern in ihrer Eigenschaft add_to_scope bzw. Unterobjekte abgelegt sind.

Räume sind durch die Eigenschaft Ausgänge miteinander verbunden, außerdem hat jede Richtung ein zu ihr gehöriges Objekt in der Windrose (compass rose). In Zeta können Räume zusätzlich durch Objekte mit dem Attribut Verbindung verbuden sein.

Der Spieler ist ebenfalls ein Objekt, dieses Objekt wird in Zeta analog zu Inform durch die Variable Spieler beschrieben.

Ablauf eines Zuges. Wie in Inform werden wärend eines Zuges des Spielers verschiedene Eigenschaften der direkt beteiligten und der anwesenden Objekte betrachtet. In Zeta gibt es jedoch mehr Stufen.

Ausgabe von Objektnamen. Hier verwendet Zeta ein eher an T.A.G. angelehntes System: Die Eigenschaften Name und Genus des Objekts werden verwendet. Es gibt keine Objektnamen in der Kopfzeile des Objektes.

Die Trennung von Adjektiven (adj) und nachgestellten Attributen (post) entfällt, die passenden Endungen werden durch die Kurzstrings {e} und manchmal auch {n}, {en}, {s} und {es} eingefügt. Es muss auch keine Deklinationsform aus einer Tabelle angegeben werden, da die Endungen zuverlässig aus dem Genus (p, m, f oder n) und der Angabe der Kurzstrings ermittelt werden müssen. (Was Zeta nicht kann, ist selbständig Plurale zu bilden, aber das muss es auch nie.)

Um Objekte in Listen zu gruppieren, kann man Hilfsobjekte verwenden, auf die die Eigenschaften Listengruppe (für verschiedene Objekte) und Plural (für gleiche Objekte) verweisen.

Wie Artikel ausgegeben werden - als Eigenname, immer bestimmt oder als Mengenangabe (»einige«, »etwas«) - wird in Zeta mit einer zum Genus hinzugefügten Konstante beschrieben.

    Object -> Drachenleiche "Körper"
      with adj "leblos",
           post "eines Drachen",
           article definit,
           dekl 1,
           ...
       has male;
 
    Objekt -> Drachenleiche {
        Name = "leblos{e} Körper eines Drachen";
        Genus = m + immer_bestimmt;
        ...
    }

Objektvokabular. Objektvokabular wird in Adjektive und Substantive aufgeteilt angegeben, jede Vokabel kann eine zusätzliche Angabe haben, bei Substantiven ist dies der Genus. Da Objektvokabeln intern anders abgelegt werden, haben sie eine Auflösung von bis zu achtzehn Zeichen (im Gegensatz zu neun Zeichen, die von der Z-Maschine vorgeschrieben und die auch in Inform verwendet werden.)

Parser. Beim Parsen von Befehlen wird keine first match-Philosophie angewandt. In Zeta wird hier in zwei Schritten gearbeitet: Zunächst werden aufgrund der im Satz vorhandenen Objekte und Präpositionen mögliche Sätze ermittelt und bewertet. Diese Bewertung ist null, wenn wichtige Bedingungen, wie etwa das Vorhandensein einer Verbklammer, nicht gegeben sind. Kompletten Befehlen wird Vorzug vor Befehlen mit fehlenden Objekten gegeben, was (hoffentlich) zu weniger unkorrektem Verhalten beim Disambiguisieren führt.

Es werden immer alle Objekte geparst, nicht nur die sichtbaren, damit hilfreiche Fehlermeldungen (»Du siehst hier keinen grünen Pinguin.«) anstelle der bei Sätzen mit mehreren Objekten mehrdeutigen Meldung »Du kannst hier nichts dergleichen sehen.« ausgegeben werden können. Auch Stichpunkte für Gespräche oder für Nachschlagewerke werden durch Objekte beschrieben, gegebenenfalls, aber nicht notwendigerweise durch neu erzeugte Hilfobjekte.

Die Sichtbarkeit und Erreichbarkeit der Objekte wird als Bestandteil des Parsers überprüft, so dass aufgrund von logischen Fehlern im Befehl (»Du hast die Platiktüte bereits.«) die Befehlsabfolge bereits im Parser unterbrochen wird und das Spiel nicht um einen Zug weiterschreitet.

Einhänger und Lib-Objekte. Lib-Objekte sind Objekte, die - ähnlich wie die cogs und gizmos in Platypus - allgemein gültige Regeln an bestimmten Stellen in der Zeta-Lib einfügen. Lib-Objekte können aktiviert und deaktiviert werden, indem sie in das spezielle Objekt ZetaLib gelegt oder aus ihm entfernt werden. Dieses Konzept erweitert die Einhänger (entry points), da beliebig viele Lib-Objekte, die auch zu Modulen gehören können, definiert werden können.

(Der einzige Einhänger in Zeta ist die Routine Anfang, die aber noch durch die Eigenschaft init von Objekten ergänzt werden kann.)


________
Startseite --> Textadventures --> ZETA --> Unterschiede zu Inform
Übersicht
Martin Oehm

[ www.martin-oehm.de - Startseite ]
[ Textadventures ]
[ ZETA ]