This is the first post in a tutorial series on applying Parsec in historical linguistics. We’ll begin by providing a more formal description of sound change rule grammars and end by building a full-fledged sound change applier.
Historical linguists1 use a standard grammar to describe a language’s sound change over time (diachronically) or among different speakers at the same time (synchronically). Each individual change can be explained by a simple replacement rule, but often requires a certain context to occur. An example unconditioned sound change rule follows:
r > l
This rule states that, in some language, the /r/ sound becomes /l/ no matter the context of the /r/ sound. This rule alone can effectively describe the change from a morph /fara/ to /fala/, or from /rata/ to /lata/.
Most sound change in natural languages, however, are conditional: they only occur in certain contexts. We can describe required contexts with an additional clause in sound change rules:
r > l / a_o
This rule states that /r/ changes to /l/ only when preceded by an /a/ and succeeded by an /o/. It describes a change from /taro/ to /talo/, but not from /tar/ to /tal/ or /ero/ to /elo/.
We can describe this sound change rule format as a simple BNF grammar:
<rule> ::= <context> ">" <replacement> ["/" <condition>]
<condition> ::= <context>_<context>
<context> ::= (<phoneme> | <phoneme-class>)+
<phoneme> ::= <lowercase-letter>
<phoneme-class> ::= <uppercase-letter>
Close readers will notice that I included in the above grammar the concept of a phoneme class. Sound change appliers often accept as input along with sound change rules a list of phoneme class definitions. These describe sets of phonemes which, when referenced within a context, allow any of their members to appear in the specified position.
V: aeiou
This line defines a phoneme class V (presumably the vowel class). Whenever V appears in a sound change rule, any of /a/, /e/, /i/, /o/, or /u/ should match.
Phoneme classes are extremely useful, since most sound changes (synchronic and diachronic) only apply in certain phonological contexts rather than standing as a universal fact. Let’s amend our grammar so that we can describe an entire sound change collection:
<file> ::= (<phoneme-class-defn> <EOL>)* (<rule> <EOL>)+
<phoneme-class-defn> ::= <phoneme-class> ":" <phoneme>+
<rule> ::= <context> ">" <replacement> ["/" <condition>]
<condition> ::= <context>_<context>
<context> ::= (<phoneme> | <phoneme-class>)+
<phoneme> ::= <lowercase-letter>
<phoneme-class> ::= <uppercase-letter>
In the next installment of this tutorial, we’ll use this grammar to build a Parsec parser that can digest sound change rules.
-
And conlangers! ↩