Reguły tagowania

Reguły tagowania wywodzą się z tagera TaKIPI. Pozwalają one na zapis reguł w stylu „wykreśl interpretację X tokenu bieżącego, o ile zachodzi warunek Y”.

W WCCL reguły te mają nieco inną składnię niż w JOSKIPI (przede wszystkim nie ma numerków, w zamian są nazwy). Poza tym rozszerzono mechanizm reguł o dwa zasadnicze elementy:
  1. Dodano mechanizm unifikacji inspirowany Spejdem.
  2. Dodano możliwość znakowania anotacji w ograniczonym zakresie (tak więc wbrew nazwie, reguły nie muszą służyć tylko tagowaniu).

Każda reguła tagowania, podobnie jak wyrażenie funkcyjne WCCL, wartościowana jest względem bieżącej pozycji w zdaniu. Domyślnie zakłada się, że poddawany modyfikacji jest token bieżący (na pozycji 0).

Reguła tagowania określana jest przez nazwę, ciąg akcji do wykonania oraz opcjonalny warunek (jeśli warunek nie zostanie podany, to równoważne jest to warunkowi True). Reguły tagowania odpalane są na bieżącej pozycji w zdaniu. Parser powinien pozwalać na przeparsowanie ciągu reguł i udostępnienie wygodnego mechanizmu, który pozwala na odpalenie całego ciągu reguł na zdaniu w dwóch trybach:
  1. jednorazowo — iterujemy po pozycjach w zdaniu i dla każdej pozycji kolejno próbujemy wszystkich reguł oraz
  2. iteracyjnie — dopóki są zmiany. Reguła zwraca czy dokonała jakichkolwiek zmian w zdaniu.

Akcje reguł są specjalnego typu wyrażeniami, które przypominają predykaty, lecz mają (mogą mieć) skutki uboczne.

Składnia i semantyka reguł

rule(NAME, ACTIONS)
rule(NAME, COND, ACTIONS)

NAME to string określający nazwę reguły (przydatne w diagnozowaniu), COND to dowolny predykat, a ACTIONS to niepusty ciąg akcji oddzielonych przecinkami. Odpalenie reguły zaczyna się od sprawdzenia warunku. Jeśli warunek jest spełniony, akcje uruchamiane są sekwencyjnie. Każda akcja zwraca informację o tym, czy reguła dokonała jakichkolwiek zmian w zdaniu. Reguła zwraca wartość, która określa, czy którakolwiek z akcji dokonała zmian. Uwaga: to nie jest operator and; gdy warunek jest spełniony, to odpalane są wszystkie akcje — niezależnie od tego, czy pierwsza akcja dokonała zmian.

Uwaga: zwracana wartość określa, czy którakolwiek z reguł dokonała zmian w zdaniu. W skrajnym wypadku zwrócona może być wartość True, mimo że efektywnie zmian nie będzie — stać się tak może jeśli druga akcja cofa działanie pierwszej.

Przykładowa reguła zawierająca warunek:

rule("r1",
   in(class[0], {subst,xxx}),
   delete(
      equal(class[0], {xxx})
   )
)

Reguła może być prostsza, np.:

rule("r2",
   delete(
      equal(cas[0], {voc})
   )
)

Ciąg reguł to wyrażenie o następującej składni:

tag_rules(
   RULE; RULE2; ..., RULEn
)

Ciąg reguł nie może być pusty. Ciąg jest parsowany do obiektu pozwalającego na aplikację reguł na podanym zdaniu.

Akcje

Część akcji ma dwa warianty: z podaniem pozycji oraz bez. Warianty bez podawania pozycji są równoznaczne z podaniem pozycji 0.

Akcje badające leksem po leksemie

Akcje te działają w specyficzny sposób: wyjmujemy wszystkie leksemy z tokenu na podanej pozycji, po czym każdorazowo wkładamy z powrotem po jednym leksemie i sprawdzamy czy spełniony jest warunek (zależny od danego operatora). Otrzymujemy w ten sposób dwie grupy leksemów — te, które samodzielnie spełniają predykat (dokładniej: gdy jednoleksemowy token spełnia predykat) oraz pozostałe. Wynikiem działania operatora jest wstawienie nowego zbioru leksemów na miejsce starego. Nowy zbiór ustalany jest na podstawie wspomnianych grup oraz specyfiki konkretnego operatora.

delete(pos, pred), delete(pred) — pozostawia jedynie leksemy niespełniające predykatu, no chyba że wszystkie spełniają, to nie wprowadza żadnych zmian

select(pos, pred), select(pred) — pozostawia jedynie leksemy spełniające predykat, no chyba że żaden nie spełnia, to nie wprowadza żadnych zmian

relabel(pos, tset_op, pred), relabel(tset_op, pred) — leksemy niespełniające predykatu pozostają niezmienione, natomiast spełniające poddawane są korekcie tagów; korekta tagów polega na wstawieniu podanych w zbiorze uzyskanym z tset_op wartości w odpowiednie miejsce tagu, czyszcząc poprzednie wartości ustawianych atrybutów, łącznie z klasą gramatyczną (jeśli została podana)

Uwaga: akcji relabel należy używać ostrożnie, gdyż może ona prowadzić do powstania tagów niezgodnych z tagsetem. Dalszych konsekwencji takiego stanu rzeczy nie da się określić na etapie specyfikacji języka (zależy to od implementacji).

Unifikacja zakresu

Unifikacja jest próbą wymuszenia uzgodnienia na podanym zakresie. W tym wypadku wymuszamy „bardzo słabe uzgodnienie”, tj. odpowiednik słabego uzgodnienia lecz bez szczególnego traktowania krańców zakresu (wszystkie tokeny z zakresu traktowane są jak środek zakresu słabego uzgodnienia). Wymuszenie polega na zostawieniu jedynie tych leksemów, które nie naruszają uzgodnienia. Zwracamy True tylko wtedy, gdy usuniemy przynajmniej jeden leksem.

unify(pos1, pos2, agr_attrs)

Operator unify może być szczególnie przydatny, jeśli przynajmniej jedna z pozycji będzie wskazywana przez zmienną, której wartością użytkownik może sterować.

Akcje zmieniające anotacje

Uwaga: w poniższych operacjach podane zakresy są najpierw przycinane do granic zdania.

mark(pos1, pos2, phrase) — w kanale o nazwie phrase znakuje anotację zaczynającą się od pos1, kończącą się na pos2; nardzędnik ustawiany jest na pos1.

mark(pos1, pos2, head_pos, phrase) — w kanale o nazwie phrase znakuje anotację zaczynającą się od pos1, kończącą się na pos2; nadrzędnik ustawiany jest na head_pos. Jeśli przekazany head_pos jest poza zakresem, powinno zgłosić wyjątek.

unmark(pos, phrase) — w kanale o nazwie phrase usuwa anotację, która przechodzi przez pozycję pos. Jeśli przez tę pozycję nie przechodzi żadna anotacja, nie dzieje się nic.

Uwaga: jeśli przez podany zakres przebiega jakakolwiek anotacja, żadna akcja nie jest wykonywana.