void SG_EntryForm::SaveTxt( OFormatter& txtfile, Grammar &gram, const SG_Entry &entry ) const { const GramClass &c = gram.classes()[ entry.GetClass() ]; txtfile.printf( " " ); for( Container::size_type i=0; i<coords().size(); i++ ) { const GramCoordPair cp = coords()[i]; if( find( c.attrs(), cp.GetCoord() )!=UNKNOWN ) continue; const GramCoord& c = gram.coords()[cp.GetCoord().GetIndex()]; const UCString& dim_name = c.GetName()[cp.GetCoord().GetVar()]; if( !c.states().empty() ) { const UCString &state_name = c.GetStateName(cp.GetState()); if( c.IsDefState(cp.GetState()) && c.IsHeadState(cp.GetState() ) ) txtfile.printf( "%us%us%us%us%us ", dim_name.c_str(), sol_get_token(B_COLON).c_str(), sol_get_token(B_OROUNDPAREN).c_str(), state_name.c_str(), sol_get_token(B_CROUNDPAREN).c_str() ); else txtfile.printf( "%us%us%us ", dim_name.c_str(), sol_get_token(B_COLON).c_str(), state_name.c_str() ); } else { UCString prefix; if(!cp.GetState()) prefix=sol_get_token(B_NEGATIVE); txtfile.printf( "%us%us ", prefix.c_str(), dim_name.c_str() ); } } txtfile.printf( " %us %us %us\n", sol_get_token(B_OFIGPAREN).c_str(), content->c_str(), sol_get_token(B_CFIGPAREN).c_str() ); return; }
void Base_Entry::BeforeFirstForm(Grammar& gram) { if (is_quantor(GetClass())) return; const GramClass& cl = gram.classes()[GetClass()]; const int na = cl.attrs().size(); for (int i = 0; i < na; i++) { const GramCoordAdr iglob = cl.attrs()[i]; const GramClass &cls = gram.classes()[GetClass()]; if (GetAttrState(iglob) == UNKNOWN) { // Для атрибута задано значение по умолчанию? lem::zbool has_def; for (lem::Container::size_type j = 0; j < cls.attr_defaults.size(); ++j) { if (cls.attr_defaults[j].first == iglob) { if (cls.attr_defaults[j].second != UNKNOWN) { int ia = attr.FindOnce(iglob); if (ia != UNKNOWN) attr.Remove(ia); attr.push_back(GramCoordPair(iglob, cls.attr_defaults[j].second)); } has_def = true; break; } } if (!has_def) { // Если это координата с двумя неявно объявленными // состояниями, то следует установить состояние // атрибута как FALSE. if (gram.coords()[iglob.GetIndex()].states().empty()) attr.push_back(GramCoordPair(iglob, false)); } } } return; }
/********************************************************************* Все атрибуты должны быть определены! Метод вызывается после чтения тела описания Статьи. **********************************************************************/ void Base_Entry::CheckAttr(Macro_Parser& txtfile, Grammar& gram) { if (is_quantor(GetClass())) return; const GramClass& cl = gram.classes()[GetClass()]; const int na = CastSizeToInt(cl.attrs().size()); for (int i = 0; i < na; i++) { const GramCoordAdr iglob = cl.attrs()[i]; const GramClass &cls = gram.classes()[GetClass()]; if (GetAttrState(iglob) == UNKNOWN) { lem::zbool def_unk; for (lem::Container::size_type j = 0; j < cl.attr_defaults.size(); ++j) { if (cl.attr_defaults[j].first == iglob && cl.attr_defaults[j].second == UNKNOWN) { def_unk = true; break; } } if (!def_unk) { // Состояние аттрибута не определено! Print_Error(txtfile); gram.GetIO().merr().printf( "Not defined attribute [%us] state\n", gram.coords()[iglob.GetIndex()].GetName()[iglob.GetVar()].c_str() ); throw E_ParserError(); } } } 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())
/************************************************************************* ЗАГРУЗКА ОПИСАНИЯ ИЗ ТЕКСТОВОГО ФАЙЛА 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; }