|
(*~\Глагол\Отделы\Среда~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(**) ОТДЕЛ СРЕДА;
(*============================================================================*
* НАЗНАЧЕНИЕ: среда для выполнения Глагол-приложений. *
* Распределяет память под создаваемые переменные и выполняет *
* уборку памяти (УП) от неиспользуемых. *
* В исключительных состояниях (АвОстах) сохраняет в файл "Срез.пер" *
* значения переменных у запущенных задач (из стека приложения). *
* ПРИМЕЧАНИЯ: *
* Свободная память запрашивается у ОС кусками. Для создаваемой *
* переменной из 'куска памяти' выбирается свободный (или нарезается новый) *
* участок памяти необходимого размера. Свойства участка хранятся в *
* описателе участка (ОУ), расположенном до значения переменной. *
* Для уборки памяти используются Данные о Видах во время выполнения (ДВ), *
* которые создаются Преобразователем Глагола (ПГ). *
* 'Куски памяти' организованны в кольцевой список. *
* *
* Размещение ДВ набора в области ПОСТоянных: *
* ДВ-> вид:4; | (Данных о Видах во время выполнения) *
* имя:...; } размерДВ ячеек *
* ... | *
* размерДВ :4; *
* адр(ДВ.имя) :4; *
* размер набора:4; *
* ОВ-> ОВ1:4; | (Описатель Вида) *
* ОВ2:4; | *
* ... } ВсегоРасширений шт. *
* 0 :4; | *
* ... | *
* 0 :4; | *
*============================================================================*)
ИСПОЛЬЗУЕТ
ОБХОД,
ОС ИЗ "..\Обмен\",
Асм ИЗ "..\Иное\",
Буква ИЗ "..\Иное\",
Текст ИЗ "..\Числа\",
Вывод ИЗ "..\Обмен\",
Писать ИЗ "..\Обмен\";
ПОСТ
(* размер запрашиваемого у ОС куска свободной памяти *)
РазмерКуска=10000H; (* 10000H *)
(* выделяется памяти перед принудительным запуском Уборки Памяти (УП) *)
ЗапускУП=100*РазмерКуска;
(* предельный уровень вложения доступов при записи среза переменных *)
УровеньД=4;
(* предельный уровень вложения задач при записи среза переменных *)
УровеньЗ=30;
(* количественные ограничители Преобразователя Глагола (ПГ) *)
рНазвания=32; (* наибольший размер названия. Из отдела НП. *)
ВсегоРасширений=10; (* наибольший уровень расширения наборов. Из отдела ЗК. *)
ВсегоОтделов=64; (* количество отделов. Из отдела ВД. *)
(* Программные ловушки/(аварийные остановы). Из отдела СК. *)
пределыАвОст=1;
номерАвОст=2;
арифмАвОст=3;
охранаАвОст=4;
пустоАвОст=5;
дляАвОст=6;
выбратьАвОст=7;
ответАвОст=8;
проверитьАвОст=9;
нольАвОст=10;
бегунокАвОст=11;
(* Род видов (Вид.родв). Из отдела ВД. Причём:
* вЯчейка <= вЦел8 <= вЗнак <= вЦел16 <= вЦел32 <= вЦел64. *)
вНеопр=0;
вЯчейка=1;
вКлюч=2;
вЗнак=3;
вЦел8=4;
вЦел16=5;
вЦел32=6;
вЦел64=7;
вВещ32=8;
вВещ64=9;
вМнож=10;
вПЦепь=11;
вПусто=12;
вНет=13;
вДоступ=14;
вЗадача=15;
вБегунок=16;
вРяд=17;
вОРяд=18;
вНабор=19;
вКон=20;
(* вКон для ДВ. При изменении вКон нужно 3 преобразования с уборка:=ОТКЛ. *)
ВИД
(* описатель куска находится в начале каждого куска памяти,
* полученного от ОС *)
ОпКуска-=ДОСТУП К ВидОпКуска;
ВидОпКуска=НАБОР
первсв-:ЦЕЛ; (* адрес первого свободного участка *)
размер-:ЦЕЛ; (* количество ячеек в куске памяти *)
первуч-:ЦЕЛ; (* адрес первого участка памяти *)
следку-:ОпКуска (* для организации списка *)
КОН;
ПОСТ
РазмерОК=16; (* размер описателя куска *)
ПОСТ
(* Позиции свойств описателя участка (ОУ) относительно его начала.
* Описатель участка предшествует каждому участку памяти, выделенному
* задачей СОЗДАТЬ. Т.к. преобразователь подразумевает, что 4 ячейки,
* предшествующие данным, всегда содержат адрес описателя вида (ОВ),
* то <ПозУчОВ> всегда должен указывать на последнее свойство ОУ. *)
ПозУчРазмера-=0; (* размер участка (если <0, то участок свободен) *)
ПозУчСледСв- =4; (* адрес следующего свободного участка *)
ПозУчОВ- =4; (* адрес описателя вида (ОВ) *)
РазмерОУ- =8; (* размер описателя участка *)
ВИД
Название-=ЦЕПЬ[рНазвания];
(* Описатель Отдела (ОО) создаётся преобразователем Глагола в области
* постоянных *)
ОпОтдела-=ДОСТУП К ВидОпОтдела;
ВидОпОтдела=НАБОР
название- :Название;
адрПерем- :ЦЕЛ; (* адрес переменных уровня отдела *)
адрПервЗадачи- :ЦЕЛ; (* адрес первой задачи *)
адрЗаПослЗадачей-:ЦЕЛ; (* адрес за последней задачей *)
адрДВПерем- :ЦЕЛ; (* адрес ДВ переменных уровня отдела *)
длДВПерем- :ЦЕЛ; (* длина ДВ переменных уровня отдела *)
описанияЗадач- :РЯД 1 ИЗ НАБОР (* начало ряда описания задач *)
нз-:ЦЕЛ; (* адрес начала задачи *)
нч-:ЦЕЛ; (* адрес начала ДВ задачи *)
КОН
КОН;
ПЕР
опОтделов-:РЯД ВсегоОтделов ИЗ ЦЕЛ; (* адреса описателей отделов *)
отделов- :ЦЕЛ; (* всего адресов описателей отделов *)
памПослеУП:ЦЕЛ; (* выделенно ячеек памяти после прошлой УП *)
уборка+ :КЛЮЧ;(* ВКЛ, если разрешена периодическая уборка памяти (УП) *)
теккус- :ЦЕЛ; (* адрес текущего куска в кольцевом списке кусков *)
тексвуч- :ЦЕЛ; (* адрес свободного участка <теккус> *)
(* Запись среза переменных в исключительном состоянии *)
ПЕР
поток:Писать.Поток; (* для записи среза переменных *)
отступ:ЦЕЛ; (* отступ на строке при записи среза *)
уровеньд:ЦЕЛ; (* текущий уровень вложения доступов при записи среза *)
(***************************************************************************
* Задачи помощники для работы с видами и переменными приложения
***************************************************************************)
ЗАДАЧА ИмяИзОВ-(ов:ЦЕЛ; имя+:ЦЕПЬ);
ПЕР
доступИмени:ДОСТУП К Название;
УКАЗ
ЕСЛИ ов = 0 ТО
СПИСАТЬ("ПУСТО",имя)
ИНАЧЕ
ОБХОД.ИзПамяти(ов-8,доступИмени);
СПИСАТЬ(доступИмени^,имя)
КОН
КОН ИмяИзОВ;
(******************************************************************************)
ЗАДАЧА ОВИзПер-(пер:ЦЕЛ; ов+:ЦЕЛ);
УКАЗ
ЕСЛИ пер = 0 ТО
ов:=0
ИНАЧЕ
ОБХОД.ИзПамяти(пер-РазмерОУ+ПозУчОВ,ов)
КОН
КОН ОВИзПер;
(*
(******************************************************************************)
ЗАДАЧА ИмяВИзПер-(пер:ЦЕЛ; имя+:ЦЕПЬ);
ПЕР
ов:ЦЕЛ;
УКАЗ
ОВИзПер(пер,ов);
ИмяИзОВ(ов,имя)
КОН ИмяВИзПер;
*)
(***************************************************************************
* Задачи для чтения ДВ
***************************************************************************)
ЗАДАЧА ЦелИзДВ-(тч+,цел+:ЦЕЛ);
(* Цель: прочитать целое число <цел> из ДВ
* До: <тч> - текущий адрес чтения ДВ *)
УКАЗ
ОБХОД.ИзПамяти(тч,цел);
УВЕЛИЧИТЬ(тч,4)
КОН ЦелИзДВ;
(******************************************************************************)
ЗАДАЧА ЦепьИзДВ-(тч+:ЦЕЛ; цепь+:ЦЕПЬ);
(* Цель: прочитать в <цепь> цепочку знаков
* До: <тч> - текущий адрес чтения ДВ *)
ПЕР
поз:ЦЕЛ;
зн:ЗНАК;
УКАЗ
поз:=0;
ПОВТОРЯТЬ
ОБХОД.ИзПамяти(тч,зн);
УВЕЛИЧИТЬ(тч,2);
ЕСЛИ поз < РАЗМЕР(цепь) ТО
цепь[поз]:=зн
КОН;
УВЕЛИЧИТЬ(поз)
ДО зн = 0X
КОН ЦепьИзДВ;
(******************************************************************************)
ЗАДАЧА ВидИмяИзДВ-(тч+,вид+:ЦЕЛ; имя+:ЦЕПЬ);
(* Цель: прочитать в <вид> метку ДВ, а в <имя> название ДВ
* До: <тч> - текущий адрес чтения ДВ *)
УКАЗ
ЦелИзДВ(тч,вид); (* +вид *)
ЦепьИзДВ(тч,имя) (* +имя *)
КОН ВидИмяИзДВ;
(******************************************************************************)
ЗАДАЧА НаборИзДВ-(нп,тч+:ЦЕЛ; Обработка:ЗАДАЧА (нп,тч+:ЦЕЛ));
(* Цель: обработать ДВ набора
* До: <нп> - адрес начала области переменных
* <тч> - текущий адрес чтения ДВ *)
ПЕР
вид:ЦЕЛ;
УКАЗ
ОБХОД.ИзПамяти(тч,вид);
ПОКА вид # вКон ВЫП
Обработка(нп,тч);
ОБХОД.ИзПамяти(тч,вид)
КОН;
УВЕЛИЧИТЬ(тч,4) (* +вид *)
КОН НаборИзДВ;
ЗАДАЧА^ ОтметитьВПер(нп,тч+:ЦЕЛ);
(******************************************************************************)
ЗАДАЧА ПропуститьДВ-(нп,тч+:ЦЕЛ);
(* Цель: увеличить <тч> на столько, чтобы пропустить один ДВ
* До: <нп> - адрес начала области переменных
* <тч> - текущий адрес чтения ДВ *)
ПЕР
вид:ЦЕЛ;
имя:Название;
УКАЗ
ВидИмяИзДВ(тч,вид,имя); (* +вид *)
УВЕЛИЧИТЬ(тч,4); (* +оп *)
ВЫБРАТЬ вид ИЗ
вДоступ:
ВидИмяИзДВ(тч,вид,имя); (* +вид *)
УВЕЛИЧИТЬ(тч,4); (* +оп *)
ВЫБРАТЬ вид ИЗ
вНабор:
УМЕНЬШИТЬ(тч,4); (* -оп *)
| вРяд:
УВЕЛИЧИТЬ(тч,8); (* +рслаг +чслаг *)
ПропуститьДВ(нп,тч)
| вОРяд:
УВЕЛИЧИТЬ(тч,4); (* +рслаг *)
ПропуститьДВ(нп,тч)
| вБегунок:
ПропуститьДВ(нп,тч)
| вНеопр:
КОН
| вРяд:
УВЕЛИЧИТЬ(тч,8); (* +рслаг +чслаг *)
ПропуститьДВ(нп,тч)
| вБегунок:
ПропуститьДВ(нп,тч)
| вНабор:
НаборИзДВ(нп,тч,ПропуститьДВ)
ИНАЧЕ
КОН
КОН ПропуститьДВ;
(******************************************************************************
* Шаги по уборке памяти (УП):
* а) все ранее распределённые участки памяти переводим в разряд
* неиспользуемых (выставляем их размеры отрицательными);
* б) отмечаем участки памяти всех размещённых переменных доступных на
* данный момент как на уровне отдела так и через стек (в том числе и
* через переменные доступа), как используемые (выставляем их размеры
* положительными);
* в) считаем, что оставшиеся участки с отрицательными размерами больше не
* используются приложением, и их можно использовать для новых переменных;
* г) смежные свободные участки памяти объединяем;
* д) целиком свободные куски памяти возвращаем ОС.
******************************************************************************)
ЗАДАЧА ОтметитьВРяду-(нпс,тч+,чслаг,рслаг:ЦЕЛ);
(* Цель: отметить слагаемые ряда
* До: <нпс> - адрес начала переменной слагаемого
* <тч> - текущий адрес чтения ДВ
* <чслаг> - число слагаемых ряда
* <рслаг> - размер одного слагаемого *)
ПЕР
тчс:ЦЕЛ; (* текущий адрес чтения ДВ слагаемого *)
вид:ЦЕЛ; (* вид слагаемых *)
УКАЗ
ОБХОД.ИзПамяти(тч,вид);
ЕСЛИ вид В {вДоступ,вНабор,вРяд,вОРяд} ТО
(* пробегаем по всем слагаемым *)
ПОКА чслаг > 0 ВЫП
тчс:=тч;
ОтметитьВПер(нпс,тчс);
УВЕЛИЧИТЬ(нпс,рслаг);
УМЕНЬШИТЬ(чслаг)
КОН;
тч:=тчс
ИНАЧЕ
(* пропускаем ДВ слагаемого *)
ПропуститьДВ(нпс,тч)
КОН
КОН ОтметитьВРяду;
(******************************************************************************)
ЗАДАЧА ОтмечаемУчПер(пер:ЦЕЛ):КЛЮЧ;
(* Цель: искать в куче и отметить участок памяти переменной с адресом <пер>
* Ответ: ВКЛ, если участок ещё не был отмечен *)
ПЕР
нк:ОпКуска; (* начальный кусок в кольцевом списке кусков *)
тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
уч: ЦЕЛ; (* адрес участка *)
учпер: ЦЕЛ; (* адрес похожий на адрес участка переменной *)
размуч:ЦЕЛ; (* размер участка *)
УКАЗ
ЕСЛИ пер # 0 ТО (* не ПУСТО *)
учпер:=пер-РазмерОУ;
(* ищем кусок, содержащий учпер *)
тк:=ОБХОД.Значение(ОпКуска,теккус);
нк:=тк;
ПОВТОРЯТЬ
ЕСЛИ (учпер >= тк.первуч) И (учпер < тк.первуч+тк.размер) ТО (* нашли кусок *)
(* ищем участок *)
уч:=тк.первуч;
ПОКА уч <= учпер ВЫП
ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч);
ЕСЛИ уч = учпер ТО
(* нашли участок *)
ЕСЛИ размуч < 0 ТО
(* он ещё не отмечен занятым *)
ОБХОД.ВПамять(уч+ПозУчРазмера,-размуч);
ВОЗВРАТ ВКЛ
ИНАЧЕ
ВОЗВРАТ ОТКЛ
КОН
КОН;
УВЕЛИЧИТЬ(уч,МОДУЛЬ(размуч))
КОН
КОН;
тк:=тк.следку
ДО тк = нк (* обошли всё кольцо кусков *)
КОН;
ВОЗВРАТ ОТКЛ
КОН ОтмечаемУчПер;
ЗАДАЧА^ НаборИзД-(нп,ов:ЦЕЛ; Обработка:ЗАДАЧА (нп,тч+:ЦЕЛ));
(******************************************************************************)
ЗАДАЧА ОтметитьВПер(нп,тч+:ЦЕЛ);
(* Цель: разбирая ДВ, найти размещённые переменные и отметить их участки памяти
* До: <нп> - адрес начала области переменных
* <тч> - текущий адрес чтения ДВ *)
ПЕР
оп:ЦЕЛ; (* адрес переменной относительно <нп> *)
пп:ЦЕЛ; (* полный адрес переменной <нп>+<оп> *)
ов:ЦЕЛ; (* адрес ОВ *)
зд:ЦЕЛ; (* значение ДОСТУП *)
вид:ЦЕЛ; (* ДВ метка вида *)
имя:Название;(* имя переменной (вида) *)
чслаг:ЦЕЛ; (* число слагаемых ряда *)
рслаг:ЦЕЛ; (* размер одного слагаемого *)
чразм:ЦЕЛ; (* число размерностей у вОРяд *)
нразм:ЦЕЛ; (* номер размерности вОРяд *)
длразм:ЦЕЛ; (* длина размерности вОРяд *)
УКАЗ
ВидИмяИзДВ(тч,вид,имя); (* +вид *)
ЦелИзДВ(тч,оп); (* +оп *)
ПРОВЕРИТЬ(вид # вНет);
ВЫБРАТЬ вид ИЗ
вДоступ:
ОБХОД.ИзПамяти(нп+оп,зд);
ВидИмяИзДВ(тч,вид,имя); (* +вид *)
ЦелИзДВ(тч,оп); (* +оп *)
ВЫБРАТЬ вид ИЗ
вНабор:
УМЕНЬШИТЬ(тч,4); (* -оп *)
ЕСЛИ ОтмечаемУчПер(зд) ТО
ОВИзПер(зд,ов);
НаборИзД(зд,ов,ОтметитьВПер)
КОН
| вРяд:
ЦелИзДВ(тч,рслаг); (* +рслаг *)
ЦелИзДВ(тч,чслаг); (* +чслаг *)
ЕСЛИ ОтмечаемУчПер(зд) ТО
ОтметитьВРяду(зд,тч,чслаг,рслаг)
ИНАЧЕ
ПропуститьДВ(зд,тч)
КОН
| вОРяд:
ЦелИзДВ(тч,рслаг); (* +рслаг *)
(* по адресу ОРЯД 0-е слово содержит его размерность,
* а следующие слова содержат РАЗМЕР его измерений *)
ЕСЛИ ОтмечаемУчПер(зд) ТО
ОБХОД.ИзПамяти(зд,чразм);
чслаг:=1;
нразм:=1;
ПОКА нразм <= чразм ВЫП
ОБХОД.ИзПамяти(зд+нразм*4,длразм);
чслаг:=чслаг*длразм;
УВЕЛИЧИТЬ(нразм)
КОН;
ОтметитьВРяду(зд+нразм*4,тч,чслаг,рслаг)
ИНАЧЕ
ПропуститьДВ(зд,тч)
КОН
| вБегунок:
ПропуститьДВ(нп,тч)
| вНеопр:
КОН
| вРяд:
ЦелИзДВ(тч,рслаг); (* +рслаг *)
ЦелИзДВ(тч,чслаг); (* +чслаг *)
ОтметитьВРяду(нп+оп,тч,чслаг,рслаг)
| вНабор:
НаборИзДВ(нп,тч,ОтметитьВПер)
| вБегунок:
ПропуститьДВ(нп,тч)
ИНАЧЕ
КОН
КОН ОтметитьВПер;
(******************************************************************************)
ЗАДАЧА НаборИзД-(нп,ов:ЦЕЛ; Обработка:ЗАДАЧА (нп,тч+:ЦЕЛ));
(* Цель: найти размещённые переменные набора и обработать их
* До: <нп> - адрес начала области переменных *)
ПЕР
тч: ЦЕЛ; (* текущий адрес для чтения *)
вч: ЦЕЛ; (* всего ячеек для чтения *)
кч: ЦЕЛ; (* последний адрес для чтения *)
ур: ЦЕЛ; (* уровень расширения набора *)
ово:ЦЕЛ; (* адрес описателя вида основания *)
имя:Название;
УКАЗ
кч:=ов-12;
ОБХОД.ИзПамяти(кч,вч);
ИмяИзОВ(ов,имя);
ЕСЛИ вч >= 0 ТО
тч:=кч-вч;
(* просмотр ДВ в нашем наборе *)
ПОКА тч < кч ВЫП
Обработка(нп,тч)
КОН;
(* просмотр ДВ в основаниях нашего набора *)
ур:=ВсегоРасширений-1;
КОЛЬЦО
ЕСЛИ ур <= 0 ТО ВЫХОД КОН;
ОБХОД.ИзПамяти(ов+ур*4,ово);
ЕСЛИ ово # 0 ТО
(* берём предпоследний ОВО, т.к. в последнем ОВО
* хранится адрес своего ОВ *)
ОБХОД.ИзПамяти(ов+(ур-1)*4,ово);
НаборИзД(нп,ово,Обработка);
ВЫХОД
КОН;
УМЕНЬШИТЬ(ур)
КОН
КОН
КОН НаборИзД;
(******************************************************************************)
ЗАДАЧА ОтметитьВЗадаче(нп,тч:ЦЕЛ);
(* Цель: разбирает ДВ задачи, находит размещённые переменные и отмечает их
* участки памяти как занятые
* До: <нп> - адрес начала переменных задачи (регистр EBP при работе задачи)
* <тч> - текущий адрес чтения ДВ *)
ПЕР
вид:ЦЕЛ; (* ДВ метка вида *)
имя:Название;
УКАЗ
ЦепьИзДВ(тч,имя);
КОЛЬЦО
ЦелИзДВ(тч,вид); (* +вид *)
ЕСЛИ вид = вКон ТО
ВЫХОД
КОН;
УМЕНЬШИТЬ(тч,4); (* -вид *)
ОтметитьВПер(нп,тч)
КОН
КОН ОтметитьВЗадаче;
(******************************************************************************)
ЗАДАЧА ОтметитьВОтделе(адрОО:ЦЕЛ);
(* Цель: разбирает ДВ отдела, находит размещённые переменные и отмечает их
* участки памяти как занятые *)
ПЕР
тч:ЦЕЛ; (* текущий адрес для чтения *)
кч:ЦЕЛ; (* запоследний адрес для чтения *)
оо:ОпОтдела; (* Описатель Отдела *)
УКАЗ
оо:=ОБХОД.Значение(ОпОтдела,адрОО);
тч:=оо.адрДВПерем;
кч:=тч+оо.длДВПерем;
ПОКА тч < кч ВЫП
ОтметитьВПер(оо.адрПерем,тч)
КОН
КОН ОтметитьВОтделе;
(******************************************************************************)
ЗАДАЧА УдалитьСвКуски();
(* Цель: найти полностью свободные куски памяти и возвратить их в ОС
* Прим: из кольцевого списка удобно удалять последующий кусок
* После: <теккус> - адрес начального куска в кольцевом списке кусков
* <тексвуч> - адрес первого свободного участка <теккус> *)
ПЕР
тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
ск:ОпКуска; (* следующий кусок в кольцевом списке кусков *)
нк:ОпКуска; (* начальный неудаляемый кусок *)
размсв:ЦЕЛ; (* размер первого свободного участка в <ск> *)
удалёнск:КЛЮЧ; (* если был удалён <ск>, то ВКЛ *)
адрес:ЦЕЛ; (* адрес памяти, возвращаемой в ОС *)
УКАЗ
тк:=ОБХОД.Значение(ОпКуска,теккус);
ск:=тк.следку;
нк:=ПУСТО;
ПОВТОРЯТЬ
удалёнск:=ОТКЛ;
ЕСЛИ ск.первсв # 0 ТО
ОБХОД.ИзПамяти(ск.первсв+ПозУчРазмера,размсв);
ЕСЛИ ск.размер = -размсв ТО (* весь кусок свободен *)
адрес:=ОБХОД.Значение(ЦЕЛ,ск);
ЕСЛИ ск = тк ТО (* был последним куском в списке *)
ОС.ОтдатьПамять(адрес);
теккус:=0;
ВОЗВРАТ
КОН;
(* удаляем <ск> из кольцевого списка *)
ск:=ск.следку;
тк.следку:=ск;
удалёнск:=ВКЛ;
ОС.ОтдатьПамять(адрес)
КОН
КОН;
ЕСЛИ НЕ удалёнск ТО
ЕСЛИ нк = ПУСТО ТО
нк:=ск
КОН;
(* продвигаем <тк> и <ск> *)
тк:=ск;
ск:=тк.следку
КОН
ДО ск = нк; (* обошли всё кольцо кусков *)
теккус:=ОБХОД.Значение(ЦЕЛ,нк);
тексвуч:=нк.первсв
КОН УдалитьСвКуски;
(*
(******************************************************************************)
ЗАДАЧА ПроверитьКучу-();
(* Цель: проверить строение всей кучи *)
ПЕР
нк:ОпКуска; (* начальный кусок в кольцевом списке кусков *)
тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
послуч:ЦЕЛ; (* адрес запоследнего участок в куске *)
уч: ЦЕЛ; (* адрес текущего участка *)
св: ЦЕЛ; (* адрес свободного участка *)
размуч:ЦЕЛ; (* размер <уч> *)
УКАЗ
ЕСЛИ теккус = 0 ТО ВОЗВРАТ КОН;
тк:=ОБХОД.Значение(ОпКуска,теккус);
нк:=тк;
ПОВТОРЯТЬ
ПРОВЕРИТЬ((тк.размер > 0) И
((тк.размер+РазмерОК) ОСТАТОК РазмерКуска = 0) И
(тк.первуч = (ОБХОД.Значение(ЦЕЛ,тк)+РазмерОК)));
уч:=тк.первуч;
послуч:=тк.первуч+тк.размер;
св:=тк.первсв;
ПОКА уч < послуч ВЫП
ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч);
ЕСЛИ размуч < 0 ТО (* свободный участок *)
ПРОВЕРИТЬ(уч = св);
ОБХОД.ИзПамяти(св+ПозУчСледСв,св);
УВЕЛИЧИТЬ(уч,-размуч)
ИНАЧЕ
УВЕЛИЧИТЬ(уч,размуч)
КОН
КОН;
ПРОВЕРИТЬ((уч = послуч) И (св = 0));
тк:=тк.следку
ДО тк = нк (* обошли всё кольцо кусков *)
КОН ПроверитьКучу;
*)
(******************************************************************************)
ЗАДАЧА GetEBP-():ЦЕЛ;
(* Цель: возвратить значение регистра EBP вызвавшей задаче *)
ПЕР
п:ЦЕЛ;
УКАЗ
п:=ОБХОД.ПолучитьАдрес(п)+4+4; (* после 'п': свой EBP, пред. EBP, пред. EIP *)
ОБХОД.ИзПамяти(п,п);
ВОЗВРАТ п
КОН GetEBP;
(******************************************************************************)
ЗАДАЧА НайтиДВЗадачи-(адр,но+,нч+:ЦЕЛ);
(* Цель: найти задачу и её ДВ по внутреннему адресу задачи <адр>
* После: <тч> - начальный адрес чтения ДВ
* <но> - номер отдела, в котором находится задача или 0 *)
ПЕР
оо:ОпОтдела;(* Описатель Отдела *)
оз:ЦЕЛ; (* адрес Описания Задачи *)
нз:ЦЕЛ; (* адрес начала задачи *)
УКАЗ
но:=0;
ПОКА но < отделов ВЫП
оо:=ОБХОД.Значение(ОпОтдела,опОтделов[но]);
ЕСЛИ (адр >= оо.адрПервЗадачи) И (адр < оо.адрЗаПослЗадачей) ТО (* нашли отдел *)
оз:=ОБХОД.ПолучитьАдрес(оо.описанияЗадач[0].нз);
КОЛЬЦО
ОБХОД.ИзПамяти(оз,нз);
ЕСЛИ нз <= адр ТО (* нашли задачу *)
ОБХОД.ИзПамяти(оз+4,нч);
ВОЗВРАТ
КОН;
УВЕЛИЧИТЬ(оз,8) (* следующая запись *)
КОН;
КОН;
УВЕЛИЧИТЬ(но)
КОН;
КОН НайтиДВЗадачи;
(******************************************************************************)
ЗАДАЧА Уборка-();
(* Цель: найти и объединить неиспользуемые участки памяти
* После: <теккус> - адрес начального куска в кольцевом списке кусков
* <тексвуч> - адрес первого свободного участка <теккус> *)
ПЕР
но: ЦЕЛ; (* номер отдела *)
св: ЦЕЛ; (* адрес группы свободных участков *)
размуч:ЦЕЛ; (* размер участка *)
послуч:ЦЕЛ; (* адрес первой ячейки после куска *)
размсв:ЦЕЛ; (* размер группы свободных участков *)
предсв:ЦЕЛ; (* адрес предыдущего свободного участка *)
EBP: ЦЕЛ; (* значение машинного регистра *)
EIP: ЦЕЛ; (* значение машинного регистра *)
тч: ЦЕЛ; (* текущий адрес чтения ДВ *)
нк:ОпКуска; (* начальный кусок в кольцевом списке кусков *)
тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
уч: ЦЕЛ; (* адрес текущего участка *)
ц0: ЦЕЛ; (* целый 0 *)
УКАЗ
ЕСЛИ теккус = 0 ТО ВОЗВРАТ КОН;
ц0:=0;
(* размеры всех участков делаем отрицательными (как у свободных) *)
нк:=ОБХОД.Значение(ОпКуска,теккус);
тк:=нк;
ПОВТОРЯТЬ
уч:=тк.первуч;
послуч:=уч+тк.размер;
ПОКА уч < послуч ВЫП
ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч);
размуч:=МОДУЛЬ(размуч);
ОБХОД.ВПамять(уч+ПозУчРазмера,-размуч);
УВЕЛИЧИТЬ(уч,размуч)
КОН;
тк:=тк.следку
ДО тк = нк; (* обошли всё кольцо кусков *)
(* отмечаем переменные всех отделов *)
но:=0;
ПОКА но < отделов ВЫП
ОтметитьВОтделе(опОтделов[но]);
УВЕЛИЧИТЬ(но)
КОН;
(* отмечаем переменные работающих задач (переменные стека) *)
EBP:=GetEBP();
КОЛЬЦО
ОБХОД.ИзПамяти(EBP+4,EIP); (* EIP вызвавшей задачи *)
ОБХОД.ИзПамяти(EBP,EBP); (* EBP вызвавшей задачи *)
ЕСЛИ EBP = 0 ТО ВЫХОД КОН; (* вызвавшая задача - Пускач.^Запуск *)
НайтиДВЗадачи(EIP,но,тч);
ЕСЛИ но < отделов ТО
ОтметитьВЗадаче(EBP,тч)
КОН
КОН;
(* объединяем смежные свободные участки, и строим для них список *)
тк:=нк;
ПОВТОРЯТЬ
св:=0;
предсв:=0;
уч:=тк.первуч;
послуч:=уч+тк.размер;
ПОКА уч < послуч ВЫП (* по всем участкам куска *)
ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч);
ЕСЛИ размуч < 0 ТО (* для свободного участка *)
ЕСЛИ св = 0 ТО (* если это начало области *)
св:=уч; (* сохраним её адрес *)
размсв:=размуч (* и начнем её замерять *)
ИНАЧЕ (* продолжение области *)
УВЕЛИЧИТЬ(размсв,размуч) (* замеряем её дальше *)
КОН
АЕСЛИ св # 0 ТО (* конец области *)
(* заранее обнуляем весь участок *)
Асм.ОбнулитьПамять(св+РазмерОУ,-размсв-РазмерОУ);
(* выставляем окончательный размер области *)
ОБХОД.ВПамять(св+ПозУчРазмера,размсв);
ОБХОД.ВПамять(св+ПозУчСледСв,ц0);
ЕСЛИ предсв = 0 ТО (* первая область *)
тк.первсв:=св (* обновляем первсв в куске *)
ИНАЧЕ (* уже была область *)
(* то выставляем у неё ссылку на нашу область *)
ОБХОД.ВПамять(предсв+ПозУчСледСв,св)
КОН;
предсв:=св; (* готовимся к следующей области *)
св:=0
КОН;
УВЕЛИЧИТЬ(уч,МОДУЛЬ(размуч))
КОН;
(* такая же обработка в конце куска *)
ЕСЛИ св # 0 ТО (* конец области *)
(* заранее обнуляем весь участок *)
Асм.ОбнулитьПамять(св+РазмерОУ,-размсв-РазмерОУ);
(* выставляем окончательный размер области *)
ОБХОД.ВПамять(св+ПозУчРазмера,размсв);
ОБХОД.ВПамять(св+ПозУчСледСв,ц0);
ЕСЛИ предсв = 0 ТО (* первая область *)
тк.первсв:=св (* записываем ссылку в куске *)
ИНАЧЕ (* уже была предобласть *)
(* то выставляем у неё ссылку на область *)
ОБХОД.ВПамять(предсв+ПозУчСледСв,св)
КОН
КОН;
тк:=тк.следку
ДО тк = нк; (* обошли всё кольцо кусков *)
УдалитьСвКуски();
памПослеУП:=0
КОН Уборка;
(******************************************************************************)
ЗАДАЧА НаходимСвобУч(размер:ЦЕЛ):КЛЮЧ;
(* Цель: искать по всем кускам участок памяти не меньше <размер> ячеек
* Прим: если находит такой участок, то возвращает ВКЛ и
* После: <теккус> - адрес куска из кольцевого списка
* <тексвуч> - адрес свободного участка <теккус> *)
ПЕР
тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
нк:ОпКуска; (* кусок с которого начинается поиск *)
нсвуч: ЦЕЛ; (* адрес свободного участка с которого начинается поиск *)
размсв:ЦЕЛ; (* размер свободного <тексвуч> *)
УКАЗ
ЕСЛИ теккус = 0 ТО ВОЗВРАТ ОТКЛ КОН;
тк:=ОБХОД.Значение(ОпКуска,теккус);
нк:=тк;
нсвуч:=тексвуч;
ПОВТОРЯТЬ
ПОКА тексвуч = 0 ВЫП (* кончился кусок *)
тк:=тк.следку;
теккус:=ОБХОД.Значение(ЦЕЛ,тк);
тексвуч:=тк.первсв;
ЕСЛИ (тк = нк) И (тексвуч = нсвуч) ТО (* обошли все участки *)
ВОЗВРАТ ОТКЛ
КОН
КОН;
ОБХОД.ИзПамяти(тексвуч+ПозУчРазмера,размсв);
ЕСЛИ -размсв >= размер ТО
ВОЗВРАТ ВКЛ
КОН;
ОБХОД.ИзПамяти(тексвуч+ПозУчСледСв,тексвуч)
ДО (тк = нк) И (тексвуч = нсвуч); (* обошли все участки *)
ВОЗВРАТ ОТКЛ
КОН НаходимСвобУч;
(******************************************************************************)
ЗАДАЧА СоздатьКусок(размер:ЦЕЛ);
(* Цель: запрос у ОС нового куска памяти с полезным размером <размер>
* После: <теккус> - адрес нового текущего куска в кольцевом списке кусков
* <тексвуч> - адрес первого (и единственного) участка <теккус> *)
ПЕР
нк:ОпКуска; (* новый кусок в кольцевом списке кусков *)
тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
ц0: ЦЕЛ; (* целый 0 *)
УКАЗ
ц0:=0;
тк:=ОБХОД.Значение(ОпКуска,теккус);
УВЕЛИЧИТЬ(размер,РазмерОК);
УВЕЛИЧИТЬ(размер,(-размер) ОСТАТОК РазмерКуска); (* выравнивание на РазмерКуска *)
теккус:=ОС.ВзятьПамять(размер);
ПРОВЕРИТЬ(теккус # 0);
нк:=ОБХОД.Значение(ОпКуска,теккус);
тексвуч:=теккус+РазмерОК; (* оставляем место для <нк> *)
УМЕНЬШИТЬ(размер,РазмерОК);
нк.размер:=размер;
нк.первуч:=тексвуч;
нк.первсв:=тексвуч;
ОБХОД.ВПамять(тексвуч+ПозУчСледСв,ц0);
ОБХОД.ВПамять(тексвуч+ПозУчРазмера,-размер);
(* вставляем новый кусок в кольцевой список после текущего куска *)
ЕСЛИ тк # ПУСТО ТО
нк.следку:=тк.следку;
тк.следку:=нк
ИНАЧЕ
нк.следку:=нк
КОН
КОН СоздатьКусок;
(******************************************************************************)
ЗАДАЧА СоздатьУч(размер:ЦЕЛ):ЦЕЛ;
(* Цель: создать участок с размером <размер> (в конце <тексвуч>
* или весь <тексвуч>) и возвратить его адрес
* До: <теккус> - адрес текущего куска в кольцевом списке кусков
* <тексвуч> - адрес достаточно большого свободного участка в <теккус>
* После: <тексвуч> - бывший или следующий адрес свободного участка *)
ПЕР
предсв:ЦЕЛ; (* адрес предыдущего свободного участка *)
размсв:ЦЕЛ; (* размер свободного участка *)
тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
уч: ЦЕЛ; (* адрес свободного участка *)
создуч:ЦЕЛ; (* адрес созданного участка *)
УКАЗ
ОБХОД.ИзПамяти(тексвуч+ПозУчРазмера,размсв);
размсв:=-размсв; (* размер будет положительным *)
ЕСЛИ размсв > размер+РазмерОУ+4 ТО (* забираем хвост у <тексвуч> *)
УМЕНЬШИТЬ(размсв,размер);
ОБХОД.ВПамять(тексвуч+ПозУчРазмера,-размсв);
создуч:=тексвуч+размсв;
ОБХОД.ВПамять(создуч+ПозУчРазмера,размер);
(* ссылки в списке свободных участков остались те же *)
ИНАЧЕ (* забираем целиком <тексвуч> *)
создуч:=тексвуч;
ОБХОД.ВПамять(создуч+ПозУчРазмера,размсв);
(* новый <тексвуч> *)
ОБХОД.ИзПамяти(создуч+ПозУчСледСв,тексвуч);
(* удаляем <создуч> из списка свободных участков *)
тк:=ОБХОД.Значение(ОпКуска,теккус);
ЕСЛИ создуч = тк.первсв ТО (* это <первсв> в куске *)
тк.первсв:=тексвуч
ИНАЧЕ
предсв:=тк.первсв; (* ищем предыдущий свободный участок *)
уч:=предсв;
ПОКА уч # создуч ВЫП
предсв:=уч;
ОБХОД.ИзПамяти(уч+ПозУчСледСв,уч)
КОН;
ОБХОД.ВПамять(предсв+ПозУчСледСв,тексвуч)
КОН
КОН;
ВОЗВРАТ создуч
КОН СоздатьУч;
(***************************************************************************
* Задачи, вызываемые из приложения неявным образом
***************************************************************************)
ЗАДАЧА Создать-(ов,размер,адрес+:ЦЕЛ);
(* Цель: поддержка встроенных в Глагол задач:
* СОЗДАТЬ(<пер>+:вид) - для наборов и рядов
* СОЗДАТЬ(<пер>+:вид; <ДЛ1>,...,<ДЛn>:ЦЕЛ) - для открытых рядов
* До: <ов> - описатель вида переменной <пер>
* для рядов и открытых рядов <ов> = 0
* <размер> - размер данных у <пер>
* для открытых рядов <размер> = 4+n*4+<ДЛ1>*...*<ДЛn>
* После: <адрес> - адрес выделенной памяти заполненной 0-ми,
* четыре ячейки перед <адрес> всегда содержат <ов> *)
ПЕР
уч:ЦЕЛ; (* адрес свободного участка *)
УКАЗ
УВЕЛИЧИТЬ(размер,РазмерОУ);
УВЕЛИЧИТЬ(размер,(-размер) ОСТАТОК 4); (* выравнивание *)
ЕСЛИ НЕ НаходимСвобУч(размер) ТО
ЕСЛИ уборка И (памПослеУП >= ЗапускУП) ТО
Уборка();
ЕСЛИ НЕ НаходимСвобУч(размер) ТО
СоздатьКусок(размер)
КОН
ИНАЧЕ
СоздатьКусок(размер)
КОН
КОН;
ЕСЛИ размер < РазмерКуска ТО
УВЕЛИЧИТЬ(памПослеУП,размер)
КОН;
уч:=СоздатьУч(размер);
ОБХОД.ВПамять(уч+ПозУчОВ,ов);
адрес:=уч+РазмерОУ
КОН Создать;
(******************************************************************************)
ЗАДАЧА Присоединить-(адрОО:ЦЕЛ);
(* Цель: присоединить к среде отдел, где <адрОО> адрес описателя отдела,
* расположенного в постоянной области кода
* Прим: вызывается однократно для каждого отдела при запуске приложения *)
УКАЗ
ПРОВЕРИТЬ(отделов < ВсегоОтделов);
опОтделов[отделов]:=адрОО;
УВЕЛИЧИТЬ(отделов)
КОН Присоединить;
(***************************************************************************
* Запись среза значений переменных работающих задач в исключительном состоянии
***************************************************************************)
ЗАДАЧА^ Пер(нп,тч+:ЦЕЛ);
(******************************************************************************)
ЗАДАЧА Цепь(цепь-:ЦЕПЬ);
УКАЗ
Писать.Цепь(поток,цепь)
КОН Цепь;
(******************************************************************************)
ЗАДАЧА Цел(описание-:ЦЕПЬ; ц:ШИРЦЕЛ);
УКАЗ
Писать.ЧЦел(поток,описание,ц,0,0,0);
КОН Цел;
(******************************************************************************)
ЗАДАЧА Вещ(описание-:ЦЕПЬ; в:ШИРВЕЩ);
УКАЗ
Писать.ЧВещ(поток,описание,в,0,0,0);
КОН Вещ;
(******************************************************************************)
ЗАДАЧА Ряд(нпс,тч+,чслаг,рслаг:ЦЕЛ);
(* Цель: выписать значения всех слагаемых ряда
* До: <нпс> - адрес начала переменной слагаемого
* <тч> - текущий адрес чтения ДВ
* <чслаг> - число слагаемых в ряду
* <рслаг> - размер одного слагаемого *)
ПЕР
зз:ЗНАК; (* ЗНАК значение *)
тчс:ЦЕЛ; (* текущий адрес чтения ДВ слагаемого *)
вид:ЦЕЛ; (* ДВ метка вида *)
имя:Название;(* название переменной (вида) *)
УКАЗ
тчс:=тч;
ВидИмяИзДВ(тчс,вид,имя);
ЕСЛИ вид = вЗнак ТО (* цепочка знаков *)
Цепь('"');
КОЛЬЦО
ЕСЛИ чслаг <= 0 ТО ВЫХОД КОН;
ОБХОД.ИзПамяти(нпс,зз);
ЕСЛИ зз = 0X ТО
ВЫХОД
АЕСЛИ ((зз >= ' ') И (зз <= '#007F')) ИЛИ Буква.Известная(зз) ТО
Цел("%c",ВЦЕЛ(зз))
ИНАЧЕ
Цел("##%.4x",ВЦЕЛ(зз))
КОН;
УВЕЛИЧИТЬ(нпс,рслаг);
УМЕНЬШИТЬ(чслаг)
КОН;
Цепь('"');
тч:=тчс+4 (* +оп *)
ИНАЧЕ
УВЕЛИЧИТЬ(отступ,2);
ПОКА чслаг > 0 ВЫП
тчс:=тч;
Пер(нпс,тчс);
УВЕЛИЧИТЬ(нпс,рслаг);
УМЕНЬШИТЬ(чслаг)
КОН;
УМЕНЬШИТЬ(отступ,2);
тч:=тчс
КОН;
КОН Ряд;
(******************************************************************************)
ЗАДАЧА ИмяЗадачи(аз,тч+:ЦЕЛ);
(* Цель: выписать полное название задачи
* До: <аз> - произвольный адрес внутри кода задачи
* <тч> - текущий адрес чтения ДВ *)
ПЕР
оо:ОпОтдела; (* описатель отдела *)
но:ЦЕЛ; (* № отдела *)
имя:Название;(* имя задачи *)
УКАЗ
НайтиДВЗадачи(аз,но,тч);
ЕСЛИ но < отделов ТО
оо:=ОБХОД.Значение(ОпОтдела,опОтделов[но]);
Цепь(оо.название);
Цепь(".");
ЦепьИзДВ(тч,имя);
Цепь(имя)
ИНАЧЕ
Цепь("ПУСТО");
тч:=0
КОН
КОН ИмяЗадачи;
(******************************************************************************)
ЗАДАЧА Пер(нп,тч+:ЦЕЛ);
(* Цель: выписать значение переменной
* До: <нп> - адрес начала области переменных
* <тч> - текущий адрес чтения ДВ *)
ПЕР
оп:ЦЕЛ; (* адрес переменной относительно <нп> *)
пп:ЦЕЛ; (* полный адрес переменной <нп>+<оп> *)
ов:ЦЕЛ; (* адрес ОВ *)
зз:ЗНАК; (* ЗНАК значение *)
ц8:ОБХОД.Цел8; (* Цел8 значение *)
ц16:ОБХОД.Цел16; (* Цел16 значение *)
ц32:ОБХОД.Цел32; (* Цел32 значение *)
ц64:ОБХОД.Цел64; (* Цел64 значение *)
в32:ОБХОД.Вещ32; (* Вещ32 значение *)
в64:ОБХОД.Вещ64; (* Вещ64 значение *)
ц :ЦЕЛ; (* ЦЕЛ значение *)
дз:ЦЕЛ; (* ДОСТУП значение *)
тб:ЦЕЛ; (* текущее значение бегунка *)
нб:ЦЕЛ; (* начало ряда бегунка *)
кб:ЦЕЛ; (* конец ряда бегунка *)
вид:ЦЕЛ; (* ДВ метка вида *)
имя:Название;(* название переменной (вида) *)
чслаг:ЦЕЛ; (* число слагаемых ряда *)
рслаг:ЦЕЛ; (* размер одного слагаемого *)
чразм:ЦЕЛ; (* число размерностей у вОРяд *)
нразм:ЦЕЛ; (* номер размерности вОРяд *)
длразм:ЦЕЛ; (* длина размерности вОРяд *)
УКАЗ
ВидИмяИзДВ(тч,вид,имя); (* +вид *)
ЦелИзДВ(тч,оп); (* +оп *)
пп:=нп+оп;
Цел("^%*",отступ);
Цепь(имя);
Цепь("=");
ВЫБРАТЬ вид ИЗ
вЯчейка:
ОБХОД.ИзПамяти(пп,ц8);
ц:=ц8;
ЕСЛИ ц < 0 ТО
УВЕЛИЧИТЬ(ц,100H)
КОН;
Цел("%.2xH",ц)
| вКлюч:
ОБХОД.ИзПамяти(пп,ц8);
Цел("%d",ц8)
| вЗнак:
ОБХОД.ИзПамяти(пп,зз);
ЕСЛИ ((зз >= ' ') И (зз <= '#007F')) ИЛИ Буква.Известная(зз) ТО
Цел("'%c'",ВЦЕЛ(зз))
ИНАЧЕ
Цел("%.4xX",ВЦЕЛ(зз))
КОН
| вЦел8:
ОБХОД.ИзПамяти(пп,ц8);
Цел("%d",ц8)
| вЦел16:
ОБХОД.ИзПамяти(пп,ц16);
Цел("%d",ц16)
| вЦел32:
ОБХОД.ИзПамяти(пп,ц32);
Цел("%d",ц32)
| вЦел64:
ОБХОД.ИзПамяти(пп,ц64);
Цел("%d",ц64)
| вВещ32:
ОБХОД.ИзПамяти(пп,в32);
Вещ("%g",в32)
| вВещ64:
ОБХОД.ИзПамяти(пп,в64);
Вещ("%g",в64)
| вМнож:
ОБХОД.ИзПамяти(пп,ц32);
Цел("%.8xH",ц32)
| вЗадача:
ОБХОД.ИзПамяти(пп,дз);
ИмяЗадачи(дз,дз)
| вБегунок:
ОБХОД.ИзПамяти(пп+0,тб);
ОБХОД.ИзПамяти(пп+4,нб);
ОБХОД.ИзПамяти(пп+8,кб);
ЕСЛИ уровеньд >= УровеньД ТО
ПропуститьДВ(нп,тч)
АЕСЛИ тб = 0 ТО
Цепь("ПУСТО");
ПропуститьДВ(нп,тч)
АЕСЛИ тб < нб ТО (* работает, если ВКЛ проверки *)
Цепь("до ряда");
ПропуститьДВ(нп,тч)
АЕСЛИ тб >= кб ТО (* работает, если ВКЛ проверки *)
Цепь("после ряда");
ПропуститьДВ(нп,тч)
ИНАЧЕ
УВЕЛИЧИТЬ(уровеньд);
УВЕЛИЧИТЬ(отступ,2);
Пер(тб,тч);
УМЕНЬШИТЬ(отступ,2);
УМЕНЬШИТЬ(уровеньд)
КОН;
| вДоступ:
ОБХОД.ИзПамяти(пп,дз);
ВидИмяИзДВ(тч,вид,имя); (* +вид *)
ЦелИзДВ(тч,оп); (* +оп *)
ВЫБРАТЬ вид ИЗ
вНабор:
УМЕНЬШИТЬ(тч,4); (* -оп *)
ЕСЛИ дз = 0 ТО
Цепь("ПУСТО")
ИНАЧЕ
ЕСЛИ уровеньд < УровеньД ТО
УВЕЛИЧИТЬ(уровеньд);
ОВИзПер(дз,ов);
УВЕЛИЧИТЬ(отступ,2);
НаборИзД(дз,ов,Пер);
УМЕНЬШИТЬ(отступ,2);
УМЕНЬШИТЬ(уровеньд)
КОН
КОН
| вНеопр:
Цепь("ОБХОД.Доступ")
| вРяд:
ЦелИзДВ(тч,рслаг); (* +рслаг *)
ЦелИзДВ(тч,чслаг); (* +чслаг *)
ЕСЛИ (дз = 0) ИЛИ (уровеньд >= УровеньД) ТО
ЕСЛИ дз = 0 ТО
Цепь("ПУСТО")
КОН;
ПропуститьДВ(нп,тч)
ИНАЧЕ
УВЕЛИЧИТЬ(уровеньд);
Ряд(дз,тч,чслаг,рслаг);
УМЕНЬШИТЬ(уровеньд)
КОН
| вОРяд:
ЦелИзДВ(тч,рслаг); (* +рслаг *)
(* по адресу ОРЯД 0-е слово содержит его размерность,
* а следующие слова содержат РАЗМЕРы его измерений *)
ЕСЛИ (дз = 0) ИЛИ (уровеньд >= УровеньД) ТО
ЕСЛИ дз = 0 ТО
Цепь("ПУСТО")
КОН;
ПропуститьДВ(нп,тч)
ИНАЧЕ
УВЕЛИЧИТЬ(уровеньд);
ОБХОД.ИзПамяти(дз,чразм);
чслаг:=1;
нразм:=1;
ПОКА нразм <= чразм ВЫП
ОБХОД.ИзПамяти(дз+нразм*4,длразм);
чслаг:=чслаг*длразм;
УВЕЛИЧИТЬ(нразм)
КОН;
Ряд(дз+нразм*4,тч,чслаг,рслаг);
УМЕНЬШИТЬ(уровеньд)
КОН
| вБегунок:
ПропуститьДВ(нп,тч)
КОН
| вРяд:
ЦелИзДВ(тч,рслаг); (* +рслаг *)
ЦелИзДВ(тч,чслаг); (* +чслаг *)
Ряд(пп,тч,чслаг,рслаг)
| вНабор:
УВЕЛИЧИТЬ(отступ,2);
НаборИзДВ(нп,тч,Пер);
УМЕНЬШИТЬ(отступ,2)
ИНАЧЕ
Цепь("НЕИЗВЕСТНЫЙ вид")
КОН
КОН Пер;
(******************************************************************************)
ЗАДАЧА ПерСтека(EBP:ЦЕЛ);
ПЕР
EIP:ЦЕЛ; (* значение машинного регистра *)
тч: ЦЕЛ; (* текущий адрес чтения ДВ *)
вид:ЦЕЛ; (* ДВ метка вида *)
уровеньз:ЦЕЛ;(* уровень вложения задач *)
УКАЗ
уровеньз:=0;
КОЛЬЦО
ЕСЛИ уровеньз >= УровеньЗ ТО ВЫХОД КОН;
ОБХОД.ИзПамяти(EBP+4,EIP); (* EIP вызвавшей задачи *)
ОБХОД.ИзПамяти(EBP,EBP); (* EBP вызвавшей задачи *)
ЕСЛИ EBP = 0 ТО ВЫХОД КОН; (* вызвавшая задача - Пускач._Nachalo *)
Цепь("^^Переменные задачи ");
ИмяЗадачи(EIP,тч);
ЕСЛИ тч # 0 ТО
отступ:=2;
КОЛЬЦО
ЦелИзДВ(тч,вид); (* +вид *)
ЕСЛИ вид = вКон ТО ВЫХОД КОН;
УМЕНЬШИТЬ(тч,4); (* -вид *)
Пер(EBP,тч)
КОН
КОН;
УВЕЛИЧИТЬ(уровеньз)
КОН
КОН ПерСтека;
(******************************************************************************)
ЗАДАЧА Ловушка-(адрОО,кодстрока:ЦЕЛ);
(* Цель: ловушка исключений *)
ПЕР
EBP:ЦЕЛ;
код,строка:ЦЕЛ;
оо:ОпОтдела;
текст:ЦЕПЬ[100];
УКАЗ
EBP:=GetEBP();
оо:=ОБХОД.Значение(ОпОтдела,адрОО);
код:=кодстрока ОСТАТОК 10000H;
строка:=кодстрока ДЕЛИТЬ 10000H;
Вывод.Цепь('^Сработала ловушка в отделе "');
Вывод.Цепь(оо.название);
Текст.ИзЧЦел('" на строке %d.^Причина: ',строка,0,0,0,текст);
Вывод.Цепь(текст);
ВЫБРАТЬ код ИЗ
| пределыАвОст: текст:='выход значения за допустимые пределы'
| номерАвОст: текст:='неверный номер переменной ряда'
| арифмАвОст: текст:='арифметическое переполнение'
| охранаАвОст: текст:='неверный размещённый вид'
| пустоАвОст: текст:='значение доступа "ПУСТО"'
| дляАвОст: текст:='у "ДЛЯ" нет "ИНАЧЕ"'
| выбратьАвОст: текст:='у "ВЫБРАТЬ" нет "ИНАЧЕ"'
| ответАвОст: текст:='не определён ответ'
| проверитьАвОст:текст:='"ПРОВЕРИТЬ" выдаёт ошибку'
| нольАвОст: текст:='деление на ноль'
| бегунокАвОст: текст:='бегунок вне ряда'
ИНАЧЕ
Текст.ИзЧЦел('код %d',код,0,0,0,текст)
КОН;
Вывод.Цепь(текст);
Вывод.Цепь('.^Подробности см. в файле "Срез.пер".^');
поток:=Писать.Открыть("Срез.пер");
поток.видЗнаков:=Писать.знУни;
Цепь(текст);
ПерСтека(EBP);
Писать.Закрыть(поток);
СТОП(код)
КОН Ловушка;
(******************************************************************************)
УКАЗ
уборка:=ВКЛ
КОН СРЕДА.
|
|