void SG_EntryGroup::Compress_Interval( IntCollect& indeces, SG_Interval &range ) { int i,j; const int n=indeces.size(); // Шаг 1. // Найдем самый длинный диапазон индексов, который будет компактно // представлен двумя числами n_from и n_sequent. int n_from_max=0, n_sequent_max=0; for( i=0; i<n; i++ ) { // Определяем длину последовательно идущих индексов, начиная с i. int nn=1, iprev=indeces[i], inew; for( j=i+1; j<n; j++, nn++ ) if( (inew=indeces[j])!=iprev+1 ) break; else iprev=inew; if( n_sequent_max<nn ) { n_from_max = i; n_sequent_max = nn; } } // Если найденный максимальный диапазон охватывает больше 2 индексов, или // он охватывает все индексы списка (когда их <=2), то сохраняем этот // диапазон в полях n_from и n_sequent. if( n_sequent_max>2 || (n_from_max==0 && n_sequent_max==n) ) { range.from = indeces[n_from_max]; range.n = n_sequent_max; // Теперь индексы из списка indeces, вошедшие в сохраненный диапазон, // исключаем. IntCollect tmp; tmp.reserve(indeces.size()); const int n_to=range.from+range.n; int ii; if( range.from!=0 || range.n!=n ) for( i=0; i<n; i++ ) { ii = indeces[i]; if( ii<range.from || ii>n_to ) tmp.push_back( ii ); } indeces = tmp; } return; }
/************************************************************************ Составляет список всех состояний у указанной координаты <Coord>. Процедура позволяет собрать список всех состояний одной AND-координаты. *************************************************************************/ const IntCollect Word_Form::GetStates( const GramCoordAdr& Coord ) const { IntCollect res; // Первый проход - с точным учетом синонимов. const int npair=GetnPair(); for( int i=0; i<npair; i++ ) if( pair[i].GetCoord() == Coord ) res.push_back( pair[i].GetState() ); // Если составленный список оказался пуст, то попробуем найти координаты // без учета синонимов. if( res.empty() ) for( int i=0; i<npair; i++ ) if( pair[i].GetCoord().GetIndex() == Coord.GetIndex() ) res.push_back( pair[i].GetState() ); return res; }
/******************************************************************* Вернем список индексов состояний, входящих в указанную подгруппу. *******************************************************************/ const IntCollect GramCoord::GetSubgroupIndeces(int isubgroup) const { int istart = 0; for (int i1 = 0; i1 < isubgroup; i1++) istart += CastSizeToInt(GetTopState(i1).size()); IntCollect is; for (lem::Container::size_type i2 = 0; i2 < GetTopState(isubgroup).size(); i2++) is.push_back(istart + i2); return is; }
/************************************************************************** ЗАГРУЗКА ОДНОЙ АТРИБУТНОЙ КООРДИНАТНОЙ ПАРЫ из текстового файла Общий формат: коорд_имя : состояние Особое внимание следует уделять автоматическому созданию 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())