/
bear
/
morph_dict
Обзор
Документация
Войти
/
bear
/
morph_dict
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
AgramtabLib/RusGramTab.cpp
768 строк
23 KB
sokirko74
update morphology
05 мар 2023, 23:53
05 мар 2023, 23:53
5c07ac1
Код
Авторство
О чём код?
// ========== This file is under LGPL, the GNU Lesser General Public Licence // ========== Dialing Lemmatizer (www.aot.ru) // ========== Copyright by Alexey Sokirko #include "RusGramTab.h" #include "rus_consts.h" struct TMorphConstant { std::string Cyrillic; std::string Latin; }; const static TMorphConstant RussianPartOfSpeech[] = { {_R("С"), "N"}, // 0 {_R("П"), "A"}, // 1 {_R("Г"), "V"}, // 2 {_R("МС"),"P"}, // 3 {_R("МС-П"),"PA"}, // 4 {_R("МС-ПРЕДК"),"P-PRED"}, // 5 {_R("ЧИСЛ"), "N"}, // 6 {_R("ЧИСЛ-П"),"NA"}, // 7 {_R("Н"),"ADV"}, // 8 {_R("ПРЕДК"), "PRED"}, //9 {_R("ПРЕДЛ"), "PREP"}, // 10 {_R("ПОСЛ"), "POSL"}, // 11 {_R("СОЮЗ"), "CONJ"}, // 12 {_R("МЕЖД"), "INT"}, // 13 {_R("ВВОДН"), "INP"},// 14 {_R("ФРАЗ"), "COLLOC"}, // 15 {_R("ЧАСТ"), "PARTICLE"}, // 16 {_R("КР_ПРИЛ"), "ADJ_SHORT"}, // 17 {_R("ПРИЧАСТИЕ"), "PARTICIPLE"}, //18 {_R("ДЕЕПРИЧАСТИЕ"),"ADV_PARTICIPLE"}, //19 {_R("КР_ПРИЧАСТИЕ"),"PARTICIPLE_SHORT"}, // 20 {_R("ИНФИНИТИВ"), "INFINITIVE"} //21 }; const static TMorphConstant Grammems[] = { {_R("мн"), "pl"}, {_R("ед"), "sg"}, {_R("им"), "nom"}, {_R("рд"), "gen"}, {_R("дт"), "dat"}, {_R("вн"), "acc"}, {_R("тв"), "ins"}, {_R("пр"), "prp"}, {_R("зв"), "voc"}, {_R("мр"), "mas"}, {_R("жр"), "fem"}, {_R("ср"), "neu"}, {_R("мр-жр"), "mas-fem"}, {_R("нст"), "pres"}, {_R("буд"), "fut"}, {_R("прш"), "past"}, {_R("1л"), "1p"}, {_R("2л"), "2p"}, {_R("3л"), "3p"}, {_R("пвл"), "imp"}, {_R("од"), "anim"}, {_R("но"), "inanim"}, {_R("сравн"), "compar"}, {_R("св"), "perf"}, {_R("нс"), "imperf"}, {_R("нп"), "intrans"}, {_R("пе"), "trans"}, {_R("дст"), "act"}, {_R("стр"), "pass"}, {_R("0"), "0"}, {_R("аббр"), "abbr"}, {_R("отч"), "patr"}, {_R("лок"), "loc"}, {_R("орг"), "org"}, {_R("кач"), "qual"}, {_R("дфст"), "sing_tant"}, {_R("вопр"), "interrog"}, {_R("указат"), "demon"}, {_R("имя"), "name"}, {_R("фам"), "surname"}, {_R("безл"), "impers"}, {_R("жарг"), "jargon"}, {_R("опч"), "misspell"}, {_R("разг"), "conv"}, {_R("притяж"), "poss"}, {_R("арх"), "arch"}, {_R("2"), "2"}, {_R("поэт"), "poet"}, {_R("проф"), "prof"}, {_R("прев"), "superl"}, {_R("полож"), "positive"} }; std::string rClauseTypes[] = { _R("ГЛ_ЛИЧН"), _R("ДПР"), _R("КР_ПРЧ"), _R("КР_ПРИЛ"), _R("ПРЕДК"), _R("ПРЧ"), _R("ИНФ"), _R("ВВОД"), _R("ТИРЕ"), _R("НСО"), _R("СРАВН"), _R("КОПУЛ") }; CRusGramTab::CRusGramTab() { assert(sizeof(Grammems) / sizeof(TMorphConstant) == RussianGrammemsCount); assert(sizeof(RussianPartOfSpeech) / sizeof(TMorphConstant) == RUSSIAN_PART_OF_SPEECH_COUNT); assert(sizeof(rClauseTypes) / sizeof(std::string) == RUSSIAN_CLAUSE_TYPE_COUNT); for (size_t i = 0; i < GetMaxGrmCount(); i++) { GetLine(i) = nullptr; } m_Language = morphRussian; m_bUseNationalConstants = true; } CRusGramTab :: ~CRusGramTab() { for (size_t i = 0; i < GetMaxGrmCount(); i++) { if (GetLine(i) != NULL) delete GetLine(i); } } const char* CRusGramTab::GetRegistryString() const { return "Software\\Dialing\\Lemmatizer\\Russian\\Rgramtab"; }; part_of_speech_t CRusGramTab::GetPartOfSpeechesCount() const { return RUSSIAN_PART_OF_SPEECH_COUNT; }; size_t CRusGramTab::GetMaxGrmCount() const { return rMaxGrmCount; } const char* CRusGramTab::GetPartOfSpeechStr(part_of_speech_t i) const { if (m_bUseNationalConstants) { return RussianPartOfSpeech[i].Cyrillic.c_str(); } else { return RussianPartOfSpeech[i].Latin.c_str(); } }; grammem_t CRusGramTab::GetGrammemsCount() const { return RussianGrammemsCount; }; const char* CRusGramTab::GetGrammemStr(size_t i) const { if (m_bUseNationalConstants) { return Grammems[i].Cyrillic.c_str(); } else { return Grammems[i].Latin.c_str(); } }; CAgramtabLine*& CRusGramTab::GetLine(size_t LineNo) { return Lines[LineNo]; } const CAgramtabLine* CRusGramTab::GetLine(size_t LineNo) const { return Lines[LineNo]; } size_t CRusGramTab::GramcodeToLineIndex(const char* s) const { return (unsigned char)s[0] * 0x100 + (unsigned char)s[1] - rStartUp; }; std::string CRusGramTab::LineIndexToGramcode(uint16_t i) const { i += rStartUp; char res[3]; res[0] = (i >> 8); res[1] = (0xFF & i); res[2] = 0; return res; }; bool CRusGramTab::ProcessPOSAndGrammems(const char* tab_str, part_of_speech_t& PartOfSpeech, grammems_mask_t& grammems, bool deduce_grammems) const { if (!CAgramtab::ProcessPOSAndGrammems(tab_str, PartOfSpeech, grammems)) return false; if (!deduce_grammems) { return true; } // неизменяемые слова как будто принадлежат всем падежам if ((_QM(rIndeclinable) & grammems) && (PartOfSpeech != PREDK) ) grammems |= rAllCases; if ((_QM(rIndeclinable) & grammems) && (PartOfSpeech == PRONOUN_P) ) grammems |= rAllGenders | rAllNumbers; // слова общего рода ('сирота') могут использованы как // слова м.р., так и как слова ж.р. if (_QM(rMascFem) & grammems) grammems |= _QM(rMasculinum) | _QM(rFeminum); // слово 'пальто' не изменяется по числам, поэтому может // быть использовано в обоих числах if (PartOfSpeech != PREDK) if ((_QM(rIndeclinable) & grammems) && !(_QM(rSingular) & grammems)) grammems |= _QM(rPlural) | _QM(rSingular); return true; }; // Стандартное согласование между двумя именами по падежу, причем первый код должен // иметь граммему множественного числа inline bool CaseFirstPlural(const CAgramtabLine* l1, const CAgramtabLine* l2) { return (((rAllCases & l1->m_Grammems & l2->m_Grammems) > 0) && (((1 << rPlural) & l1->m_Grammems) > 0) ); }; // Стандартное согласование между двумя именами по роду и числу inline bool GenderNumber(const CAgramtabLine* l1, const CAgramtabLine* l2) { return ((rAllNumbers & l1->m_Grammems & l2->m_Grammems) > 0) && (((l1->m_Grammems & l2->m_Grammems & _QM(rPlural)) > 0) || ((rAllGenders & l1->m_Grammems & l2->m_Grammems) > 0) ); } // Стандартное согласование по лицу и числу (для 1 и 2 лица) inline bool PersonNumber(const CAgramtabLine* l1, const CAgramtabLine* l2) { size_t t1 = (rAllNumbers & l1->m_Grammems & l2->m_Grammems) > 0; size_t t2 = ((rAllPersons & l1->m_Grammems & l2->m_Grammems) > 0); return t1 && t2; } // Стандартное согласование между подлежащим и сказуемым inline bool SubjectPredicate(const CAgramtabLine* subj_l, const CAgramtabLine* verb_l) { const grammems_mask_t& subj = subj_l->m_Grammems; const grammems_mask_t& verb = verb_l->m_Grammems; if (!(subj & _QM(rNominativ)) ) return false; if (((verb & _QM(rPastTense)) > 0) || (verb_l->m_PartOfSpeech == ADJ_SHORT) || (verb_l->m_PartOfSpeech == PARTICIPLE_SHORT) ) { // ты вышел // я вышел // ты был // я красива // мы шли // вы шли if (subj & (_QM(rFirstPerson) | _QM(rSecondPerson))) return (verb & subj & _QM(rPlural)) || ((verb & (_QM(rMasculinum) | _QM(rFeminum))) && (verb & subj & _QM(rSingular)) ); else // он вышел // поезд ушел // девочка красива // девочки красивы // мальчик красив return GenderNumber(subj_l, verb_l); } else if ((verb & _QM(rPresentTense)) || (verb & _QM(rFutureTense))) { // я выйду // ты выедешь // мы выйдем if ((subj & (_QM(rFirstPerson) | _QM(rSecondPerson))) || (verb & (_QM(rFirstPerson) | _QM(rSecondPerson)))) return PersonNumber(subj_l, verb_l); else return (rAllNumbers & subj & verb) > 0; } else if (verb & _QM(rImperative)) return ((subj & _QM(rSecondPerson)) > 0) && ((rAllNumbers & subj & verb) > 0); return false; } // Стандартное согласование между двумя именами по падежу inline bool Case(const CAgramtabLine* l1, const CAgramtabLine* l2) { return ((rAllCases & l1->m_Grammems & l2->m_Grammems) > 0); } // Стандартное согласование между существительным и прилашательнымпо роду, числу и падежу, если // если существительное одушевленное bool GenderNumberCaseAnimRussian(const CAgramtabLine* l1, const CAgramtabLine* l2) { const grammems_mask_t& gram_noun = l1->m_Grammems; const grammems_mask_t& gram_adj = l2->m_Grammems; return ((rAllCases & gram_noun & gram_adj) > 0) && ((rAllNumbers & gram_noun & gram_adj) > 0) && (((_QM(rAnimative) & gram_adj) > 0) || ((rAllAnimative & gram_adj) == 0) ) && (((rAllGenders & gram_noun & gram_adj) > 0) || ((rAllGenders & gram_noun) == 0) || ((rAllGenders & gram_adj) == 0) ); }; // Стандартное согласование между существительным и прилашательнымпо роду, числу и падежу, если // если существительное неодушевленное bool GenderNumberCaseNotAnimRussian(const CAgramtabLine* l1, const CAgramtabLine* l2) { const grammems_mask_t& gram_noun = l1->m_Grammems; const grammems_mask_t& gram_adj = l2->m_Grammems; return ((rAllCases & gram_noun & gram_adj) > 0) && ((rAllNumbers & gram_noun & gram_adj) > 0) && (((_QM(rNonAnimative) & gram_adj) > 0) || ((rAllAnimative & gram_adj) == 0) ) && (((rAllGenders & gram_noun & gram_adj) > 0) || ((rAllGenders & gram_noun) == 0) || ((rAllGenders & gram_adj) == 0) ); }; // Стандартное согласование между существительным и прилашательнымпо роду, числу и падежу, если // если существительное не неодушевленное и не одушевленное // (для местоимений, например, "все это было хорошо") bool GenderNumberCaseRussian(const CAgramtabLine* l1, const CAgramtabLine* l2) { const grammems_mask_t& gram_noun = l1->m_Grammems; const grammems_mask_t& gram_adj = l2->m_Grammems; return ((rAllCases & gram_noun & gram_adj) > 0) && ((rAllNumbers & gram_noun & gram_adj) > 0) && (((rAllGenders & gram_noun & gram_adj) > 0) || ((rAllGenders & gram_noun) == 0) || ((rAllGenders & gram_adj) == 0) ); }; bool FiniteFormCoordRussian(const CAgramtabLine* l1, const CAgramtabLine* l2) { const grammems_mask_t& verb1 = l1->m_Grammems; const grammems_mask_t& verb2 = l2->m_Grammems; // жил и был if (verb1 & verb2 & rAllNumbers) if (verb1 & verb2 & _QM(rPastTense)) { if ((verb1 & verb2 & rAllGenders) || ((verb1 & verb2 & rAllNumbers) == _QM(rPlural)) ) return true; } else if (verb1 & verb2 & rAllPersons) return true; return false; }; /* Примеры работы функции GleicheGenderNumberCase: - красивого стол; - красивых столы; - красивый пирата; - красивые пиратов; - достойных жизни; - достойные матерей; - длинные чудовищ + на этот дом; + красивую маму; + в красивый дом; + в длинное облако; + примерить его цилиндр; + все это */ grammems_mask_t CRusGramTab::GleicheGenderNumberCase(const char* common_gram_code_noun, const char* gram_code_noun, const char* gram_code_adj) const { if ((common_gram_code_noun == 0) || !strcmp(common_gram_code_noun, "??") || (strlen(common_gram_code_noun) == 0) ) // нет сведений об одушевленности return Gleiche(GenderNumberCaseRussian, gram_code_noun, gram_code_adj); else if ((GetLine(GramcodeToLineIndex(common_gram_code_noun))->m_Grammems & _QM(rNonAnimative)) > 0) // неодушевленный return Gleiche(GenderNumberCaseNotAnimRussian, gram_code_noun, gram_code_adj); else if ((GetLine(GramcodeToLineIndex(common_gram_code_noun))->m_Grammems & _QM(rAnimative)) > 0) // одушевленный return Gleiche(GenderNumberCaseAnimRussian, gram_code_noun, gram_code_adj); else // нет сведений об одушевленности return Gleiche(GenderNumberCaseRussian, gram_code_noun, gram_code_adj); } bool CRusGramTab::GleicheCaseNumber(const char* gram_code1, const char* gram_code2) const { return Gleiche(CaseNumber, gram_code1, gram_code2) != 0; } bool CRusGramTab::GleicheGenderNumber(const char* gram_code1, const char* gram_code2) const { return Gleiche(GenderNumber, gram_code1, gram_code2) != 0; } //with absent grammems check, less strict than GleicheGenderNumber bool CRusGramTab::ConflictGenderNumber(const char* gram_code1, const char* gram_code2) const { return Gleiche(GenderNumber0, gram_code1, gram_code2) == 0; } bool CRusGramTab::ConflictGrammems(grammems_mask_t g1, grammems_mask_t g2, grammems_mask_t breaks) const { grammems_mask_t BR[] = { rAllCases, rAllNumbers, rAllGenders }; bool R = true; for (int i = 0; i < (sizeof BR) / (sizeof BR[0]) && R; i++) { if (breaks & BR[i]) R &= ((BR[i] & g1 & g2) > 0 || !(BR[i] & g1) || !(BR[i] & g2)); } return !R; } bool CRusGramTab::GleicheSubjectPredicate(const char* gram_code1, const char* gram_code2) const { return Gleiche(SubjectPredicate, gram_code1, gram_code2) != 0; } bool CRusGramTab::GleicheCase(const char* gram_code1, const char* gram_code2) const { return Gleiche(Case, gram_code1, gram_code2) != 0; } const size_t CRusGramTab::GetClauseTypesCount() const { return RUSSIAN_CLAUSE_TYPE_COUNT; }; long CRusGramTab::GetClauseTypeByName(const char* TypeName) const { for (int i = 0; i < RUSSIAN_CLAUSE_TYPE_COUNT; i++) { if (rClauseTypes[i] == TypeName) { return i; } } return -1; } const char* CRusGramTab::GetClauseNameByType(long type) const { if (type >= RUSSIAN_CLAUSE_TYPE_COUNT) return 0; if (type < 0) return 0; return rClauseTypes[type].c_str(); } /* истина для предикативных типов клауз. */ bool CRusGramTab::IsStrongClauseRoot(const part_of_speech_mask_t poses) const { return (poses & (1 << VERB)) || (poses & (1 << ADVERB_PARTICIPLE)) // субъект деепричастия совпадлает с субъектом // главной клаузы || (poses & (1 << PARTICIPLE_SHORT)) || (poses & (1 << ADJ_SHORT)) || (poses & (1 << PREDK)); }; const static std::string months[] = { _R("ЯНВАРЬ"),_R("ФЕВРАЛЬ"),_R("МАРТ"), _R("АПРЕЛЬ"),_R("МАЙ"),_R("ИЮНЬ"), _R("ИЮЛЬ"),_R("АВГУСТ"),_R("СЕНТЯБРЬ") ,_R("ОКТЯБРЬ"),_R("НОЯБРЬ"),_R("ДЕКАБРЬ") }; bool CRusGramTab::is_month(const char* lemma) const { if (!lemma) return false; for (size_t i = 0; i < 12; i++) if (months[i] == lemma) return true; return false; } const static std::string SmallNumbers[] = { _R("ДВА"),_R("ТРИ"),_R("ЧЕТЫРЕ"),_R("ОБА"),_R("ПОЛТОРА") }; bool CRusGramTab::is_small_number(const char* lemma) const { if (!lemma) return false; for (size_t i = 0; i < 5; i++) if (SmallNumbers[i].compare(lemma) == 0) return true; return false; } bool CRusGramTab::IsMorphNoun(part_of_speech_mask_t poses) const { return (poses & (1 << NOUN)); }; bool CRusGramTab::is_morph_adj(part_of_speech_mask_t poses) const { return (poses & (1 << ADJ_FULL)) || (poses & (1 << ADJ_SHORT)); }; bool CRusGramTab::is_morph_participle(part_of_speech_mask_t poses) const { return (poses & (1 << PARTICIPLE)) || (poses & (1 << PARTICIPLE_SHORT)); }; bool CRusGramTab::is_morph_pronoun(part_of_speech_mask_t poses) const { return (poses & (1 << PRONOUN)) != 0; }; bool CRusGramTab::is_morph_pronoun_adjective(part_of_speech_mask_t poses) const { return (poses & (1 << PRONOUN_P)) != 0; }; bool CRusGramTab::is_left_noun_modifier(part_of_speech_mask_t poses, grammems_mask_t grammems) const { return (poses & (1 << ADJ_FULL)) || (poses & (1 << NUMERAL_P)) || (poses & (1 << PRONOUN_P)) || (poses & (1 << PARTICIPLE)); } bool CRusGramTab::is_numeral(part_of_speech_mask_t poses) const { return (poses & (1 << NUMERAL)) != 0; }; bool CRusGramTab::is_verb_form(part_of_speech_mask_t poses) const { return is_morph_participle(poses) || (poses & (1 << VERB)) || (poses & (1 << INFINITIVE)) || (poses & (1 << ADVERB_PARTICIPLE)); }; bool CRusGramTab::is_infinitive(part_of_speech_mask_t poses) const { return (poses & (1 << INFINITIVE)) != 0; } bool CRusGramTab::is_morph_predk(part_of_speech_mask_t poses) const { return (poses & (1 << PREDK)) || (poses & (1 << PRONOUN_PREDK)); } bool CRusGramTab::is_morph_adv(part_of_speech_mask_t poses) const { return (poses & (1 << ADV)) != 0; } bool CRusGramTab::is_morph_personal_pronoun(part_of_speech_mask_t poses, grammems_mask_t grammems) const { return (poses & (1 << PRONOUN)) != 0 && (grammems & (_QM(rFirstPerson) | _QM(rSecondPerson) | _QM(rThirdPerson))); }; const size_t ParticleCount = 8; const static std::string Particles[ParticleCount] = { _R("ЛИ"),_R("ЖЕ"),_R("БЫ"),_R("УЖ"),_R("ТОЛЬКО"), _R("Ж"), _R("Б"), _R("ЛЬ") }; bool CRusGramTab::IsSimpleParticle(const char* lemma, part_of_speech_mask_t poses) const { if (!lemma) return false; if (!(poses & (1 << PARTICLE))) return false; for (int i = 0; i < ParticleCount; i++) if (Particles[i] == lemma) return true; return false; } /* Есть такие мест. прилагательные, которые могут выступать в роли существительных: _R("КАЖДЫЙ"), _R("ОДИН"), _R("ДРУГОЙ"),_R("ТОТ"),_R("КОТОРЫЙ"). Для них не имеет смысла вводит аналогичные местоимения,поскольку все они могут быть использованы во всех родах. Эти прилагательные могут вести себя так же, как существительные. Например, Я купил два яблока, в каждом оказалось много червяков Я знаю ту, которая тебя видит Один пришел, другой ушел. Я вижу дом, который разрушился. Вышеуказанные мест. прилагательные отличаются, например, от местоимения _R(_R("этот")) и _R("всякий"), поскольку трудно себе представить что-то вроде: "эта пришла" "всякая пришла" Но возможно: "всякое бывает" "это бывает" Здесь _R("всякое") и _R("это") - простые местоимения ср рода. !! Таким образом, я не хочу дублировать в морфологии МС-П, если они могут использованы !! во всех родах в качестве существительного. 1 марта 2001 года, Сокирко */ bool CRusGramTab::IsSynNoun(part_of_speech_mask_t poses, const char* lemma) const { return IsMorphNoun(poses) || (poses & (1 << PRONOUN)) || ((poses & (1 << PRONOUN_P)) && (_R("КАЖДЫЙ") == lemma) || (_R("ОДИН") == lemma) || (_R("ДРУГОЙ") == lemma) || (_R("ТОТ") == lemma) || (_R("КОТОРЫЙ") == lemma) ) ; }; const int StandardParamAbbrCount = 8; const static std::string StandardParamAbbr[StandardParamAbbrCount] = { _R("КГ"), _R("КМ"), _R("СМ"),_R("МЛ"), _R("МБ"),_R("КБ"), _R("МГЦ"), _R("КВ") }; bool CRusGramTab::IsStandardParamAbbr(const char* WordStrUpper) const { if (strlen(WordStrUpper) > 4) return false; for (long i = 0; i < StandardParamAbbrCount; i++) if (StandardParamAbbr[i] == WordStrUpper) return true; return false; } bool CRusGramTab::is_morph_article(part_of_speech_mask_t poses) const { return false; }; bool CRusGramTab::FilterNounNumeral(std::string& gcNoun, const std::string& gcNum, grammems_mask_t& grammems) const { if (gcNoun.length() == 2 || !(grammems & rAllCases)) return false; GleicheAncode1(CaseNumberGender0, gcNum, FilterGramCodes(gcNum, grammems & rAllCases | ~rAllCases, 0), gcNoun); return true; } std::string RussianCaseNumberGender(const CAgramtab* pGramTab, const std::string& adj, const std::string& common_noun_grm, const std::string& noun) { assert(false); //return pGramTab->GleicheGenderNumberCase(common_noun_grm.c_str(), noun.c_str(), adj.c_str()); return ""; }; grammems_mask_t CRusGramTab::ChangeGleicheAncode1(GrammemCompare CompareFunc, const std::string& wordGramCodes, std::string& groupGramCodes, const grammems_mask_t wordGrammems) const { groupGramCodes = GleicheAncode1(CompareFunc, FilterGramCodes(wordGramCodes, ~_QM(rIndeclinable), 0), groupGramCodes); if (groupGramCodes == "") { return 0; } const grammems_mask_t gramFilter = rAllCases | rAllGenders | rAllTimes | rAllPersons | rAllAnimative; return wordGrammems & ~(gramFilter) | GetAllGrammems(groupGramCodes.c_str()); } bool CaseNumber(const CAgramtabLine* l1, const CAgramtabLine* l2) { return ((rAllCases & l1->m_Grammems & l2->m_Grammems) > 0) && ((rAllNumbers & l1->m_Grammems & l2->m_Grammems) > 0); }; bool CaseGender(const CAgramtabLine* l1, const CAgramtabLine* l2) { return ((rAllCases & l1->m_Grammems & l2->m_Grammems) > 0) && ((rAllGenders & l1->m_Grammems & l2->m_Grammems) > 0); }; bool CaseNumberGender(const CAgramtabLine* l1, const CAgramtabLine* l2) { return ((rAllCases & l1->m_Grammems & l2->m_Grammems) > 0) && ((rAllNumbers & l1->m_Grammems & l2->m_Grammems) > 0) && ((rAllGenders & l1->m_Grammems & l2->m_Grammems) > 0); }; bool CaseNumberGender0(const CAgramtabLine* l1, const CAgramtabLine* l2) //with absent grammems check { return ((rAllCases & l1->m_Grammems & l2->m_Grammems) > 0 || !(rAllCases & l1->m_Grammems) || !(rAllCases & l2->m_Grammems)) && ((rAllNumbers & l1->m_Grammems & l2->m_Grammems) > 0 || !(rAllNumbers & l1->m_Grammems) || !(rAllNumbers & l2->m_Grammems)) && ((rAllGenders & l1->m_Grammems & l2->m_Grammems) > 0 || !(rAllGenders & l1->m_Grammems) || !(rAllGenders & l2->m_Grammems)); ; }; bool GenderNumber0(const CAgramtabLine* l1, const CAgramtabLine* l2) //with absent grammems check { return ((rAllGenders & l1->m_Grammems & l2->m_Grammems) > 0 || !(rAllGenders & l1->m_Grammems) || !(rAllGenders & l2->m_Grammems)) && ((rAllNumbers & l1->m_Grammems & l2->m_Grammems) > 0 || !(rAllNumbers & l1->m_Grammems) || !(rAllNumbers & l2->m_Grammems)); }; bool CaseNumber0(const CAgramtabLine* l1, const CAgramtabLine* l2) //with absent grammems check { return ((rAllCases & l1->m_Grammems & l2->m_Grammems) > 0 || !(rAllCases & l1->m_Grammems) || !(rAllCases & l2->m_Grammems)) && ((rAllNumbers & l1->m_Grammems & l2->m_Grammems) > 0 || !(rAllNumbers & l1->m_Grammems) || !(rAllNumbers & l2->m_Grammems)); ; }; bool CRusGramTab::PartOfSpeechIsProductive(part_of_speech_t p) const { return p == NOUN || p == ADJ_FULL || p == VERB || p == ADV || p == INFINITIVE; }