/******************************************************************* Именем таблицы в данном случае является целое неотрицательное число в десятеричной системе счисления. ********************************************************************/ void SG_DeclensionTable::LoadName( Macro_Parser &txtfile, Dictionary &dict ) { const BethToken& t = txtfile.read(); key = ANY_STATE; // Формат: // paradigma Условное_Имя, Алиас1, ... : name = t.string(); names.push_back(name); key = ANY_STATE; while( !txtfile.eof() && txtfile.pick().GetToken()==B_COMMA ) { txtfile.read_it(B_COMMA); names.push_back( txtfile.read().string() ); } txtfile.read_it(B_COLON); if( dict.GetDebugLevel_ir()>=3 ) { dict.GetIO().mecho().printf( "%us [%vfE%us%vn]->", sol_get_token(B_PARADIGMA).c_str(), GetName().c_str() ); } return; }
/******************************************************************** Загрузка описания Статьи из текстового файла *********************************************************************/ void Form_Table::LoadTxt( Macro_Parser &txtfile, Grammar& gram, bool IsRealized ) { is_realized = IsRealized; iclass = UNKNOWN; LoadName(txtfile, gram.GetDict()); if (iclass == UNKNOWN) // если в LoadName еще не прочитали информацию о принадлежности к грамматическому классу... { const BethToken class_name = txtfile.read(); if ((iclass = gram.FindClass(class_name.string())) == UNKNOWN) { // Не найден класс, заявленный для статьи Print_Error(class_name, txtfile); gram.GetIO().merr().printf( "The class [%us] is not previously declared in grammar\n" , class_name.c_str() ); throw E_ParserError(); } } LoadBody(txtfile, gram); Loaded(gram.GetDict()); return; }
/******************************************************************** Читаем из текстового файла секции расширенного описания статьи. Под расширенным описанием подразумевается список координат-атрибутов, формы, грамматическая сеть и специфические для производных классов поля. *********************************************************************/ void Base_Entry::LoadTxtEx( Macro_Parser& txtfile, Grammar& gram ) { // *** Считываем описание статьи *** bool looping = true; BethToken token; CP_Array common; while (looping) { if (txtfile.eof()) { Print_Error(txtfile); gram.GetIO().merr().printf("End of file has been reached before entry body completely loaded\n"); throw E_ParserError(); } const BSourceState back = txtfile.tellp(); token = txtfile.read(); if (token.GetToken() == B_CFIGPAREN) { // Описание статьи закончено looping = false; break; } if (token.GetToken() == B_OTRIPAREN) { txtfile.seekp(token.GetBegin()); SkipNetSection(txtfile, gram); continue; } if (ProcessSection(txtfile, gram, token)) continue; txtfile.seekp(back); if (LoadAttribute(txtfile, gram)) continue; // Загружаем словоформу. LoadForm( txtfile, gram, common, GramCoordAdr(UNKNOWN, UNKNOWN), UNKNOWN, GramCoordAdr(UNKNOWN, UNKNOWN), UNKNOWN, UNKNOWN ); } // конец цикла считывания описания статьи return; }
void SG_DeclensionForm::ReadAdditionalInfo( Grammar &gram, const SG_DeclensionTable &table, Macro_Parser& txtfile ) { // :: flexer рег_выражение for регулярное_выражение while( !txtfile.eof() ) { BethToken t = txtfile.read(); if( t==B_FOR ) { UFString re = strip_quotes( txtfile.read().string() ).c_str(); if( table.GetClass()!=UNKNOWN ) { const SG_Class &cls = (const SG_Class&)gram.classes()[ table.GetClass() ]; const int id_lang = cls.GetLanguage(); if( id_lang!=UNKNOWN ) { const SG_Language &lang = gram.GetDict().GetSynGram().languages()[id_lang]; lang.SubstParadigmPattern(re); } } condition_str = re; condition = boost::wregex( re.c_str(), boost::basic_regex<wchar_t>::icase ); valid_condition = true; } else if( t==B_FLEXER ) { UFString re = strip_quotes( txtfile.read().string() ).c_str(); flexer_flags_str = re; flexer_flags = boost::wregex( re.c_str(), boost::basic_regex<wchar_t>::icase ); valid_flexer_flags = true; } else { txtfile.seekp(t); break; } } return; }
void LA_PhoneticCondictor::LoadTxt( Macro_Parser &txtfile, GraphGram &gram ) { txtfile.read_it(B_CONTEXT); const BethToken t = txtfile.read(); context = t.string(); context.strip_quotes(); // Каждый символ из строки должен быть известен как буква - то есть // быть определен через Алфавит. Допускается также специальный // кванторный символ '*'. // // В двух случаях допускается применение символа $ - для требования на // размещение символов: "$aaa" - приставка, "aaa$" - аффикс. if( context.front()==L'$' ) { loc = PREFIX; context.Remove(0); } else if( context.back()==L'$' ) { loc = AFFIX; context.Remove( context.length()-1 ); } else loc = UNLOCATED; const int cl=context.length(); for( int i=0; i<cl; i++ ) { const wchar_t ch = context[i]; if( ch==L'*' ) continue; const Word_Coord wc = gram.FindSymbol(ch); if( wc.GetEntry()==UNKNOWN ) { lem::Iridium::Print_Error( t, txtfile ); gram.GetIO().merr().printf( "Condictor [%us] contains unknown symbol (neither " "char nor quantor '*')\n" , context.c_str() ); throw E_ParserError(); } context.set( i, gram.entries()[wc.GetEntry()].GetName() ); } return; }
void Form_Table::LoadBody(Macro_Parser &txtfile, Grammar& gram) { txtfile.read_it(B_OFIGPAREN); // *** Считываем описание Таблицы *** BethToken token; CP_Array common; FOREVER { if (txtfile.eof()) { Print_Error(txtfile); gram.GetIO().merr().printf("End of file has been reached before entry body completely loaded\n"); throw E_ParserError(); } const BSourceState back = txtfile.tellp(); token = txtfile.read(); if (token.GetToken() == B_CFIGPAREN) { // Описание Таблицы закончено. break; } if (ProcessSection(txtfile,gram,token)) continue; txtfile.seekp(back); if (LoadAttribute(txtfile,gram)) continue; LoadForm( txtfile, gram, common, GramCoordAdr(UNKNOWN,UNKNOWN), UNKNOWN, GramCoordAdr(UNKNOWN,UNKNOWN), UNKNOWN, UNKNOWN ); // Загружаем словоформу. } // конец цикла считывания описания статьи return; }
/**************************************************************************** Загружаем из текстового файла множество символьных строк. Если слово только одно, то оно может идти непосредственно. Если необходимо определить несколько слов, то они заключаются в фигурные скобочки. Форматы: 1. лексема 2. { лексема лексема ... лексема } Второй формат охватывает также и первый, если в фигурных скобочках указать только одну лексему. Способ хранения в обоих случаях одинаков! *****************************************************************************/ void UCStringSet::LoadTxt( const Sol_IO &io, Macro_Parser &txtfile ) { BethToken t = txtfile.read(); if( t.GetToken()!=B_OFIGPAREN ) { // Первый формат. push_back(t.c_str()); } else { // Второй формат. while( !txtfile.eof() ) { if( txtfile.eof() ) { Print_Error(t,txtfile); io.merr().printf( "End of file has been reached before " "set of lexems completely loaded\n" ); LEM_STOPIT; } t = txtfile.read(); if( t.GetToken()==B_CFIGPAREN ) break; push_back(t.string()); weight.push_back(1); } } return; }
/********************************************************** Загрузка тела описания статьи из текстового файла Словаря. Само тело состоит из нескольких факультативных частей. ***********************************************************/ void Base_Entry::LoadBody( Macro_Parser &txtfile, Grammar& gram ) { if (is_realized) { // Если теперь встретится '{', то значит имеем расширенное // описание словарной статьи. const BSourceState prefig = txtfile.tellp(); const BethToken isfig = txtfile.read(); #if LEM_DEBUGGING==1 int nf = CountForms(); #endif if (isfig.GetToken() != B_OFIGPAREN) txtfile.seekp(prefig); else LoadTxtEx(txtfile, gram); if (CountForms() == 0) BeforeFirstForm(gram); CheckAttr(txtfile, gram); } #if defined SOL_DETAILED if (gram.GetDict().GetDebugLevel_ir() >= 3) { // Эхо-сообщение: закончили трансляцию статьи. gram.GetIO().mecho().printf("Ok\n"); } #endif return; }
/************************************************************************** ЗАГРУЗКА ОДНОЙ АТРИБУТНОЙ КООРДИНАТНОЙ ПАРЫ из текстового файла Общий формат: коорд_имя : состояние Особое внимание следует уделять автоматическому созданию AND-атрибутов для многоохватных состояний. Если такое создание нежелательно, то следует заключить имя состояния, входящего в группу многоохватных, в круглые скобочки: коор_имя : ( состояние ) ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: true - действительно, загружен атрибут или тэг. false - это не определение состояния атрибута или тэга. ****************************************************************************/ bool Form_Table::LoadAttribute( Macro_Parser &txtfile, Grammar& gram ) { const BSourceState back = txtfile.tellp(); bool negative_state = txtfile.probe(B_NEGATIVE); // считываем префикс в ~ПРИЧАСТИЕ BethToken coord_name = txtfile.read(); // Индекс координаты в списке грамматики. const GramCoordAdr iglob = gram.FindCoord(coord_name.string()); // Найдем атрибут в списке грамматического класса. const int iattr = gram.classes()[iclass].attrs().FindTwice(iglob); if (iattr == UNKNOWN) { const int itag = gram.classes()[iclass].tags().FindTwice(iglob); if (itag == UNKNOWN) { txtfile.seekp(back); return false; } } // Если координата имеет два неявно объявленных состояния // TRUE/FALSE, то состояние явно в данной секции не должно быть // указано. if (!gram.coords()[iglob.GetIndex()].IsBistable()) { // Несколько состояний у координаты. if (negative_state) { Print_Error(back, txtfile); gram.GetIO().merr().printf("~ is appliable to bistable coordinates only, whereas [%us] is not bistable\n", coord_name.c_str()); throw E_ParserError(); } txtfile.read_it(B_COLON); // Учтем, что может встретиться AND-атрибут. Такая координата // одновременно может иметь несколько состояний. IntCollect statei; IntCollect doload; FOREVER { if (txtfile.eof()) { Print_Error(txtfile); gram.GetIO().merr().printf("End of file has been reached before list of attribute states in entry completely loaded\n"); throw E_ParserError(); } // Теперь считаем состояние(-я) для заявленного атрибута. const BSourceState back = txtfile.tellp(); BethToken state_name = txtfile.read(); bool letautoload = true; if (state_name.GetToken() == B_ANY) { if (StoreQuantors()) { attr.push_back(GramCoordPair(iglob,ANY_STATE)); break; } else if (statei.empty()) { // Вместо имен состояний для AND-координаты указан квантор *. // Инициализируем координату ВСЕМИ состояниями, заявленными // для координаты. const int ns = gram.coords()[iglob.GetIndex()].GetTotalStates(); for (int i = 0; i < ns; i++) attr.push_back(GramCoordPair(iglob,i)); // Продолжать дальше считывание не имеет смысла. break; } } if (!statei.empty()) { // Если это запятая, то список AND-состояний продолжается. // в противном случае прерываем загрузку состояний. if (state_name.GetToken() != B_COMMA) { txtfile.seekp(back); break; } else state_name = txtfile.read(); } // Если имя атрибута заключено в круглые скобочки, то // для координатной пары запрещено автоматическое создание. if (state_name.GetToken() == B_OROUNDPAREN) { state_name = txtfile.read(); txtfile.read_it(B_CROUNDPAREN); letautoload = false; } // Ищем индекс состояния в координате const int istate = gram.coords()[iglob.GetIndex()].FindState(state_name.string()); if (istate == UNKNOWN) { Print_Error(state_name,txtfile); gram.GetIO().merr().printf( "State [%us] is not declared for coordinate [%us]\n" , state_name.c_str(), coord_name.c_str() ); throw E_ParserError(); } // Добавляем глобальный индекс атрибута и индекс его состояния // к нашим спискам. statei.push_back(istate); doload.push_back(letautoload); } // Состояния, которые объявлены для атрибута, превратим // в список координатных пар и добавим к своему списку // атрибутов статьи. lem::Container::size_type ils; for (ils = 0; ils < statei.size(); ils++) attr.push_back(GramCoordPair(iglob, statei[ils])); // Автоматически подключим те состояния, которые не запрещены // для этого пользователем, не объявлены и входят в подгруппу. const GramCoord& c = gram.coords()[iglob.GetIndex()]; IntCollect attaches; // Автоматически созданные и присоединяемые состояния for (ils = 0; ils < statei.size(); ils++) if (doload[ils]) { int ibase = statei[ils]; // Входит ли состояние в группу многоохватных как главное? if (c.IsHeadState(ibase)) { // Да, входит. // Получаем список состояний, входящих в группу. const IntCollect to_attach = c.GetSubgroupIndeces(c.GetSubgroup(ibase)); for (Container::size_type ia = 1; ia < to_attach.size(); ia++) { const int state_attach = to_attach.get(ia); // Очередное состояние из группы многоохватных // Посмотрим, можно ли присоединять состояние // iglob:state_attach. // // Противопоказания могут быть следующие. // // 1. Состояние уже присутствует в списке statei. // 2. Состояние уже автоматически создано и // добавлено в список attaches. // // 3. Координатная пара уже загружена в списки // статьи. bool already_loaded = false; if (attr.FindOnce(GramCoordPair(iglob, state_attach)) != UNKNOWN) already_loaded = true; if ( !already_loaded && find(statei, state_attach) == UNKNOWN && find(attaches, state_attach) == UNKNOWN ) attaches.push_back(state_attach); // К списку присоединяемых } } } if (!attaches.empty()) // Есть присоединяемые? { // Необходимо предупредить пользователя об автоматически // присоединяемых состояниях. lem::LogFile::logfile->printf("\nCoordinate pairs were autocreated for a form table:"); PrintName(*lem::LogFile::logfile); lem::LogFile::logfile->printf(" ->"); for (Container::size_type ils = 0; ils < attaches.size(); ils++) { if (ils) lem::LogFile::logfile->printf(","); lem::LogFile::logfile->printf( " %us%us%us ", c.GetName().string().c_str(), sol_get_token(B_COLON).c_str(), c.GetStateName(attaches[ils]).c_str() ); attr.push_back(GramCoordPair(iglob, attaches[ils])); } lem::LogFile::logfile->eol(); } } else { // Добавляем глобальный индекс атрибута и индекс его состояния // к нашим спискам, учитывая, что сам факт появления атрибута // с неявными состояниями TRUE/FALSE означает его состояние TRUE. // Если был префикс ~, то состояние присваиваем FALSE. // Есть один особый случай, когда для бистабильной координаты задается // состояние - для грамматических кванторов. В этом случае имя состояния // обязательно квантор * if (StoreQuantors())
void Word_Form::LoadPreciser( CompilationContext &context, Macro_Parser& txtfile, SynGram& gram, int iclass ) { // Тапереча в {} могет быть идти список уточняющих координат. // // Каждая уточняющая координата должна следовать такому формату: // // [~]имя_координаты:имя_состояния // // Причем, только если вместо имени статьи указан квантор всеобщности, // то разрешается задавать АТРИБУТЫ как координаты. // // Особо обрабатываются координаты с неявно объявленными состояниями // TRUE/FALSE. Следует учесть, что само упоминание имени такой координаты // равносильно упоминанию также и имени состояния TRUE, а для объявлени // состояния FALSE необходимо использовать конструкцию с оператором // отрицания НЕ. while(!txtfile.eof()) { // Считываем имя координаты. BethToken coord_name = txtfile.read(); // Может, список закончился, то есть встретилась '{' ? if( coord_name.GetToken()==B_CFIGPAREN ) break; // В двойных апострофах может идти имя формы, которую надо использовать вместо // имени словарной статьи. if( lem::in_quotes(coord_name.string()) ) { Lexem *mname = new Lexem( strip_quotes(coord_name) ); gram.GetDict().GetLexAuto().TranslateLexem(*mname,false); mname->Translate( gram.GetDict().GetGraphGram(), 2 ); name = RC_Lexem( mname ); } else { bool AFFIRM=true; if( coord_name.GetToken()==B_NEGATIVE ) { // Оператор отрицания перед определением координаты! AFFIRM=false; coord_name = txtfile.read(); } const GramCoordAdr iglob_coord = gram.FindCoord(coord_name.string()); // Попытаемся найти координату среди списка атрибутов и тэгов. int iloc_coord = gram.classes()[iclass].attrs().find(iglob_coord); // Нашли? if( iloc_coord!=UNKNOWN ) { // Да! Примем к сведению, что если для опорной точки задано // имя словарной статьи, то мы не имеем право по логике вещей // определять также и атрибуты, так как само определение словарной // статьи определяет необходимые атрибуты. if( entry_key!=ANY_STATE ) { lem::Iridium::Print_Error(coord_name,txtfile); gram.GetIO().merr().printf( "The attribute can not be declared here, because entry is already declared\n" ); throw E_ParserError(); } } else { // Попробуем найти координату среди списка измерений. iloc_coord = gram.classes()[iclass].dims().find(iglob_coord); if( iloc_coord==UNKNOWN ) iloc_coord = gram.classes()[iclass].tags().find(iglob_coord); // Нашли? if( iloc_coord==UNKNOWN && iclass!=SOL_EQUIL_INDEX ) { // Нет. Таким образом, имя координаты не определяет // ни тэг, ни измерение. Генерируем сообщение // об ошибке. lem::Iridium::Print_Error(coord_name,txtfile); gram.GetIO().merr() .printf( "Coordinate [%us] is neither tag" " nor dimention for the class [%us]\n" , coord_name.string().c_str() , gram.classes()[ iclass ].GetName().c_str() ); throw E_ParserError(); } } /*------------------------------------------------------------------------- Теперь считываем определение состояния. В некоторых случаях допускается такой формат записи: имя_координаты:=индекс Обычно так указываются те состояния, которые имеет данная координата у заданной индексом опорной точки контекста. Внутреннее описание в этом случае отличается от обычного лишь тем, что состояние имеет знак минус и хранит на самом деле числовое значение индекса минус единица, так что состояние -1 означает опорную точку 0, и так далее. Это сделано, чтобы корректно отличать случай состояния с нулевым индексом. -------------------------------------------------------------------------*/ int istate; const BSourceState back = txtfile.tellp(); if( txtfile.read().GetToken()==B_COLON && txtfile.read().GetToken()==B_EQUAL ) istate = -txtfile.read_int()-1; // Да, это формат ИМЯ_КООРД:=ИНДЕКС else { txtfile.seekp(back); // Является ли она бистабильной? if( gram.coords()[iglob_coord.GetIndex()].states().empty() ) { // Да - считывать имя состояния не надо. istate=AFFIRM; } else { // Индекс состояния у найденной координаты. txtfile.read_it(B_COLON); const BethToken state_name = txtfile.read(); istate = gram.coords()[iglob_coord.GetIndex()].FindState(state_name.string()); if( istate==UNKNOWN ) { lem::Iridium::Print_Error(state_name,txtfile); gram.GetIO().merr().printf( "State [%us] is not declared for coordinate [%us]\n" , state_name.c_str(), coord_name.c_str() ); throw E_ParserError(); } } } pair.push_back(GramCoordEx(iglob_coord,istate,AFFIRM)); } } // конец цикла считывания уточненных координат return; }
/****************************************************************** Считывание описание узла BETH-дерева из текстового файла Словаря. *******************************************************************/ void Word_Form::LoadTxt( CompilationContext &context, Macro_Parser &txtfile, SynGram &gram ) { val=Real1(100); score=0; iversion = seq_iversion++; // Сначала считываем определение класса и имя словарной статьи. const BethToken class_name = txtfile.read(); entry_key=UNKNOWN_STATE; int iclass; // Если считанная лексема заключена в апострофы, то имеем дело // с сокращенным форматом: ?:строка. Этот формат применяется дл // описания лексемы, принадлежность которой к какому-либо классу // не очевидна или не важна, а важно лексическое представление. if( in_apostrophes(class_name.string()) ) { name = RC_Lexem( new Lexem(strip_quotes(class_name.string())) ); return; } if( class_name.string()==SOL_UNKNOWN_ENTRY_NAME ) { // Только одна статья принадлежит особому классу UNKNOWN! // Эта статья может быть описана только как "?:?" if( txtfile.read().string()==sol_get_token(B_COLON) && txtfile.read().string()==sol_get_token(B_UNKNOWN) ) { const Word_Coord iuu = gram.FindEntryForm( class_name.string() ); const SG_Entry& euu = gram.GetEntry(iuu.GetEntry()); iclass=UNKNOWN_STATE; entry_key = euu.GetKey(); return; } } // Пытаемся найти имя синтаксического класса в списке // уже загруженных в Словаре для синтаксической грамматики. if( (iclass=gram.FindClass(class_name.string()))==UNKNOWN ) { // Класс не определен. // // Предполагаем, что задано лексическое содержимое некоторой // словоформы. Если такая словоформа лексически уникальна, // то мы сами можем восстановить пару класс:статья. В случае // множественности вариантов тяжесть ответственности ложитс // на пользователя. Word_Coord ie = gram.FindEntryForm( class_name.string() ); if( ie.GetEntry()==UNKNOWN ) { // Выводим сообщение о неверном имени синтаксического класса или // ненайденной словоформе. lem::Iridium::Print_Error(class_name,txtfile); gram.GetIO().merr().printf("Neither a class previously declared in grammar, nor an entry form\n"); throw E_ParserError(); } if( ie.GetEntry()!=UNKNOWN ) { // Словоформа найдена! const SG_Entry& ef = gram.GetEntry(ie.GetEntry()); entry_key = ef.GetKey(); // Вероятно, следует также переслать координатные пары. const SG_EntryForm& eef = ef.forms()[ ie.GetForm() ]; const CP_Array& dims = eef.coords(); for( Container::size_type ii=0; ii<dims.size(); ii++ ) { // Здесь немного наворочено - прямо использовать конструктор без // копирования в промежуточные поля нельзя из-за ошибки в // кодогенераторе Symantec C++ (появляется General Protection Fault). const GramCoordAdr ca = dims[ii].GetCoord(); const int cs = dims[ii].GetState(); pair.push_back( GramCoordEx( ca, cs, true ) ); } // И наконец, пересылаем полное имя (лексическое содержимое) статьи. // icenter=0; // e_list.push_back( entry_key ); name = RC_Lexem( const_cast<Lexem*>(&ef.GetName()), null_deleter() ); } return; } const BSourceState back=txtfile.tellp(); const BethToken t = txtfile.read(); bool read_ofigparen=true; if( t.GetToken()==B_COLON ) { // Считываем имя статьи, которое может в общем случае состоять // из нескольких лексем. Признаком окончания имени служит // открывающая фигурная скобка '{'. Lexem *mname = new Lexem( sol_read_multyname( gram.GetIO(), txtfile,B_OFIGPAREN) ); // Преобразуем в мультилексему так, чтобы правильно распознавались // объявления имен типа "ЕЩ^Ё". gram.GetDict().GetLexAuto().TranslateLexem(*mname,false); mname->Translate( gram.GetDict().GetGraphGram(), 2 ); //(*name) = mname; name = RC_Lexem( mname ); // lexem_owner.resize(1); // lexem_owner.Nullify(); read_ofigparen=false; // Пытаемся найти статью. if( *mname != sol_get_token(B_ANY) ) { // Считан НЕ квантор всеобщности, так что это должно быть имя статьи. // Попытаемся найти статью среди уже загруженных, причем ищем с // критерием принадлежности определенному синтаксическому классу. const int ientry=gram.FindEntry2(*mname,iclass); // Нашли ? if( ientry==UNKNOWN ) { // Нет! Выводим сообщение об неверном имени словарной статьи. lem::Iridium::Print_Error(txtfile); gram.GetIO().merr().printf( "The entry [%us:%us] is not previously declared in grammar\n" , gram.classes()[iclass].GetName().c_str() , mname->ToString().c_str() ); throw E_ParserError(); } // Запомним КЛЮЧ словарной статьи. entry_key=gram.GetEntry(ientry).GetKey(); } else entry_key=ANY_STATE; } else { txtfile.seekp(back); entry_key=ANY_STATE; } bool load_precise=true; if( read_ofigparen ) { const BSourceState back = txtfile.tellp(); if( txtfile.read().GetToken()!=B_OFIGPAREN ) { // Секции уточнения координат нет. txtfile.seekp(back); load_precise = false; } } if(load_precise) LoadPreciser(context,txtfile,gram,iclass); return; }
/************************************************************************ Собственно, загрузка содержимого тела секции Автомата. Дабы позволить производным классам автоматов разпознавать и загружать свои собственные структуры данных сверх того, что распознает и загружает наш класс, вызывается виртуальный метод ProcessLexem. *************************************************************************/ void Automaton::load( Macro_Parser &txtfile, const Binarization_Options &options ) { bool looping=true; while( looping ) { if( txtfile.eof() ) { Print_Error(txtfile); GetIO().merr().printf( "End of file has been reached before Automaton [%us] section completely loaded\n" , GetName().c_str() ); throw E_ParserError(); } const BethToken t=txtfile.read(); if( !ProcessLexem(t,txtfile,options) ) { switch(t.GetToken()) { case B_CRITERION: if( param!=NULL ) param->LoadTxt( GetIO(), txtfile ); break; case B_CFIGPAREN: looping=false; break; default: { const BSourceState back=txtfile.tellp(); if( param!=NULL ) { if( txtfile.read().GetToken()==B_EQUAL ) { txtfile.seekp( t.GetBegin() ); param->LoadTxt(GetIO(),txtfile); break; } } else { LEM_STOPIT; } txtfile.seekp(back); // Нераспознанная лексема. GetIO().merr().printf( "\nIncorrect lexem [%us]\n", t.string().c_str() ); Print_Error(t,txtfile); throw E_ParserError(); } } } } return; }
SG_calibrator::SG_calibrator(const lem::UCString & keyword, const SynGram &sg, const Sol_IO &io, Macro_Parser &txtfile) { if (keyword.eqi(L"wordentry_freq")) freq_type = WordEntryFreq; else if (keyword.eqi(L"wordform_score")) freq_type = WordFormScore; else if (keyword.eqi(L"wordforms_score")) freq_type = WordFormsScore; id_class = UNKNOWN; freq = 0; word = txtfile.read().string(); word.strip(L'"'); // если далее идет открывающая фигурная скобка, то значит конкретизируется словоформа (или несколько // словоформ). if (txtfile.probe(B_OFIGPAREN)) { while (!txtfile.eof()) { if (txtfile.pick().GetToken() == B_CFIGPAREN) { txtfile.read(); break; } // для обычных: координата:состояние // для бистабильных: координата lem::Iridium::BethToken coord_name = txtfile.read(); if (id_class == UNKNOWN) { const int id_class0 = sg.FindClass(coord_name); if (id_class0 != UNKNOWN) { id_class = id_class0; continue; } } bool AFFIRM = true; if (coord_name.GetToken() == B_NEGATIVE) { // Оператор отрицания перед определением координаты! AFFIRM = false; coord_name = txtfile.read(); } const GramCoordAdr iglob_coord = sg.FindCoord(coord_name.string()); if (!iglob_coord.IsDefined()) { sg.GetIO().merr().printf("Unknown coordinate %us\n", coord_name.c_str()); lem::Iridium::Print_Error(coord_name, txtfile); throw lem::E_BaseException(); } if (sg.coords()[iglob_coord.GetIndex()].IsBistable()) { // Имя состояния не может быть указано. coords.push_back(GramCoordPair(iglob_coord, AFFIRM)); } else { // После двоеточия должно идти имя состояния для координаты. txtfile.read_it(B_COLON); // Имя состояния. BethToken state_name = txtfile.read(); // Получим индекс состояния для определенной координаты. const int istate = sg.coords()[iglob_coord.GetIndex()] .FindState(state_name.string()); if (istate == UNKNOWN) { // Нет такого состояния для этого измерения. lem::Iridium::Print_Error(state_name, txtfile); sg.GetIO().merr().printf( "State [%vfE%us%vn] is not declared for coordinate [%vfE%us%vn]\n" , state_name.c_str(), coord_name.c_str() ); throw E_ParserError(); } coords.push_back(GramCoordEx(iglob_coord, istate, AFFIRM)); } } } txtfile.read_it(B_EQUAL); if (txtfile.probe(B_SUB)) freq = -txtfile.read_int(); else freq = txtfile.read_int(); return; }
void SG_ComplexLink::LoadPoint( Macro_Parser &txtfile, SynGram &gram, lem::UFString &entry ) { BethToken t = txtfile.read(); if( t.GetToken()==B_ENTRY ) { // Особый формат entry Класс:Статья { уточнение } // преобразуется в ключ статьи и возвращается в виде #ключ UCString class0 = txtfile.read().string(); const int ic0 = class0==L"?" ? ANY_STATE : gram.FindClass(class0); if( ic0==UNKNOWN ) { Print_Error( txtfile ); gram.GetIO().merr().printf( "Unknown class %us\n", class0.c_str() ); throw E_BaseException(); } txtfile.read_it( B_COLON ); UCString entry0 = sol_read_multyname( gram.GetIO(), txtfile, B_OFIGPAREN ); entry0.strip(L'"'); entry0.trim(); // Может быть задана дополнительная фильтрующая координата Solarix::CP_Array coords0; coords0.LoadTxt( txtfile, gram ); if( gram.IsOmonym(ic0,lem::to_upper(entry0)) && coords0.empty() ) { Print_Error( txtfile ); gram.GetIO().merr().printf( "Omonym %us:%us requires the coordinate array\n", class0.c_str(), entry0.c_str() ); throw E_BaseException(); } const int ie0 = coords0.empty() ? gram.FindEntry(entry0,ic0,false) : gram.FindEntryOmonym(entry0,ic0,coords0); if( ie0==UNKNOWN ) { Print_Error( txtfile ); gram.GetIO().merr().printf( "Unknown entry %us:%us\n", class0.c_str(), entry0.c_str() ); throw E_BaseException(); } const int ekey = gram.GetEntry(ie0).GetKey(); entry = lem::format_str( L"#%d", ekey ); return; } bool figparen = t.GetToken()==B_OFIGPAREN; if( !figparen ) txtfile.seekp(t); entry.reserve(128); if( t.string()==L'@' ) { entry = L'@'; t = txtfile.read(); } while( !txtfile.eof() ) { BethToken t = txtfile.read(); if( figparen && t.GetToken()==B_CFIGPAREN ) break; if( !entry.empty() ) entry.Add_Dirty(L' '); UFString ts( t.GetFullStr() ); ts.strip(L'"'); entry.Add_Dirty( ts ); if( !figparen ) break; } entry.calc_hash(); if( entry.front()==L'@' ) { // Спецсимвол @ заставляет запомнить строку в виде "как есть" entry.remove(0); entry.trim(); } else { entry.strip(L'"'); gram.GetDict().GetLexAuto().TranslateLexem(entry,true); } return; }
void SG_Language::LoadTxt(int Id, Macro_Parser& txt, GraphGram& gram) { // Store the beginning of language specification BSourceState beg = txt.tellp(); id = Id; name = txt.read().string(); const bool Me = gram.GetDict().GetDebugLevel_ir() >= 3; if (Me) { // Эхо-сообщение: начали трансляцию языка. gram.GetIO().mecho().printf( "%us [%vfE%us%vn]->", sol_get_token(B_LANGUAGE).c_str(), name.c_str() ); } BethToken t = txt.read(); if (t.GetToken() == B_AS) { c_name = txt.read().string(); t = txt.read(); } if (t.GetToken() != B_OFIGPAREN) { // Пустое объявление языка. txt.seekp(t.GetBegin()); } else { // Load the list of alphabets, allowed for the language. Also do load other // language parameters. while (!txt.eof()) { BethToken t = txt.read(); if (t.GetToken() == B_CFIGPAREN) break; if (t.GetToken() == B_ALPHABET) { // Add the valid alphabet name for this language BethToken abc_name = txt.read(); int id_abc = gram.Find_Alphabet(abc_name.string()); if (id_abc == UNKNOWN) { lem::Iridium::Print_Error(abc_name, txt); gram.GetIO().merr().printf("Unknown alphabet [%us] used in in language [%us] specification\n", abc_name.string().c_str(), name.c_str()); throw E_ParserError(); } alphabet.push_back(id_abc); continue; } else if (t.GetToken() == B_LINK) { Tree_Link l; l.LoadTxt(txt, gram.GetDict().GetSynGram()); txt.read_it(B_LANGUAGE); BethToken lang_name = txt.read(); int id_lang = gram.GetDict().GetSynGram().Find_Language(lang_name); if (id_lang == UNKNOWN) { lem::Iridium::Print_Error(lang_name, txt); gram.GetIO().merr().printf("Unknown language [%us] used in in language [%us] specification\n", lang_name.string().c_str(), name.c_str()); throw E_ParserError(); } lang_links.push_back(std::make_pair(l, id_lang)); continue; } else { // Синтаксис задания параметра: // 1. скалярный param_name = value // 2. векторный param_name = { value1 values2 ... } if (txt.pick().GetToken() == B_EQUAL) { txt.read_it(B_EQUAL); SG_LanguageParam *param = new SG_LanguageParam; param->name = t; if (txt.pick().GetToken() == B_OFIGPAREN) { txt.read_it(B_OFIGPAREN); while (!txt.eof()) { if (txt.pick().GetToken() == B_CFIGPAREN) { txt.read_it(B_CFIGPAREN); break; } UFString v = txt.read().GetFullStr(); v.strip(L'"'); v.trim(); param->values.push_back(v); } } else { param->values.push_back(lem::trim(lem::UFString(txt.read().GetFullStr()))); } params.push_back(param); continue; } } lem::Iridium::Print_Error(t, txt); gram.GetIO().merr().printf("Invalid token in language [%us] specification\n", name.c_str()); throw E_ParserError(); } } if (Me) { // Эхо-сообщение: закончили трансляцию. gram.GetIO().mecho().printf("%vfAOK%vn\n"); } return; }
/************************************************************************* ЗАГРУЗКА ОПИСАНИЯ ИЗ ТЕКСТОВОГО ФАЙЛА 1. Общий формат: 1.1 Заголовок enum имя, синоним1, синоним2, ... Кроме основного имени можно устанавливать альтернативные имена координаты (синонимы). Это необходимо для работы с некоторыми просторечными конструкциями (типа слова 'ЕГОННЫЙ'). Имя координаты должно начинаться с буквы или символа '_'. 1.2 Список состояний (два взаимоисключающих случая): ... = имя_источника - таким способом координата [имя] получает тот же список состояний, что и заявленые для [имя_источник]. ... { сост1 сост2 ... состN } - в фигурных скобочках перечисляются имена состояний. 2. Один из особых случаев - координаты с двумя состояниями, представимыми по смыслу как TRUE и FALSE. Формат описани их несколько иной. Объявление имеет такой формат: : enum имя_координаты : То есть имена состояний явно не объявляются. Внутреннее описание также не загружается подставными именами состояний, но при операциях с координатами появление координаты с нулевым количеством состояний отлавливается и особо учитывается. **************************************************************************/ void GramCoord::LoadTxt( Macro_Parser &txtfile, const Grammar& gram, bool IsRealized ) { is_realized = IsRealized; BethToken coord_name = txtfile.read(); sol_check_coord_name(gram.GetDict(), txtfile, coord_name); name.push_back(coord_name.c_str()); const bool Me = gram.GetDict().GetDebugLevel_ir() >= 3; if (Me) { // Эхо-сообщение: начали трансляцию координаты. gram.GetIO().mecho().printf( "%us [%vfE%us%vn]->", sol_get_token(B_COORDINATE).c_str(), name.get(0).c_str() ); } BSourceState back = txtfile.tellp(); bool cname_loaded = false; if (txtfile.read().GetToken() == B_AS) { c_name = txtfile.read(); back = txtfile.tellp(); cname_loaded = true; } else txtfile.seekp(back); // Цикл загрузки компонентов описания координаты. bool loading = true; while (loading) { const BethToken t1 = txtfile.read(); switch (t1.GetToken()) { case B_EQUAL: { // Встретили спецификацию '='. Так что пересылаем себе состояния // другой координаты, имя которой идёт следом. const BethToken another = txtfile.read(); const GramCoordAdr ianother = gram.FindCoord(another.string()); if (ianother.GetIndex() == UNKNOWN) { Print_Error(another, txtfile); MemFormatter f; f.printf( "The coordinate [%us] is not previously " "declared in grammar\n" , another.c_str() ); throw E_Solarix(f.string().c_str()); } state = gram.coords()[ianother.GetIndex()].state; // Пересылаем себе состояния #if defined SOL_COMPILER // Очищаем C-имена состояний for (lem::Container::size_type i = 0; i < state.size(); ++i) { state[i].Clear_API_Names(); } #endif loading = false; // Больше считывать нечего break; } case B_COMMA: { // Через запятую идут синонимы имени координаты. const BethToken t2 = txtfile.read(); sol_check_s_name(gram.GetDict(), txtfile, t2, true); if (name.Find(t2.c_str()) != UNKNOWN) { Print_Error(t2, txtfile); MemFormatter f; f.printf("Duplication of the name in coordinate [%us] declaration\n", t2.c_str()); throw E_Solarix(f.string().c_str()); } name.push_back(t2.c_str()); break; } case B_OFIGPAREN: { // В фигурных скобочках перечислены возможные состояния координаты. while (!txtfile.eof()) { const BSourceState back2 = txtfile.tellp(); // Если это '}', то список атрибутов завершен. if (txtfile.read().GetToken() == B_CFIGPAREN) break; txtfile.seekp(back2); GramCoordState dummy; dummy.LoadTxt(gram.GetIO(), txtfile); // Нет повторных объявлений состояний? for (lem::Container::size_type i = 0; i < dummy.size(); i++) { // Проверим, чтобы в загруженной подгруппе не было двух // одинаковых имен. for (lem::Container::size_type j = 0; j < dummy.size(); j++) { if (i != j) if (dummy[i] == dummy[j]) { Print_Error(txtfile); MemFormatter f; f.printf("Two equal names in a coordinate [%us] state subgroup\n", name.string().c_str()); throw E_Solarix(f.string().c_str()); } } const UCString& look_for = dummy.get(i); if (FindState(look_for) != UNKNOWN) { Print_Error(txtfile); MemFormatter f; f.printf("Two states of coordinate [%us] have got the same name\n", name.string().c_str()); throw E_Solarix(f.string().c_str()); } } state.push_back(dummy); if (Me) gram.GetIO().mecho().printf('.'); } loading = false; break; } default: { if (states().size()) { Print_Error(t1, txtfile); MemFormatter f; f.printf( "Definition of the coordinate [%us] is not" " identical to previous one.\n" , name.string().c_str() ); throw E_Solarix(f.string().c_str()); } // Если это не открывающая фигурная скобочка, то имеем координату // с двумя состояниями TRUE и FALSE (бистабильную координату). txtfile.seekp(back); // На этом считывание описания заканчиваем. loading = false; break; } } // end of switch } // end of while if (Me) { // Эхо-сообщение: закончили трансляцию координаты. gram.GetIO().mecho().printf("%vfAOK%vn\n"); } return; }
/************************************************************************* Загрузка дескриптора ребра из текстового файла. Распознаются форматы: 1. <имя_коорд:имя_связки> Расширенный формат, явно задано имя координаты имя_коорд, одно из состояний которой имя_связки признается за имя связки. Угловые скобки обязательны. Частные случаи этого формата: 1.1 <имя_коорд:*> То есть имя связки (состояния координаты имя_коорд) задается квантором производьности, и в дальнейших проверках игнорируется. 1.2 <имя_коорд:?> Имя связки задано как квантор UNKNOWN. 2. <имя_связки> Сокращенный формат, имя связки должно быть объявлено как имя состояния координаты с предопределенным именем net. 3. <*> Связка задана как квантор всеобщности, так что в операциях сравнения она будет подходить для любой другой связки. 4. <?> Особое задание связки - через квантор UNKNOWN. ***************************************************************************/ bool Tree_Link::LoadTxt(Macro_Parser &txtfile, const SynGram &gram) { const BSourceState back = txtfile.tellp(); BethToken coord_name = txtfile.read(); if (coord_name.GetToken() == B_OTRIPAREN) { coord_name = txtfile.read(); switch (coord_name.GetToken()) { case ANY_STATE: icoord = ANY_STATE; break; case UNKNOWN_STATE: icoord = UNKNOWN_STATE; break; default: { const BethToken t = txtfile.read(); if (t.GetToken() == B_COLON) { // Полный, расширенный формат с указанием имени координаты. if ((icoord = gram.FindCoord(coord_name.string()).GetIndex()) == UNKNOWN) { lem::Iridium::Print_Error(coord_name, txtfile); gram.GetIO().merr().printf( "The coordinate [%us] is not previously declared in grammar\n" , coord_name.c_str() ); throw E_ParserError(); } } else { icoord = I_NET; txtfile.seekp(coord_name); } const BethToken state_name = txtfile.read(); switch (state_name.GetToken()) { case B_ANY: istate = ANY_STATE; break; case B_UNKNOWN: istate = UNKNOWN_STATE; break; default: if ((istate = gram.coords()[icoord].FindState(state_name.string())) == UNKNOWN) { lem::Iridium::Print_Error(state_name, txtfile); gram.GetIO().merr().printf( "State [%us] is not declared for coordinate [%us]\n" , state_name.c_str(), gram.coords()[icoord].GetName().string().c_str() ); throw E_ParserError(); } break; } break; } } txtfile.read_it(B_CTRIPAREN); return true; } else { txtfile.seekp(back); icoord = UNKNOWN; istate = UNKNOWN; return false; } return false; }