diff --git a/Build/mkall.targets b/Build/mkall.targets
index f549811001..44f6b09526 100644
--- a/Build/mkall.targets
+++ b/Build/mkall.targets
@@ -236,7 +236,7 @@
9.4.0.1-beta
11.0.0-beta0131
70.1.123
- 3.6.6
+ 3.6.7
1.1.1-beta0001
bt393
diff --git a/Build/nuget-common/packages.config b/Build/nuget-common/packages.config
index bbc782831f..bcb3a2caac 100644
--- a/Build/nuget-common/packages.config
+++ b/Build/nuget-common/packages.config
@@ -63,8 +63,8 @@
-
-
+
+
diff --git a/DistFiles/Language Explorer/Configuration/Parts/Morphology.fwlayout b/DistFiles/Language Explorer/Configuration/Parts/Morphology.fwlayout
index 719519c6d8..9858871d87 100644
--- a/DistFiles/Language Explorer/Configuration/Parts/Morphology.fwlayout
+++ b/DistFiles/Language Explorer/Configuration/Parts/Morphology.fwlayout
@@ -43,18 +43,22 @@
+
+
+
+
diff --git a/DistFiles/Language Explorer/Configuration/Parts/MorphologyParts.xml b/DistFiles/Language Explorer/Configuration/Parts/MorphologyParts.xml
index b6d1f4e68e..21190e798d 100644
--- a/DistFiles/Language Explorer/Configuration/Parts/MorphologyParts.xml
+++ b/DistFiles/Language Explorer/Configuration/Parts/MorphologyParts.xml
@@ -667,6 +667,11 @@
+
+
+
+
+
@@ -2106,6 +2111,14 @@
+
+
+
+
+
+
+
+
diff --git a/Src/LexText/ParserCore/FwXmlTraceManager.cs b/Src/LexText/ParserCore/FwXmlTraceManager.cs
index a0ebf5478c..6a7702c0ec 100644
--- a/Src/LexText/ParserCore/FwXmlTraceManager.cs
+++ b/Src/LexText/ParserCore/FwXmlTraceManager.cs
@@ -13,6 +13,8 @@
using SIL.Machine.Annotations;
using System.Collections.Generic;
using System.Text;
+using SIL.Machine.Rules;
+using SIL.Core.ClearShare;
namespace SIL.FieldWorks.WordWorks.Parser
{
@@ -91,6 +93,40 @@ public void MorphologicalRuleNotUnapplied(IMorphologicalRule rule, int subruleIn
{
}
+ public void CompoundingRuleNotUnapplied(IMorphologicalRule rule, int subruleIndex, Word input, FailureReason reason, object obj)
+ {
+ var trace = new XElement("CompoundingRuleAnalysisTrace",
+ CreateMorphologicalRuleElement(rule));
+ var crule = rule as CompoundingRule;
+ if (crule != null)
+ {
+ var stremProdRestricts = obj as MprFeatureSet;
+ if (stremProdRestricts != null)
+ {
+ trace.Add(new XElement("FailureReason", new XAttribute("type", "missingProdRestrict"),
+ new XElement("StemProdRestricts", stremProdRestricts.Select(f => new XElement("MprFeature", f))),
+ new XElement("RuleProdRestricts", crule.NonHeadProdRestrictionsMprFeatures.Select(f => new XElement("MprFeature", f)))));
+ }
+ }
+ trace.Add(new XElement("Output", "*None*"));
+ ((XElement)input.CurrentTrace).Add(trace);
+ }
+
+ public void CompoundingRuleNotApplied(IMorphologicalRule rule, int subruleIndex, Word input, FailureReason reason, object failureObj)
+ {
+ var trace = new XElement("CompoundingRuleSynthesisTrace",
+ CreateMorphologicalRuleElement(rule));
+ var crule = rule as CompoundingRule;
+ if (crule != null)
+ {
+ trace.Add(new XElement("FailureReason", new XAttribute("type", "missingProdRestrict"),
+ new XElement("StemProdRestricts", input.MprFeatures.Select(f => new XElement("MprFeature", f))),
+ new XElement("RuleProdRestricts", crule.HeadProdRestrictionsMprFeatures.Select(f => new XElement("MprFeature", f)))));
+ }
+ trace.Add(new XElement("Output", "*None*"));
+ ((XElement)input.CurrentTrace).Add(trace);
+ }
+
public void LexicalLookup(Stratum stratum, Word input)
{
var trace = new XElement("LexLookupTrace",
diff --git a/Src/LexText/ParserCore/HCLoader.cs b/Src/LexText/ParserCore/HCLoader.cs
index c0f2479aa7..f713960b4d 100644
--- a/Src/LexText/ParserCore/HCLoader.cs
+++ b/Src/LexText/ParserCore/HCLoader.cs
@@ -177,7 +177,10 @@ private void LoadLanguage()
var prodRestrictsGroup = new MprFeatureGroup { Name = "exceptionFeatures", MatchType = MprFeatureGroupMatchType.All };
foreach (ICmPossibility prodRestrict in m_cache.LanguageProject.MorphologicalDataOA.ProdRestrictOA.ReallyReallyAllPossibilities)
+ {
LoadMprFeature(prodRestrict, prodRestrictsGroup);
+
+ }
if (prodRestrictsGroup.MprFeatures.Count > 0)
m_language.MprFeatureGroups.Add(prodRestrictsGroup);
@@ -1838,12 +1841,18 @@ private CompoundingRule LoadEndoCompoundingRule(IMoEndoCompound compoundRule)
{
var headRequiredFS = new FeatureStruct();
var nonheadRequiredFS = new FeatureStruct();
+ var headProdResticts = new MprFeatureSet();
+ var nonheadProdResticts = new MprFeatureSet();
if (compoundRule.HeadLast)
{
if (compoundRule.RightMsaOA.PartOfSpeechRA != null)
headRequiredFS.AddValue(m_posFeature, LoadAllPartsOfSpeech(compoundRule.RightMsaOA.PartOfSpeechRA));
if (compoundRule.LeftMsaOA.PartOfSpeechRA != null)
nonheadRequiredFS.AddValue(m_posFeature, LoadAllPartsOfSpeech(compoundRule.LeftMsaOA.PartOfSpeechRA));
+ if (compoundRule.RightMsaOA.ProdRestrictRC.Count > 0)
+ CreateProdRestricts(compoundRule.RightMsaOA.ProdRestrictRC, headProdResticts);
+ if (compoundRule.LeftMsaOA.ProdRestrictRC.Count > 0)
+ CreateProdRestricts(compoundRule.LeftMsaOA.ProdRestrictRC, nonheadProdResticts);
}
else
{
@@ -1851,6 +1860,10 @@ private CompoundingRule LoadEndoCompoundingRule(IMoEndoCompound compoundRule)
nonheadRequiredFS.AddValue(m_posFeature, LoadAllPartsOfSpeech(compoundRule.RightMsaOA.PartOfSpeechRA));
if (compoundRule.LeftMsaOA.PartOfSpeechRA != null)
headRequiredFS.AddValue(m_posFeature, LoadAllPartsOfSpeech(compoundRule.LeftMsaOA.PartOfSpeechRA));
+ if (compoundRule.RightMsaOA.ProdRestrictRC.Count > 0)
+ CreateProdRestricts(compoundRule.RightMsaOA.ProdRestrictRC, nonheadProdResticts);
+ if (compoundRule.LeftMsaOA.ProdRestrictRC.Count > 0)
+ CreateProdRestricts(compoundRule.LeftMsaOA.ProdRestrictRC, headProdResticts);
}
headRequiredFS.Freeze();
nonheadRequiredFS.Freeze();
@@ -1870,6 +1883,8 @@ private CompoundingRule LoadEndoCompoundingRule(IMoEndoCompound compoundRule)
Name = compoundRule.Name.BestAnalysisAlternative.Text,
HeadRequiredSyntacticFeatureStruct = headRequiredFS,
NonHeadRequiredSyntacticFeatureStruct = nonheadRequiredFS,
+ HeadProdRestrictionsMprFeatures = headProdResticts,
+ NonHeadProdRestrictionsMprFeatures = nonheadProdResticts,
OutSyntacticFeatureStruct = outFS,
Properties = { { HCParser.CRuleID, compoundRule.Hvo } }
};
@@ -1894,6 +1909,14 @@ private CompoundingRule LoadEndoCompoundingRule(IMoEndoCompound compoundRule)
return hcCompoundRule;
}
+ private void CreateProdRestricts(ILcmReferenceCollection ruleProdRestricts, MprFeatureSet prodResticts)
+ {
+ foreach (var prodRstrict in ruleProdRestricts)
+ {
+ prodResticts.Add(m_mprFeatures[prodRstrict]);
+ }
+ }
+
private IEnumerable LoadExoCompoundingRule(IMoExoCompound compoundRule)
{
var rightRequiredFS = new FeatureStruct();
@@ -1908,6 +1931,12 @@ private IEnumerable LoadExoCompoundingRule(IMoExoCompound compo
if (compoundRule.ToMsaOA.PartOfSpeechRA != null)
outFS.AddValue(m_posFeature, m_posFeature.PossibleSymbols["pos" + compoundRule.ToMsaOA.PartOfSpeechRA.Hvo]);
outFS.Freeze();
+ var headProdResticts = new MprFeatureSet();
+ var nonheadProdResticts = new MprFeatureSet();
+ if (compoundRule.RightMsaOA.ProdRestrictRC.Count > 0)
+ CreateProdRestricts(compoundRule.RightMsaOA.ProdRestrictRC, headProdResticts);
+ if (compoundRule.LeftMsaOA.ProdRestrictRC.Count > 0)
+ CreateProdRestricts(compoundRule.LeftMsaOA.ProdRestrictRC, nonheadProdResticts);
var headPattern = new Pattern("head", AnyPlus());
headPattern.Freeze();
@@ -1919,6 +1948,8 @@ private IEnumerable LoadExoCompoundingRule(IMoExoCompound compo
Name = compoundRule.Name.BestAnalysisAlternative.Text,
HeadRequiredSyntacticFeatureStruct = rightRequiredFS,
NonHeadRequiredSyntacticFeatureStruct = leftRequiredFS,
+ HeadProdRestrictionsMprFeatures = headProdResticts,
+ NonHeadProdRestrictionsMprFeatures = nonheadProdResticts,
OutSyntacticFeatureStruct = outFS,
Properties = { { HCParser.CRuleID, compoundRule.Hvo } }
};
@@ -1944,6 +1975,8 @@ private IEnumerable LoadExoCompoundingRule(IMoExoCompound compo
Name = compoundRule.Name.BestAnalysisAlternative.Text,
HeadRequiredSyntacticFeatureStruct = leftRequiredFS,
NonHeadRequiredSyntacticFeatureStruct = rightRequiredFS,
+ HeadProdRestrictionsMprFeatures = nonheadProdResticts,
+ NonHeadProdRestrictionsMprFeatures = headProdResticts,
OutSyntacticFeatureStruct = outFS,
Properties = { { HCParser.CRuleID, compoundRule.Hvo } }
};
diff --git a/Src/LexText/ParserCore/ParserCoreTests/HCLoaderTests.cs b/Src/LexText/ParserCore/ParserCoreTests/HCLoaderTests.cs
index 4dfe09b700..2e2a6017f6 100644
--- a/Src/LexText/ParserCore/ParserCoreTests/HCLoaderTests.cs
+++ b/Src/LexText/ParserCore/ParserCoreTests/HCLoaderTests.cs
@@ -944,6 +944,27 @@ public void EndoCompoundRule()
Assert.That(subrule.HeadLhs.Select(p => p.ToString()), Is.EqualTo(new[] {AnyPlus}));
Assert.That(subrule.NonHeadLhs.Select(p => p.ToString()), Is.EqualTo(new[] {AnyPlus}));
Assert.That(subrule.Rhs.Select(a => a.ToString()), Is.EqualTo(new[] {"", "+", ""}));
+
+ // test for exception "features"
+ compoundRule.LeftMsaOA.ProdRestrictRC.Add(AddExceptionFeature("Left prod restrict"));
+ LoadLanguage();
+
+ Assert.That(m_lang.Strata[0].MorphologicalRules.Count, Is.EqualTo(1));
+ hcCompoundRule = (CompoundingRule)m_lang.Strata[0].MorphologicalRules[0];
+
+ Assert.That(hcCompoundRule.HeadProdRestrictionsMprFeatures.Count, Is.EqualTo(0));
+ Assert.That(hcCompoundRule.NonHeadProdRestrictionsMprFeatures.Count, Is.EqualTo(1));
+ Assert.That(hcCompoundRule.NonHeadProdRestrictionsMprFeatures.ElementAt(0).Name, Is.EqualTo("Left prod restrict"));
+
+ compoundRule.RightMsaOA.ProdRestrictRC.Add(AddExceptionFeature("Right prod restrict"));
+ LoadLanguage();
+
+ Assert.That(m_lang.Strata[0].MorphologicalRules.Count, Is.EqualTo(1));
+ hcCompoundRule = (CompoundingRule)m_lang.Strata[0].MorphologicalRules[0];
+
+ Assert.That(hcCompoundRule.NonHeadProdRestrictionsMprFeatures.Count, Is.EqualTo(1));
+ Assert.That(hcCompoundRule.HeadProdRestrictionsMprFeatures.Count, Is.EqualTo(1));
+ Assert.That(hcCompoundRule.HeadProdRestrictionsMprFeatures.ElementAt(0).Name, Is.EqualTo("Right prod restrict"));
}
[Test]
@@ -984,6 +1005,28 @@ public void ExoCompoundRule()
Assert.That(subrule.NonHeadLhs.Select(p => p.ToString()), Is.EqualTo(new[] {AnyPlus}));
Assert.That(subrule.Rhs.Select(a => a.ToString()), Is.EqualTo(new[] {"", "+", ""}));
Assert.That(subrule.OutMprFeatures.Select(mf => mf.ToString()), Is.EquivalentTo(new[] {"inflClass"}));
+
+ // test for exception "features"
+ compoundRule.LeftMsaOA.ProdRestrictRC.Add(AddExceptionFeature("Left prod restrict"));
+ LoadLanguage();
+
+ Assert.That(m_lang.Strata[0].MorphologicalRules.Count, Is.EqualTo(2));
+ hcCompoundRule = (CompoundingRule)m_lang.Strata[0].MorphologicalRules[0];
+
+ Assert.That(hcCompoundRule.HeadProdRestrictionsMprFeatures.Count, Is.EqualTo(0));
+ Assert.That(hcCompoundRule.NonHeadProdRestrictionsMprFeatures.Count, Is.EqualTo(1));
+ Assert.That(hcCompoundRule.NonHeadProdRestrictionsMprFeatures.ElementAt(0).Name, Is.EqualTo("Left prod restrict"));
+
+ compoundRule.RightMsaOA.ProdRestrictRC.Add(AddExceptionFeature("Right prod restrict"));
+ LoadLanguage();
+
+ Assert.That(m_lang.Strata[0].MorphologicalRules.Count, Is.EqualTo(2));
+ hcCompoundRule = (CompoundingRule)m_lang.Strata[0].MorphologicalRules[0];
+
+ Assert.That(hcCompoundRule.NonHeadProdRestrictionsMprFeatures.Count, Is.EqualTo(1));
+ Assert.That(hcCompoundRule.HeadProdRestrictionsMprFeatures.Count, Is.EqualTo(1));
+ Assert.That(hcCompoundRule.HeadProdRestrictionsMprFeatures.ElementAt(0).Name, Is.EqualTo("Right prod restrict"));
+
}
[Test]
diff --git a/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTests.cs b/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTests.cs
index af8e44cc52..274eb2d33d 100644
--- a/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTests.cs
+++ b/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTests.cs
@@ -40,6 +40,7 @@ public class M3ToXAmpleTransformerTests
string m_sM3FXTIrregularlyInflectedFormsDump;
string m_sM3FXTQuechuaMYLDump;
string m_sM3FXTEmiFLExDump;
+ string m_sM3FXTCompundRulesWithExceptionFeaturesFLExDump;
private string m_sAbazaOrderClassPlayDump;
readonly Dictionary m_mapXmlDocs = new Dictionary();
@@ -87,6 +88,7 @@ private void SetUpM3FXTDump()
m_sAbazaOrderClassPlayDump = Path.Combine(m_sTestPath, "Abaza-OrderclassPlay.xml");
m_sM3FXTQuechuaMYLDump = Path.Combine(m_sTestPath, "QuechuaMYLFxtResult.xml");
m_sM3FXTEmiFLExDump = Path.Combine(m_sTestPath, "emi-flexFxtResult.xml");
+ m_sM3FXTCompundRulesWithExceptionFeaturesFLExDump = Path.Combine(m_sTestPath, "CompundRulesWithExceptionFeatures.xml");
SetupXmlDocument(m_sM3FXTDump);
SetupXmlDocument(m_sM3FXTCircumfixDump);
@@ -105,6 +107,7 @@ private void SetUpM3FXTDump()
SetupXmlDocument(m_sAbazaOrderClassPlayDump);
SetupXmlDocument(m_sM3FXTQuechuaMYLDump);
SetupXmlDocument(m_sM3FXTEmiFLExDump);
+ SetupXmlDocument(m_sM3FXTCompundRulesWithExceptionFeaturesFLExDump);
}
private void SetupXmlDocument(string filepath)
@@ -182,6 +185,7 @@ public void CreateXAmpleWordGrammarFile()
ApplyTransform(m_sM3FXTAffixAlloFeatsDump, m_gramTransform, "AffixAlloFeatsWordGrammar.txt");
ApplyTransform(m_sM3FXTLatinDump, m_gramTransform, "LatinWordGrammar.txt");
ApplyTransform(m_sM3FXTQuechuaMYLDump, m_gramTransform, "QuechuaMYLgram.txt");
+ ApplyTransform(m_sM3FXTCompundRulesWithExceptionFeaturesFLExDump, m_gramTransform, "CompundRulesWithExceptionFeaturesWordGrammar.txt");
}
private void ApplyTransform(string sInput, XslCompiledTransform transform, string sExpectedOutput)
{
diff --git a/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTestsDataFiles/CompundRulesWithExceptionFeatures.xml b/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTestsDataFiles/CompundRulesWithExceptionFeatures.xml
new file mode 100644
index 0000000000..3e17450871
--- /dev/null
+++ b/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTestsDataFiles/CompundRulesWithExceptionFeatures.xml
@@ -0,0 +1,723 @@
+
+
+
+ Adverb
+ An adverb, narrowly defined, is a part of speech whose members modify verbs for such categories as time, manner, place, or direction. An adverb, broadly defined, is a part of speech whose members modify any constituent class of words other than nouns, such as verbs, adjectives, adverbs, phrases, clauses, or sentences. Under this definition, the possible type of modification depends on the class of the constituent being modified.
+ adv
+ 0
+
+
+
+
+
+
+
+
+ Noun
+ A noun is a broad classification of parts of speech which include substantives and nominals.
+ n
+ 2
+
+
+
+
+
+
+
+
+ Pro-form
+ A pro-form is a part of speech whose members usually substitute for other constituents, including phrases, clauses, or sentences, and whose meaning is recoverable from the linguistic or extralinguistic context.
+ pro-form
+ 0
+
+
+
+
+
+
+
+
+
+ Pronoun
+ A pronoun is a pro-form which functions like a noun and substitutes for a noun or noun phrase.
+ pro
+ 0
+
+
+
+
+
+
+
+
+ Verb
+ A verb is a part of speech whose members typically signal events and actions; constitute, singly or in a phrase, a minimal predicate in a clause; govern the number and types of other constituents which may occur in the clause; and, in inflectional languages, may be inflected for tense, aspect, voice, modality, or agreement with other constituents in person, number, or grammatical gender.
+ v
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+ Consonants
+ Consonants
+ C
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Vowels
+ Vowels
+ V
+
+
+
+
+
+
+
+
+
+
+ Main phoneme set
+ Main phoneme set
+
+
+ a
+ low central unrounded vowel
+
+
+ a
+
+
+
+
+
+
+ b
+ voiced bilabial stop
+
+
+ b
+
+
+
+
+
+
+ d
+ voiced alveolar stop
+
+
+ d
+
+
+
+
+
+
+ e
+ mid front unrounded vowel
+
+
+ e
+
+
+
+
+
+
+ f
+ voiceless labiodental fricative
+
+
+ f
+
+
+
+
+
+
+ g
+ voiced velar stop
+
+
+ g
+
+
+
+
+
+
+ i
+ high front unrounded vowel
+
+
+ i
+
+
+
+
+
+
+ j
+ palatal approximant
+
+
+ j
+
+
+
+
+
+
+ k
+ voiceless velar stop
+
+
+ k
+
+
+
+
+
+
+ l
+ alveolar lateral
+
+
+ l
+
+
+
+
+
+
+ m
+ bilabial nasal
+
+
+ m
+
+
+
+
+
+
+ n
+ alveolar nasal
+
+
+ n
+
+
+
+
+
+
+ o
+ mid back rounded vowel
+
+
+ o
+
+
+
+
+
+
+ p
+ voiceless bilabial stop
+
+
+ p
+
+
+
+
+
+
+ r
+ alveolar flap
+
+
+ r
+
+
+
+
+
+
+ s
+ voiceless alveolar fricative
+
+
+ s
+
+
+
+
+
+
+ t
+ voiceless alveolar stop
+
+
+ t
+
+
+
+
+
+
+ u
+ high back rounded vowel
+
+
+ u
+
+
+
+
+
+
+ v
+ voiced labiodental fricative
+
+
+ v
+
+
+
+
+
+
+ w
+ labiovelar approximant
+
+
+ w
+
+
+
+
+
+
+ x
+ voiceless velar fricative
+
+
+ x
+
+
+
+
+
+
+ z
+ voiced alveolar fricative
+
+
+ z
+
+
+
+
+
+
+ ŋ
+ velar nasal
+
+
+ ŋ
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+ #
+
+
+ #
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+ 1
+ 5
+ 0
+ 1
+ 10
+
+ XAmple
+
+
+
+
+ Noun-verb
+ ***
+
+
+
+
+
+ Verb-Noun
+ ***
+
+
+
+
+
+ non-headed
+ fake one
+
+
+
+
+
+
+
+
+ Left-headed noun incorporation
+ Is OK for this noun to be incorporated in a left-headed compound
+ lni
+
+
+ Right-headed noun incorporation
+ Is OK for this noun to be incorporated in a right-headed compound
+ rni
+
+
+ Extra exception feature
+ Used for testing only
+ xt
+
+
+
+
+ discontiguous phrase
+ dis phr
+ A discontiguous phrase has discontiguous constituents which (a) are separated from each other by one or more intervening constituents, and (b) are considered either (i) syntactically contiguous and unitary, or (ii) realizing the same, single meaning. An example is French ne...pas.
+ 0
+
+
+ infixing interfix
+ ifxnfx
+ An infixing interfix is an infix that can occur between two roots or stems.
+ 0
+
+
+ suffixing interfix
+ sfxnfx
+ A suffixing interfix is a suffix that can occur between two roots or stems.
+ 0
+
+
+ particle
+ part
+ A particle is a word that does not belong to one of the main classes of words, is invariable in form, and typically has grammatical or pragmatic meaning.
+ 0
+
+
+ phrase
+ phr
+ A phrase is a syntactic structure that consists of more than one word but lacks the subject-predicate organization of a clause.
+ 0
+
+
+ prefixing interfix
+ pfxnfx
+ A prefixing interfix is a prefix that can occur between two roots or stems.
+ 0
+
+
+ clitic
+ clit
+ A clitic is a morpheme that has syntactic characteristics of a word, but shows evidence of being phonologically bound to another word. Orthographically, it stands alone.
+ 0
+
+
+ infix
+ ifx
+ An infix is an affix that is inserted within a root or stem.
+ 0
+
+
+ prefix
+ pfx
+ A prefix is an affix that is joined before a root or stem.
+ 0
+
+
+ simulfix
+ smfx
+ A simulfix is a change or replacement of vowels or consonants (usually vowels) which changes the meaning of a word. (Note: the parser does not currently handle simulfixes.)
+ 0
+
+
+ suffix
+ sfx
+ A suffix is an affix that is attached to the end of a root or stem.
+ 0
+
+
+ suprafix
+ spfx
+ A suprafix is a kind of affix in which a suprasegmental is superimposed on one or more syllables of the root or stem, signalling a particular morphosyntactic operation. (Note: the parser does not currently handle suprafixes.)
+ 0
+
+
+ circumfix
+ cfx
+ A circumfix is an affix made up of two separate parts which surround and attach to a root or stem.
+ 0
+
+
+ enclitic
+ enclit
+ An enclitic is a clitic that is phonologically joined at the end of a preceding word to form a single unit. Orthographically, it may attach to the preceding word.
+ 0
+
+
+ proclitic
+ proclit
+ A proclitic is a clitic that precedes the word to which it is phonologically joined. Orthographically, it may attach to the following word.
+ 0
+
+
+ bound root
+ bd root
+ A bound root is a root which cannot occur as a separate word apart from any other morpheme.
+ 0
+
+
+ root
+ ubd root
+ A root is the portion of a word that (i) is common to a set of derived or inflected forms, if any, when all affixes are removed, (ii) is not further analyzable into meaningful elements, being morphologically simple, and, (iii) carries the principal portion of meaning of the words in which it functions.
+ 0
+
+
+ bound stem
+ bd stem
+ A bound stem is a stem which cannot occur as a separate word apart from any other morpheme.
+ 0
+
+
+ stem
+ ubd stem
+ "A stem is the root or roots of a word, together with any derivational affixes, to which inflectional affixes are added." (LinguaLinks Library). A stem "may consist solely of a single root morpheme (i.e. a 'simple' stem as in man), or of two root morphemes (e.g. a 'compound' stem, as in blackbird), or of a root morpheme plus a derivational affix (i.e. a 'complex' stem, as in manly, unmanly, manliness). All have in common the notion that it is to the stem that inflectional affixes are attached." (Crystal, 1997:362)
+ 4
+
+
+
+
+ Irregularly Inflected Form
+ irreg. infl.
+ An Irregularly Inflected Form is an inflected form of the lexeme that is different from what you would expect from the normal rules of the grammar.
+ ***
+ .irr.infl
+
+
+
+ Past
+ pst.
+ The past tense form of a verb that does not take the regular inflectional affix for past tense.
+ ***
+ .pst
+
+
+
+ Plural
+ pl.
+ The plural form of a noun that does not take the regular inflectional affix for plural.
+ ***
+ .pl
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ dog
+ ***
+
+
+ water
+ ***
+
+
+ pat
+ ***
+
+
+ drink
+ ***
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Infl
+ ***
+ Infl
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTestsDataFiles/CompundRulesWithExceptionFeaturesWordGrammar.txt b/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTestsDataFiles/CompundRulesWithExceptionFeaturesWordGrammar.txt
new file mode 100644
index 0000000000..01d3b8f70f
--- /dev/null
+++ b/Src/LexText/ParserCore/ParserCoreTests/M3ToXAmpleTransformerTestsDataFiles/CompundRulesWithExceptionFeaturesWordGrammar.txt
@@ -0,0 +1,832 @@
+
+| DO NOT EDIT THIS FILE DIRECTLY!
+|
+
+| ------------------------------------------------------------
+| TOP-LEVEL WORD
+| ------------------------------------------------------------
+rule {Top-level cliticless word}
+ OrthographicWord = Word
+ | percolation
+ =
+ =
+
+rule {Top-level word with one or more proclitics and enclitics}
+ OrthographicWord = Proclitics Word Enclitics
+ | percolation
+ =
+ =
+ =
+ =
+ | drip (pass down)
+ =
+ =
+
+rule {Top-level word with one or more proclitics}
+ OrthographicWord = Proclitics Word
+ | percolation
+ =
+ =
+ =
+ | drip (pass down)
+ =
+
+rule {Top-level word with one or more enclitics}
+ OrthographicWord = Word Enclitics
+ | percolation
+ =
+ =
+ =
+ | drip (pass down)
+ =
+
+
+| ------------------------------------------------------------
+| CLITICS
+| ------------------------------------------------------------
+rule {One or more proclitics}
+ Proclitics_1 = proclitic (Proclitics_2)
+ | percolation
+ =
+ | drip (pass down)
+ =
+ | constraints
+ =
+ =
+
+rule {One or more enclitics}
+ Enclitics_1 = (Enclitics_2) enclitic
+ | percolation
+ =
+ | drip (pass down)
+ =
+ | constraints
+ =
+ =
+
+
+| ------------------------------------------------------------
+| WORD
+| ------------------------------------------------------------
+rule {clitic word}
+ Word = clitic
+ | percolation
+ =
+ =
+
+rule {Fully analyzed word}
+ Word = Full
+ | percolation
+ =
+ =
+ == [requiresInflection : -] / | doesn't require inflection or
+ [inflected : +] | is inflected
+
+rule {Partially analyzed word}
+ Word = Partial
+ | percolation
+ =
+ =
+
+| ------------------------------------------------------------
+| FULLY ANALYZED WORD PORTION
+| ------------------------------------------------------------
+
+rule {Fully analyzed stem with no inflectional template}
+ Full = Stem
+ | percolation
+ =
+ =
+ =
+ =
+ | constraint
+ = - | this Full word category is not inflected
+ = - | prevent a non-final template from immediately being inflected without any intervening derivation or compounding
+
+| ------------------------------------------------------------
+| STEM
+| ------------------------------------------------------------
+
+rule {Stem consisting of a single root}
+ Stem = root
+ | percolation
+ =
+ =
+ =
+ =
+ =
+ =
+ =
+ == ~[rootCat : unknown] | root category has to be overt
+
+
+rule {Stem with a derivational prefix}
+ Stem_1 = derivPfx Stem_2
+ | percolation
+ = | default to Stem 2 (in case deriv prefix has no category)
+ <= | use priority union to override anything in Stem_2
+ =
+ =
+ = | default to stem 2 (in case deriv prefix has no to category)
+ <= | use deriv prefix when it has a category
+ =
+ =
+ <=
+ =
+ <=
+ <=
+ = - | This stem can now be inflected
+ | constraints
+ =
+ =
+ =
+ =
+ {
+
+ =
+ =
+ /
+ = 6433
+ = 6433
+{
+
+ = 6433 /
+ = 6354
+}
+
+ }
+
+rule {Stem with a derivational suffix}
+ Stem_1 = Stem_2 derivSfx
+ | percolation
+ = | default to Stem 2 (in case deriv suffix has no to category)
+ <= | use priority union to override anything in Stem_2
+ =
+ =
+ = | default to stem 2 (in case deriv suffix has no to category)
+ <= | use deriv suffix when it has a category
+ =
+ =
+ <=
+ =
+ <=
+ <=
+ = - | This stem can now be inflected
+ | constraints
+ =
+ =
+ =
+ =
+ {
+
+ =
+ =
+ /
+ = 6433
+ = 6433
+{
+
+ = 6433 /
+ = 6354
+}
+
+ }
+rule {Stem with a derivational circumfix}
+ Stem_1 = derivCircumPfx Stem_2 derivCircumSfx
+ | percolation
+ = | default to Stem 2 (in case deriv circumfixes have no to category)
+ <= | use priority union to override anything in Stem_2
+ <=
+ =
+ =
+ =
+ = | default to stem 2 (in case deriv prefix has no category)
+ <= | use deriv prefix when it has a category
+ <= | use deriv suffix when it has a category
+ =
+ =
+ <=
+ <=
+ =
+ <=
+ <=
+ <=
+ <=
+ = - | This stem can now be inflected
+ | constraints
+ =
+ =
+ =
+ =
+ =
+ =
+ =
+ =
+ {
+
+ =
+ =
+ =
+ =
+ /
+ = 6433
+ = 6433
+ = 6433
+ = 6433
+{
+
+ = 6433 /
+ = 6354
+}
+
+ }
+
+rule {Stem with a derivational circumfix where the rightmost part is an infix (and so may end up as a prefix}
+ Stem_1 = derivCircumPfx_1 derivCircumPfx_2 Stem_2
+ | percolation
+ = | default to Stem 2 (in case deriv circumfixes have no to category)
+ <= | use priority union to override anything in Stem_2
+ <=
+ =