Eine erste Morphologie in JSLIM
Abstract
Ziel dieser Dokumentation ist es, ein Beispielprojekt für die morphologische Analyse des Deutschen, genannt “german1”, in JSLIM zu implementieren. In diesem Projekt wird die Flexion der Verben “lernen” und “essen”, der Substantive “Frau”, “Mann” und “Buch” sowie der Adjektive “klein” und “groß” behandelt. Einer Erklärung der einzelnen für JSLIM notwendigen Dateien folgt jeweils die praktische Umsetzung für das Projekt. Hierbei sollen sowohl die Komponenten der Allomorphie als auch der Kombinatorik berücksichtigt werden. Das erläuterte Projekt befindet sich weiterhin auf der beigelegten CD-ROM. Eine ausführliche README-Datei gibt alle nötigen Anweisungen zu Start und Ausführung von JSLIM.
Erste Schritte
Zu Beginn des Projektes ist es wichtig, sich den Aufbau einer JSLIM-Grammatik zu vergegenwärtigen. Diese besteht aus Dateien mit den folgenden Endungen:
- .pro: Projektdatei
- .ops: Operationsdatei
- .att: Attributdatei
- .lex: Lexikondatei mit Grundformen
- .all: generiertes Allolexikon
- .var: Variablendatei
- .rul: Regeldatei
- .tbl: Tabledatei
Die Dateien werden im Folgenden näher betrachtet und erläutert.
Allgemeine Dateien
Die Projektdatei
Die Projektdatei listet alle Dateien auf, die für das zu implementierende Projekt benötigt werden. Für das Projekt “german1” sieht die Projektdatei folgendermaßen aus:
# Projektdatei
# author: cnweber
enc: UTF-8
att: german1.att
ops: german1.ops
tbl: ../allo/allo.tbl
../morph/german1-verb-table.tbl
../morph/german1-noun-table.tbl
../morph/german1-adj-table.tbl
lamorph
rul: ../morph/combi.rul
var: ../morph/german1.var
lex: ../allo/allo.all
Die Datei beginnt mit zwei Kommentaren, die Informationszwecken dienen. Kommentare werden in JSLIM mit # eingefügt und gelten bis zum Zeilenende. Mehrzeilige Blöcke werden mit #* eingeleitet und mit *# beendet. Die erste Zeile informiert über die Art der Datei, die zweite über den Autor.
Im Anschluss findet man die Information, welche Kodierung verwendet wird. Danach folgt eine Auflistung aller verwendeten Dateien. Begonnen wird jeweils mit der Dateiendung gefolgt von einem Doppelpunkt (diese Abkürzungen sind fest definiert und dürfen nicht anders deklariert werden. Möglich ist jedoch eine alternative Deklaration der Dateiendung einer Datei) und dem Namen der Datei. So definiert ops: german1.ops, dass die Operationsdatei den Namen german1.ops hat und sich im selben Verzeichnis wie die Projektdatei befindet. Bestandteile einer Grammatik müssen sich nicht zwangsläufig im selben Verzeichnis befinden, jedoch muss die Pfadangabe innerhalb der Projektdatei immer richtig gewählt werden. Bei der Pfadangabe geht man immer von dem Verzeichnis, in dem sich die Projektdatei befindet, aus. Eine Angabe der Art ops: Operations/german.ops würde darauf hinweisen, dass sich die Datei german.ops in einem unterliegenden Verzeichnis Operations befindet. Eine Angabe wie ops: ../german.ops würde bedeuten, dass die Operationsdatei in dem darüberliegenden Verzeichnis liegt. Bei einer falschen Pfadangabe startet das Projekt nicht.
Die Anweisung lamorph gibt an, dass die darauf folgenden Dateien zur Morphologiekomponente des Projektes gehören. Die Syntaxkomponente, die in einem anderen Teil der Dokumentation erläutert ist, wird mit lahear angegeben und kann wiederum einzelne Dateien speziell für die Syntax beinhalten. Es können, wie am Beispiel der Tabledateien zu sehen ist, unter einem Eintrag auch mehrere einzelne Dateien aufgelistet werden.
Die Datei allo.all wurde mit dem Allomorphiegenerator erzeugt und wird in Abschnitt weiter unten erläutert. Weiterhin haben Whitespaces wie Leerzeichen oder Tabulatoren keine spezielle Bedeutung in JSLIM und können willkürlich gewählt werden.
Die Operationsdatei
Nach der Erstellung der Projektdatei als Basis für alle weiteren Dateien werden diese im Folgenden behandelt und erläutert. Begonnen wird mit der Operationsdatei. In dieser sind alle Operationen aufgelistet, die in der Regeldatei verwendet werden. Die Operationsdatei des Projektes “german1” enthält folgenden Eintrag:
package:
de.uni_erlangen.linguistik.lag.jslim.lag.operations
setref: SetRefOperation
cancel: CancelOperation
acopy: ACopyOperation
ecopy: ECopyOperation
sappend: StringAppendOperation
table: TableLookupOperation
copy: CopyOperation
set: SetOperation
put: PutOperation
Zu Beginn wird das Package angegeben, aus dem die Operationen geladen werden. Dieses muss nicht unbedingt wie oben dargestellt angegeben werden. Stattdessen kann der Pfad auch einzeln vor jede Operation geschrieben werden. Ohne die Angabe der Pfade würden die Operationen jedoch nicht gefunden werden. Danach folgen die Operationen. In der ersten Spalte stehen die Namen der Operationen, mit denen sie in der Regeldatei verwendet werden. Der Name ist hierbei fast willkürlich. Man sollte sich jedoch an bewährte Konventionen halten, z.B. dass die CancelOperation auch mit cancel deklariert wird. Verboten sind Schlüsselworte wie ST_S oder ST_F, die in anderen Dateien Anwendung finden. In der zweiten Spalte die Namen der Java-Klassen, in denen die Operationen implementiert sind. Operationsnamen werden konventionell klein geschrieben. Ein Überblick über sämtliche zur Verfügung stehenden Operationen ist im Anhang zu finden.
Die Attributdatei
In der Attributdatei werden die Datentypen von allen in der Grammatik verwendeten Attributen deklariert. Mögliche Datentypen sind: string (Zeichenkette), list (Liste), int (Zahl), table (Tabelle) und map (Hashtabelle). Die Attributdatei des Projektes “german1” findet sich im Folgenden:
string sur
core
list cat
sem
table allo
flx
syn
Für das Projekt werden nur drei der fünf Datentypen benötigt: “string”, “table” und “list”. Die deklarierten Attribute sind:
- sur: Oberfläche
- core: Grundform
- cat: Kategorie
- sem: Semantik
- allo: Allomorphieklasse
- flx: Flexionsklasse
- syn: Markierung für die Syntaxkomponente
Die Bedeutung der einzelnen Attribute und ihre Anwendung im Projekt wird in den nächsten Kapiteln zur Lexikon- und Regeldatei ausführlich beschrieben. Wichtig ist zu beachten, dass die Attribute sur und core als Zeichenketten definiert wurden, die Attribute cat und sem hingegen als Listen. Die Attribute allo, flx und syn sind als Tabellen definiert, da mit ihnen ein Abgleich mit einer Tabledatei gemacht wird. Die Vergabe der Datentypen ist darin begründet, dass die Oberflächen und Grundformen von Proplets üblicherweise durch Zeichenketten dargestellt werden. Da Informationen über Kategorie und Semantik oftmals aus mehreren Werten bestehen, ist es von Vorteil, sie als Listen zu definieren. Die Reihenfolge, in der die Attribute angegeben werden, bestimmt weiterhin die Ausgabereihenfolge in JSLIM. In diesem Falle wird in den Analyseausgaben in JSLIM als erstes Attribut sur gefolgt von core, cat, sem, allo, flx und syn ausgegeben.
Allomorphie
Nachdem mit der Projekt-, Operations- und Attributdatei allgemeine Einstellungen für die Grammatik vorgenommen wurden, widmet sich dieser Teil der Dokumentation der Allomorphgenerierung. Hierfür werden zusätzlich zu den allgemeinen Dateien ein Grundformenlexikon und eine Tabledatei benötigt. Dem Projekt liegt ein Shell-Skript zum Starten der Allomorphie bei. Nähere Erläuterungen finden sich in der README-Datei auf der beiliegenden CD-ROM.
Das Grundformenlexikon
Im Grundformenlexikon (allo.lex) werden alle Grundformen der Lexikoneinträge mittels Templates angegeben. Ein Beispieleintrag für das Verb “lernen” ist in untenstehender Abbildung zu sehen.
!template[ allo: A_lernen
flx: C_lernen
syn: T_1
]
!+sur core:
lernen
Durch !template werden alle in eckigen Klammern stehenden Attribut-Werte-Paare deklariert, die für alle folgenden Lexikoneinträge gelten sollen. Der Vorteil dieser Notation besteht darin, dass Lexikoneinträge, die eine äquivalente Attribut-Werte-Struktur haben, zu Klassen zusammengeführt werden können. Ein Lexikoneintrag zu einem Template wird entweder mit der Anweisung !+<Attribute>: <Werte> oder ![<Attribute>] <Werte> hinzugefügt. So würde mit einem Eintrag von “schenken” am Ende der in oben dargestellter Abbildung dargestellten Datei ein weiterer Eintrag hinzugefügt, der die gleichen Werte für die Attribute allo, flx und syn wie “lernen” besitzt. Die beiden Einträge würden sich nur in den Attributen sur und core unterscheiden. Eine alternative Schreibweise zu einem Template wäre folgende:
!template[ allo: A_Buch
flx: C_Buch
syn: T_2
]
![sur, core]
BUch Buch
TUch Tuch
Der Vorteil dieser Schreibweise besteht darin, dass sich die Attribute sur und core unterscheiden dürfen. Das groß geschriebene “U” im sur-Wert von “Buch” bedeutet, dass hier mittels Alloregeln eine Umlautung stattfinden wird.
Die Tabledatei der Allomorphie
In der Tabledatei (allo.tbl) der Allomorphie werden Alloregeln mittels regulärer Ausdrücke ausgeführt. Eine Alloregel nimmt ein Lemma des Grundformenlexikons als Eingabe und leitet daraus ein oder mehrere Allomorphe ab. Untenstehende Abbildung zeigt Alloregeln für die Lexikoneinträge “essen” und “Buch”.
table A_essen: [sur] => [sur,cat,sem]
/(ess)en/ => /$1/ (stem) (präs) ;
=> /iss/ (v) (imp sg) ;
=> /äß/ (stem) (k2) ;
=> /aß/ (s13' v) (i) .
table A_Buch: [sur] => [sur,cat,sem]
/(.+)U(.+)/ => /$1u$2/ (n-g) (n sg) ;
=> /$1ü$2/ (stem)(n pl) .
Die Tabellen matchen auf die Lexikoneinträge, in deren allo-Attribut jeweils die Werte “A_essen” und “A_Buch” stehen. Der Abgleich findet durch die Angabe von [sur] mit dem sur-Attribut statt, d.h. der definierte reguläre Ausdruck (eingegrenzt durch “/.../”) muss auf den Wert der sur-Attribute im Grundformenlexikon passen. Im Beispiel “/(ess)en/” wird durch die Gruppierung von “(ess)” dieser Teil des regulären Ausdrucks gemerkt und im ersten Allomorph durch “$1” wiederverwendet. Somit wird das Allomorph “ess” gebildet. Den Allomorphen werden weiterhin ein cat- und sem-Attribut zugewiesen. Zu beachten ist, dass Listen wie in cat und sem durch runde Klammern eingegrenzt werden. Die Oberfläche gibt das Allomorph ohne angehängte Flexionsendungen oder Suffixe an. Im cat-Attribut wird durch stem das Allomorph als Wortstamm deklariert. Andere Allomorphe wie “aß” hingegen sind bereits vollständig und werden mit Informationen zu Person (“s13'”) und Tempus (“i”) markiert. Im sem-Attribut werden grammatische Informationen bezüglich Tempus und Modus angegeben. Die Kombination des Allomorphs mit den Flexionsendungen wird in den Tabledateien der Kombinatorik vorgenommen. In den anderen Allomorphen wird “/(ess)en/” durch “iss” (“er iss | t”), “äß” (“er äß | e”) und “aß” (“wir aß | en”) ersetzt, sodass insgesamt vier Allomorphe generiert werden. Für “Buch” werden zwei Allomorphe benötigt, nämlich “Buch” und “Büch”. Im regulären Ausdruck “/(.+)U(.+)/” wird verlangt, dass innerhalb des Wortes ein “U” vorkommen muss. Für “Buch” werden die gemerkten regulären Ausdrücke durch “$1” und “$2” übernommen und das “U” zu “u” umgewandelt (“Buch”). Im zweiten Allomorph wird das “U” durch “ü” ersetzt (“Büch”). Der Befehl zum Start der Allomorphiekomponente sieht folgendermaßen aus:
“./allo.sh -I allo.lex -A ../common/german1.att -V allo.tbl”
Das Kommando startet die Allomorphiekomponente über ein Shell-Skript mit dem Parameter -I (steht für Input), gefolgt von dem Namen der Lexikondatei, die als Eingabe eingelesen werden soll (allo.lex). Der zweite Parameter -A verlangt die Attributdatei (in diesem Falle german1.att). Der dritte Parameter -V verlangt die Tabledatei(en). Es können auch mehrere Lexikon- und Tabledateien angegeben werden, die mit Doppelpunkt getrennt werden müssen (Beispiel: “-V allo1.tbl:allo2.tbl”). Mit dem optionalen Parameter -O kann der Grammatikschreiber seine Ausgabedatei selbst deklarieren. Standardmäßig wird eine Datei allo.all im selben Verzeichnis erzeugt, in dem auch das Allolexikon gespeichert ist. Der gesamte Prozess läuft vor der Laufzeit ab, sodass JSLIM nicht extra gestartet werden muss. Die durch die erläuterten Alloregeln generierte Ausgabedatei kann in der folgenden Abbildung an den Beispielen “lernen”, “Buch” und “Tuch” betrachtet werden.
!template[cat: (v), sem: (imp sg), allo: A_lernen,
flx: C_lernen, syn: T_1]
![sur, core]
lern lernen
!template[cat: (n-g), sem: (n sg), allo: A_Buch,
flx: C_Buch, syn: T_2]
![sur, core]
Buch Buch
Tuch Tuch
!template[cat: (stem), sem: (n pl), allo: A_Buch,
flx: C_Buch, syn: T_2]
![sur, core]
Büch Buch
Tüch Tuch
Das generierte Allolexikon kann nun in die Projektdatei eingebunden werden.
Kombinatorik
In der Kombinatorik werden Wortformanfänge mit nächsten Allomorphen verknüpft und daraus ein neuer Wortformanfang generiert. Hierfür werden weitere Dateien benötigt, die im Folgenden erklärt werden sollen. Dem Projekt liegt ein Shell-Skript zum Starten der Morphologie-Komponente von JSLIM bei (jslim.sh).
Die Variablendatei
Die Variablendatei german1.var enthält allgemeine Variablen, die im Projekt verwendete Kategoriewerte aufnehmen (z.B. “s1'”, “s13'”). Die Variablen werden über eine definitionsbasierte Kongruenz deklariert. Hierbei werden den Variablen Werte gegeben, die sie annehmen dürfen. Die Schreibweise ist in folgender Abbildung zu sehen:
string STS <- {n-g m-g f adj s13' v stem}
string STF <- {n-g m-g f adj s13' v mg md p-d
pd ng nd p s1' p2' p13' s2' p2'
part s23' sp2' s3p2' e er em en es}
Zuerst wird der Datentyp der Variable deklariert. Danach folgt, konventionell mit einem Großbuchstaben beginnend, der Name der Variable. Die Zeichenfolge <- bedeutet, dass die folgenden Werte von der Variablen aufgenommen werden. In den geschweiften Klammern stehen die Werte der Variablen, getrennt durch Kommata. Wird eine Variable ohne Werte definiert, kann sie für irgendeinen String, eine Liste oder Zahl, je nach Datentyp, stehen.
Die Möglichkeit, Variablen zueinander in Beziehung zu setzen, wird über sogenannte constraints gehandhabt. Diese werden ausführlich in der Dokumentation zur Syntax behandelt.
Die Tabledatei der Kombinatorik
Genau genommen besteht die Tabledatei aus drei Dateien für die jeweiligen zu implementierenden Wortarten: german1-verb-table.tbl, german1-adj-table.tbl, german1-noun-table.tbl. Diese sind alle in der Projektdatei eingebunden. Die jeweiligen Dateien beinhalten, wie die Dateinamen bereits andeuten, Kombinationstabellen für Verben, Adjektive und Nomen. Diese werden mit dem speziellen Schlüsselwort table instantiiert. Sie finden Anwendung über eine Operation in der Regeldatei (siehe unten). Darauf folgend werden alle möglichen Kombinationsmöglichkeiten von Wortformanfängen mit den nächsten Allomorphen, in diesem Falle den Flexionsendungen, aufgelistet. Kombinationstabellen des Substantivs “Buch” und des Verbs “lernen” (ohne Partizip Perfekt) sind in nachfolgender Abbildung zu sehen.
table C_Buch: [cat,sem][sur] => [cat,sem]
(n-g) (n sg) es => (ng) (n sg) ;
s => (ng) (n sg) ;
e => (nd) (n sg) .
(stem)(n pl) er => (p-d) (n pl) .
(p-d)(n pl) n => (pd) (n pl) .
table C_lernen: [cat,sem] [sur] => [cat,sem]
(v)(imp sg) e => (<s1' s13'> v)(<präs k1>) ;
st => (s2' v) (präs) ;
te => (s13' v)(i_k2) ;
t => <(s3p2' v)(v)><(präs)(imp pl)> ;
en => (p13' v)(präs) ;
end => (part)(präs) .
(s13' v)(i_k2) st => (s2' v)(i_k2) ;
t => (p2' v)(i_k2) ;
n => (p13' v)(i_k2) .
(<s1' s13'> v)(<präs k1>) st => (s2' v) (k1) ;
n => (p13' v)(k1) ;
t => (p2' v)(k1) .
Nach der Angabe der Art der Variable (“table”) wird der Kombinationstabelle ein Name gegeben (hier: C_Buch beziehungsweise C_lernen). Der Name ist insofern wichtig, da alle Lexikoneinträge mit “C_Buch” und “C_lernen” im flx-Attribut diese Kombinationstabelle verwenden. Lexikoneinträge mit anderen flx-Werten können nicht darauf zugreifen. Kombinationstabellen haben folgende Eigenschaften:
- Sie beruhen auf einem Abgleichmechanismus, der vom Benutzer definiert ist. Die Deklaration “[cat,sem] [sur] => [cat,sem]” bedeutet, dass in diesem Fall die Werte des cat- und sem-Attributes des Wortformanfangs und der Wert des sur-Attributes des nächsten Allomorphs überprüft werden. D.h. “(v)(imp sg)” matcht auf das Proplet von “lern”, da in seinem cat- und sem-Attribut jeweils die gleichen Werte stehen und weiterhin “C_lernen” im flx-Attribut steht. Als Resultat können weiterhin neue Werte im cat- und sem-Attribut des neuen Wortformanfangs geschrieben werden. Wird als Resultat für ein Attribut kein Wert angegeben, wird der des Wortanfangs übernommen. Zwei Beispiele sollen dies verdeutlichen:
Beispiel 1:
[cat, sem] [sur] => [cat, sem]
(<s1' s13'> v)(<präs k1>) st => (s2' v)(k1);
Ergebnis:
[sur : lern | e | st ]
[verb: lernen ]
[allo: A_lernen ]
[cat : (s2' v) ]
[sem : (k1) ]
[flx : C_lernen ]
Beispiel 2:
[cat, sem] [sur] => [cat, sem]
(s13' v)(i) t => (sp2' v) ;
Ergebnis:
[sur : aß | t ]
[core: essen ]
[allo: A_essen ]
[cat : (sp2' v) ]
[sem : (i) ]
[flx : C_essen ]
In Beispiel 1 werden das cat- und sem-Attribut des neuen Wortformanfangs eigens definiert. Nachdem “e” und “st” an “lern” angehängt werden, soll die Kategorie “(< s1' s13'> v)(< präs k1>)” zur neuen Kategorie “(s2' v) (k1)” werden.
In Beispiel 2 bleibt das sem-Attribut im Ergebnis der Transition unverändert und es wird somit automatisch in die Zielkategorie geschrieben. Das cat-Attribut verändert sich hingegen von “(s13')” zu “(sp2')”. - Der Wortformanfang ist solange gültig, bis durch einen Punkt eine Kombination beendet wird. Kombinationen desselben Wortformanfangs mit unterschiedlichen nächsten Allomorphen werden mit Strichpunkt voneinander getrennt. Der Wortformanfang “lern” ist hier solange gültig, bis durch den Punkt nach Kombination mit der Flexionsendung “end” alle möglichen Kombinationsmöglichkeiten abgeschlossen sind. Danach kann ein neuer gleichrangiger Wortformanfang gewählt werden. Voraussetzung ist, dass die linken Transitionsseiten disjunkt sind, das heißt sie dürfen nicht dieselben Werte besitzen.
(v)(imp sg) e => (<s1' s13'> v)(<präs k1>) ;
st => (s2' v) (präs) ;
...
end => (part)(präs) .
(s13' v)(i_k2) st => (s2' v)(i_k2) ;
t => (p2' v)(i_k2) ;
n => (p13' v)(i_k2) .
...
- Das mehrfache Anhängen von nächsten Allomorphen ist möglich, wie obenstehende Abbildung zeigt. Als Beispiel kann “lern | te | n” betrachtet werden. Dieses wird durch “(v)(imp sg) te => (s13' v)(i_k2)” zunächst als “lern | te” ausgegeben. Danach wird durch eine weitere Kombination von “(s13' v)(i_k2) n => (p13' v)(i_k2)” “lernte” zu einem wiederum neuen Wortformanfang gemacht und mit der Flexionsendung “n” verbunden, aus der sich wieder neue Resultatskategorien ableiten.
- Ein weiteres Feature sind die sogenannten Multikats. Sie haben den Vorteil, dass Proplets mit identischen Oberflächen, jedoch unterschiedlichen Kategoriewerten, in einem Proplet gespeichert werden können. Ein Beispiel für ein Multikat ist die Kombination “(v)(imp sg) e => (<s1' s13'> v)(<präs k1>)”. Multikats sind durch spitze Klammern dargestellt. Die Wortform “lerne” kann sowohl 1. Person Singular Indikativ Präsens als auch 1. und 3. Person Konjunktiv 1 von “lernen” sein. Somit sind sowohl das cat- als auch das sem-Attribut unterschiedlich. Gelesen wird in der Weise, dass der erste Wert innerhalb des Multikats zum ersten Wert des Multikats im nächsten Attribut passt. Die Reihenfolge gilt für alle weiteren Werte. Bei nur einem unterschiedlichen Wert eines Attributs kann dieser zusammengefasst werden. So bedeutet beispielsweise die Notation “(s13' v)(i_k2) st => (s2' v)(i_k2)” 2. Person Singular Indikativ Imperfekt und Konjunktiv 2.
- Kombinationstabellen können vererbt werden. Vor allem bei Verben besteht häufig die Möglichkeit, dass einige Zeitformen unterschiedlicher Klassen gleich sind, andere jedoch nicht. Als Beispiel kann der Vergleich von “lernen” und “gehen” genommen werden. Beide haben im Indikativ Präsens jeweils die Eigenschaft, dass der reguläre Wortstamm mit denselben Flexionsendungen kombiniert wird. Für diese Zeitform ließe sich eine eigene Kombinationstabelle schreiben. Im Gegensatz zu “lernen” wird bei “gehen” jedoch ein anderer Wortstamm für das Indikativ Imperfekt verwendet, nämlich “ging”. Das Prinzip der Vererbung ist in nachfolgender Abbildung dargestellt.
table präs (es folgen die Kombinationen für das Präsens)
table lernen_imp (es folgen die Kombinationen
für das Imperfekt von lernen)
table gehen_imp (es folgen die Kombinationen
für das Imperfekt von gehen)
table C_lernen: table_präs, table_lernen_imp
table C_gehen: table_präs, table_gehen_imp
Der Vorteil der Vererbung liegt darin, dass “präs” sowohl von “C_lernen” als auch von “C_gehen” übernommen werden kann. Ohne eine Implementierung der Vererbung müssten die Kombinationen für das Präsens in beiden Kombinationstabellen doppelt ausgeführt werden, obwohl es sich jeweils um denselben Quelltext handelt. In diesem Beispiel werden somit Untertabellen erstellt und am Ende von einer Haupttabelle aufgenommen. Bei größeren Projekten wird dadurch die Einsparung an Quelltext beträchtlich. Unterhalb der Tabellen, welche Untertabellen aufgenommen haben, können noch einmal Transitionen geschrieben werden.
Die Regeldatei
Die Regeldatei beinhaltet die Regeln mit den dazugehörigen Regelpaketen und Operationen, mit denen die Kombinatorik von Allomorphen implementiert werden kann. Zuerst muss ein sogenannter Start-State definiert werden:
ST_S = {([cat: (STS _)] {STEM+FLX})}
Die Definition des Start State beginnt mit dem Schlüsselwort ST_S gefolgt von einem oder mehreren Tupeln aus Muster und Regelpaket. Ein Muster besteht aus der Angabe eines oder mehrerer Attribute mit ihren dazugehörigen Werten. Die Werte können entweder aus Zeichen, Listen, Hashtabellen oder Zahlen bestehen oder aus Variablen, die in der Variablendatei definiert werden. In diesem Falle wird das Muster nur durch die Variable STS und die Platzhaltervariable _ dargestellt. Erstere ist in der Variablendatei (siehe oben) definiert, letztere steht für null bis beliebige weitere Werte des cat-Attributs. Ein Regelpaket ist eine Menge von Regeln, die nach einer Regel ausgeführt werden können und wird durch geschweifte Klammern instantiiert. Das Regelpaket {STEM+FLX} gibt an, dass diese Kombinationsregel von Wortstamm und Flexionsendung zu Beginn einer Ableitung angewendet werden darf. Da in diesem Projekt nur die Flexion von Verben, Substantiven und Adjektiven dargestellt wird, muss z.B. keine Regel für die Kombination von Präfixen und Wortstämmen berücksichtigt werden, die auch am Anfang eines Wortes vorkommen kann.
Das Schema einer Verknüpfungsregel in JSLIM ist
[Name Regelpaket Kategoriemuster1 Kategoriemuster2 Operationen].
Dies soll an der Regel “STEM+FLX” veranschaulicht werden:
STEM+FLX {STEM+FLX}
[cat: (_), flx: _]
[cat: (flx)]
table(SS.flx SS nw)
sappend(SS.sur " | " nw.sur)
Der Regel wird der Name “STEM+FLX” gegeben. Wie bei den Variablen muss ein Regelname mit Großbuchstaben beginnen. In geschweiften Klammern folgen die Regelpakete, die der Regel folgen können. In diesem Fall wird die Regel rekursiv angewendet. Dies ist durch das mögliche mehrfache Anhängen von Flexionsendungen in den Kombinationstabellen begründet (Beispiel “lern | te | n”). Danach folgt das erste Kategoriemuster. Dieses gibt an, dass der Wortanfang beliebige Werte im cat- und im flx-Attribut haben kann. Somit scheiden z.B. die Flexionsendungen als Wortanfang dieser Regel aus, da sie kein flx-Attribut besitzen. Das zweite Kategoriemuster definiert, dass das folgende nächste Allomorph einen Wert “flx” im cat-Attribut haben muss, was nur auf Flexionsendungen zutrifft. In größeren Projekten, die z.B. auch Derivation und Komposition behandeln, müssen explizitere Einschränkungen vorgenommen werden, indem Variablen mit Werten anstatt Platzhaltervariablen definiert werden. Matchen die beiden Kategoriemuster, werden die beiden Operationen table und sappend angewendet. Die Operation “table” macht einen “table”-Lookup, so dass alle Produktionen innerhalb der Flexionstabellen realisiert werden können. Die Operation “sappend” verknüpft die Oberflächen des Wortanfangs mit der des nächsten Allomorphs. In diesem Falle werden die beiden Oberflächen mit | getrennt, jedoch sind auch andere Zeichen zur Trennung möglich.
Im Final State wird angegeben, welche Kategoriemuster und Regelpakete am Ende eines Wortes vorkommen dürfen:
ST_F = {([cat: (STF _)] rp_STEM+FLX)}
Initiiert durch ST_F, wird der Wert des cat-Attributs mit der Variable STF, gefolgt von einer Platzhaltervariable angegeben. Die Variable “STF” dient in diesem Falle der Restringierung der zugelassenen Endzustände, da nur Werte akzeptiert werden, die in der Variable definiert sind. Somit scheiden z.B. Flexionsendungen oder reine Wortstämme aus. Würde man keine Restringierung vornehmen, wäre das Projekt übergeneriert. Durch rp_STEM+FLX wird festgelegt, dass das Ergebnis nach Anwendung der Regel “STEM+FLX” eine vollständige Wortform ergibt und somit ein Endzustand ist.
Je größer ein Projekt ist, umso mehr Regeln müssen angewendet werden. In der Kombinatorik wären beispielsweise noch folgende Regeln notwendig:
- PRÄFIX+WORTSTAMM (“Aus | gang”)
- PRÄFIX+PRÄFIX (“ein | ver | leiben”)
- WORTSTAMM+SUFFIX (“Werb | ung”)
- SUBSTANTIV+SUBSTANTIV (“Spiel | platz”)
- ...
Guter Programmierstil ist, die Regeln nach ihrer Funktionsweise zu benennen. Möglich wäre auch eine Benennung der Regeln nach dem Schema A, B, C,..., jedoch haben Regelnamen wie STEM+FLX eine deutlich höhere semantische Signifikanz und erleichtern das Schreiben einer Grammatik.
Testlisten
Eine wichtige und sinnvolle Überprüfung des Projektes wird durch Testlisten gemacht. Hier werden in einer positiven Testliste die grammatisch korrekten Paradigmen der Lexikoneinträge, die in ein Projekt eingebunden werden, in einer Datei mit einem Wort pro Zeile eingetragen. Die Option -test, gefolgt von dem Namen der Testdatei (z.B. -test ../tests/german1.tst), erlaubt es innerhalb des JSLIM-Systems, alle Einträge der Testdatei morphologisch zu parsen. Somit kann überprüft werden, ob alle Paradigmen richtig implementiert wurden. Das Gegenteil der positiven Testliste, die negative Testliste, wird zum Finden von Übergenerierungen gebraucht. In die negative Testliste werden fehlerhafte Wortformen eingetragen, beispielsweise “lerntes” und “lerntst” für den Lexikoneintrag “lernen” oder “Büchs” und “Buchern” für den Lexikoneintrag “Buch”. Werden alle diese Wortformen nicht akzeptiert, ist dies ein guter Anhaltspunkt dafür, dass das Projekt kaum oder gar nicht übergeneriert ist. Werden jedoch nicht wohlgeformte Wortformen erkannt, so dient die negative Testliste als Basis dafür, das Projekt sukzessive durch Finden und Ausbessern der Fehler zu optimieren. Es werden bei Angabe einer Testdatei automatisch drei Dateien generiert, die denselben Namen der Testdatei, gefolgt von der Endung err (Exceptions), lst (Kurzansicht der Ausgabe) und out (Propletansicht der Ausgabe), tragen.