Język JOSKIPI definiował różne składnie w zależności od konkretnych zastosowań: plik definiujący wzorce tagera miał inną składnię, inną składnię miały reguły tagowania, a jeszcze inną plik zawierający jeden predykat. Składnie te nie były nigdzie wprost określone, a wszystkie te pliki nazywane były mimo to plikami JOSKIPI.

W WCCL-u definiujemy ogólną składnię pliku WCCL. Pozwoli to na używanie pliku o tej samej strukturze w większości zastosowań. Co więcej, pozwala to na odwołanie się do zewnętrznych zasobów, które zostaną załadowane raz, po czym mogą z nich korzystać wszystkie wyrażenia zawarte w pliku. Składnia WCCL pozwala na zapis:
  1. nazwanych operatorów zwracających wynik podanego typu,
  2. nazwanych operatorów zwracających wynik dowolnego typu,
  3. reguł tagowania,
  4. reguł dopasowania,
  5. importu leksykonów (póki co jedyna planowana forma zasobu zewnętrznego).

Uwaga na temat implementacji: parser powinien zwrócić uniwersalną strukturę odpowiadającą przeparsowanemu plikowi. Struktura taka powinna pozwalać na wygodny dostęp do wszystkich składników pliku, pozwolić też na iterację po wszystkich wyrażeniach określonego typu (a przynajmniej wypisać uporządkowaną listę nazw wyrażeń danego typu, do których to nazw można się potem odwołać, by pobrać właściwe przeparsowane wyrażenia). W niektórych sytuacjach dużo wygodniej będzie pozostać przy parsowaniu pojedynczego wyrażenia — np. jeśli plik ma zawierać pojedynczy predykat. Dlatego też API powinno pozwalać w dalszym ciągu na parsowanie pojedynczych wyrażeń (na poziomie fasady parsera, tzn. tej klasy cośtamparser dla użytkownika) — nie powinna to jednak być opcja domyślna. Wszystkie utile powinny też korzystać z parsowania całego pliku, ewentualnie w niektórych sytuacjach mieć dodatkowe opcje (np. ma to sens w przypadku wcclrun — gdzie można podać ciąg operatorów jako argumenty wywołania).

Składnia

Plik WCCL ma ogólną składnię:

WCCL_FILE ::= IMPORT* ELEMENT
IMPORT ::= import(STRING, STRING) // np. import("names.lex", "names")
ELEMENT ::= OPS | TAGRULESEQ | MATCHRULESEQ
TAGRULESEQ ::= [[SpecyfikacjaRegułTagowania#Składnia-i-semantyka-reguł|ciąg reguł tagowania, czyli tag_rules(…)]]
MATCHRULESEQ ::= [[SpecyfikacjaRegułDopasowania#Składnia-i-semantyka-reguł-dopasowania|ciąg reguł dopasowania, czyli match_rules(…)]]
OPS ::= UNTYPED_OPS | t_OPS | s_OPS | p_OPS | b_OPS
UNTYPED_OPS ::= @STRING (ANY_FUNC_OP+) // np. @"std" (cas[-1]; cas[0]; cas[1]; base[0])
STR_OPS ::= @s:STRING (SEQ_of_STR_FUNC_OP) // np. @s:"orths" (lower(orth[-1]); lower(orth[0]))
SYM_OPS ::= @t:STRING (SEQ_of_SYM_FUNC_OP+) // np. @t"case0":(cas[0])
BOOL_OPS ::= @b:STRING (SEQ_of_BOOL_FUNC_OP+) // np. nie(inter(base[0], ["nie"]))

Operatory wchodzące w skład nazwanych ciągów oddzielane są średnikami.

Przykładowy plik WCCL (korzysta z operatora lex i importów):

import("indecl.lex", "indecl") // import file as "indecl" 

@b:"indecl" ( // tests for particular classes from the lexicon
   inter(lex(lower(orth[0]), "indecl"), ["adv"]);
   inter(lex(lower(orth[0]), "indecl"), ["interj"]);
   inter(lex(lower(orth[0]), "indecl"), ["part"]);
   inter(lex(lower(orth[0]), "indecl"), ["prep"])
)

@s:"indecl_label" ( // gets the label from the lexicon
   lex(lower(orth[0]), "indecl")
)

Przykładowy plik WCCL zawierający jedynie reguły dopasowania:

match_rules(
  apply(
    match(
      and( inter(class[0], {subst, ger, depr}), inter(cas[0], {nom}) )
    ),
    actions(
      mark($m:_M, 'N_NOM')
    )
  );
  apply(
    match(
      is('N_NOM')
    ),
    actions(
      mark(M, 'COPY')
    )
  )
)

Format pliku leksykonów.

Plik składa się z linii, linie puste są pomijane. Każda linia może zawierać dwie kolumny oddzielone tabulatorem, bądź jedną kolumnę (tabulator nie występuje). W przypadku dwóch kolumn, traktowane są one jako klucz–wartość. Jeśli występuje jedna kolumna, to traktowane to jest jako przypisanie kluczowi samego siebie. Ta druga opcja też ma sens, gdyż możemy chcieć sprawdzić, czy słowo należy do leksykonu bez wnikania w klasę mu przypisaną — wtedy jako leksykon wystarczy podać listę słów.

Struktura danych (w zasadzie to nie powinno być w specyfikacji języka, ale gdzieś być musi)

Po przeparsowaniu pliku powinna powstawać struktura, która pozwala na dostęp do konkretnych operatorów. Można rozważyć też opcję klonowania wszystkiego.

Struktura powinna udostępniać następujące rzeczy:
  1. pobranie operatora podanego typu o podanej nazwie
  2. pobranie listy nazw operatorów podanego typu
  3. pobranie listy par nazwa-op danego typu
  4. pobranie listy par nazwa-op wszystkich typów (powinna być zachowana kolejność definicji w pliku, niezależnie od typu)
  5. pobranie ciągu reguł (RuleSeq)

Uwaga: jeśli pod podaną nazwą w pliku jest więcej operatorów, ich nazwy powinny zostać automatycznie o końcówkę wg wzoru -n, gdzie n to 1, 2, …. Ewentualnie można by tę informację też trzymać w strukturze, tj. zostawić możliwość dostępu do ciągów operatorów pod pierwotną nazwą (ale podstawową funkcjonalnością jest pobranie ciągu nazw i odpowiadających operatorów, dzięki temu można wygenerować cechy do klasyfikacji).

Jeśli w pliku pojawią się dwa elementy match_rules czy tag_rules, należy zgłosić wyjątek.