(*~\Глагол\ПриложенияLink\МПГ2008 (комп., но не раб.)\~~~~~~~~~~~~~~~~~~~~~~~~*)
(**)                                            ОТДЕЛ Узел;
(*============================================================================* 
 * НАЗНАЧЕНИЕ: работа с узлами
 * ВНИМАНИЕ: зСместить, зОбнулить пока не отрабатываются !
 *============================================================================*)

ИСПОЛЬЗУЕТ 
  ОБХОД,
        (*  \Глагол\              *)
  Асм     ИЗ "..\..\Отделы\Заграница\",
        (*  \Глагол\              *)
  Пустой  ИЗ "..\..\Отделы\Иное\",

  Слово,
  Рег,
  Код,
  Данные,
  Настрой,
  Ошибка;

ПОСТ
       (* род узлов *)
  уПустой-    = 20;
  уАдрО-      = 4; (* общие переменные отдела *) 
  уАдрС-      = 1;  
  уАдрСС-     = 2; (* доступ к рядам со сдвигаемым смещением 2^.. *)
  уАдрЗС-     = 9; (* занесение в стек *)
  уАдрСАдрС-  = 3;  
  уПост-      = 5;
  уРег-       = 6;
  уКодУсл-    = 8;
  уВид-       = 14;
  уЗадача-    = 15;
  уВстрЗадача-= 16;

(*
  ро - регистр основы
  ср - сдвигаемый регистр смещения

 роду      |  ро       a        b       Ссылка на:
--------------------------------------------------------------------------------
 уПост     |  -        знач     -
 уРег      |  ро       -        -      
 уАдрО     |  -        смещ     -       [имя+смещ]       
 уАдрС     |  ро       смещ     -       [ро+смещ]       
 уАдрСС    |  ро       ср       сдвиг   [ро+(ср LSL сдвиг)]
 уАдрЗС    |  ро(SP)   смещ(-4) -       [ро], ро+=смещ
 уАдрСАдрС |  ро       смещ     смещ2   [[ро+смещ]+смещ2]
 уКодУсл   |  условие  мВкл     мОткл                        *)

ВИД
  нВид- = НАБОР
        роду+:ЦЕЛ;
    ро+,a+,b+:ЦЕЛ;
         вид+:Данные.ДкВидуВид;
        понД+:Данные.ДкВидуПонятие;
    толькочт+:КЛЮЧ
  КОН;

ПОСТ
  множЦелых = {Данные.вЦел16,Данные.вЦел32};


(*-оооооооооооооо- опережающие определения/заготовки задач -ооооооооооооооооо-*)

ЗАДАЧА^ ВыставитьКУ(у+:Узел.нВид);


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Создать-(понД:Данные.ДкВидуПонятие; у+:Узел.нВид);
УКАЗ
  у.толькочт:=ОТКЛ;
  ВЫБРАТЬ понД.родп ИЗ
  | Данные.пПер:
      ЕСЛИ        (Данные.прТолькоЧт В понД.признаки)
           И
             НЕ ( (Данные.прОбщаяПер В понД.признаки)
                 И
                  (Данные.прТекущийОтд В понД.признаки)
                )
      ТО
        у.толькочт:=ВКЛ
      КОН;
      ЕСЛИ Данные.прОбщаяПер В понД.признаки ТО
        у.роду:=уАдрО
      ИНАЧЕ
        у.роду:=уАдрС;
        у.ро:=Рег.FP
      КОН;
      у.a:=понД.адр
  | Данные.пСсылка:
      ЕСЛИ Данные.прТолькоЧт В понД.признаки ТО
        у.толькочт:=ВКЛ
      КОН;
      у.роду:=уАдрСАдрС;
      у.ро:=Рег.FP;
      у.a:=понД.адр;
      у.b:=0 
  | Данные.пПост:
      у.роду:=уПост;
      у.a:=понД.адр
  | Данные.пВид:
      у.роду:=уВид
  | Данные.пЗадача:
      у.роду:=уЗадача
  | Данные.пВстрЗадача:
      у.роду:=уВстрЗадача
  КОН;
  у.понД:=понД;
  у.вид:=понД.вид
КОН Создать;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА СоздатьЦелПост-(у+:Узел.нВид; ц:ЦЕЛ);
УКАЗ
  у.роду:=уПост;
  у.вид:=Данные.цел32вид;
  у.a:=ц
КОН СоздатьЦелПост;

(*----------------------------------------------------------------------------*)
ЗАДАЧА СоздатьКУ(у+:Узел.нВид; ку:ЦЕЛ);
УКАЗ
  у.роду:=уКодУсл;
  у.вид:=Данные.ключвид;
  у.ро:=ку;
  у.a:=Код.ПолучитьМетку();
  у.b:=Код.ПолучитьМетку()
КОН СоздатьКУ;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПереходПоОтклНа-(у+:Узел.нВид):ЦЕЛ;
(*
 * Цель:  условный переход по ОТКЛ вперёд на метку <у.b>
 * До:    <у> - узел с ключём
 * Ответ: метка <у.b>
 *)
УКАЗ
  ВыставитьКУ(у);
  Код.ПереходПоКУ(у.b,Код.ОбратныйКУ(у.ро));
  Код.ПоставитьМетку(у.a);
  ВОЗВРАТ у.b
КОН ПереходПоОтклНа;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПовторятьДо-(у+:Узел.нВид; мПовторять:ЦЕЛ);
(*
 * Цель:  отработка условия перехода у ПОВТОРЯТЬ ДО
 * До:    <у>          - узел с ключём ДО
 *        <мПовторять> - метка начала ПОВТОРЯТЬ
 * После: 
 *        условный переход по ОТКЛ и по метке <у.b> (ОТКЛ) назад в <мПовторять>
 *        в конце будет метка <у.a> (ВКЛ)
 *)
УКАЗ                          
  ВыставитьКУ(у);
  Код.ПереходПоКУ(у.a,у.ро);
  Код.ПоставитьМетку(у.b);
  Код.ПереходНа(мПовторять);
Код.ПоставитьМетку(у.a)
КОН ПовторятьДо;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Освободить-(у+:Узел.нВид);
УКАЗ
  ЕСЛИ НЕ (у.роду В {уПустой,уПост,уКодУсл}) ТО
      Рег.Освободить(у.ро);
    ЕСЛИ у.роду = уАдрСС ТО
      Рег.Освободить(у.a)
    КОН
  КОН;
  у.роду:=уПустой
КОН Освободить;

(*----------------------------------------------------------------------------*)
ЗАДАЧА АдрОвАдрС(у+:Узел.нВид);
(* адресацию переменных отдела переводит на адресацию по смещению *)
ПЕР
  ро:ЦЕЛ; (* новый ро *)
УКАЗ
  ПРОВЕРИТЬ(у.роду В {уАдрО,уЗадача});
  Рег.Занять(ро); 
  Код.ЗагрузитьОбщАдр(ро,у.понД);
  ЕСЛИ у.роду = уЗадача ТО
    у.a:=0
  КОН;
  у.роду:=уАдрС;
  у.ро:=ро
КОН АдрОвАдрС;

(*----------------------------------------------------------------------------*)
ЗАДАЧА АдрСАдрСвАдрС(у+:Узел.нВид);
(* До:    у.роду = уАдрСАдрС
 * После: у.роду = уАдрС *)
ПЕР
  ро:ЦЕЛ; (* новый ро *)
УКАЗ
  ПРОВЕРИТЬ(у.роду = уАдрСАдрС);
  Рег.Занять(ро); (* чтобы не затереть FP *)
  Код.ПЗС1(Код.LDR,ро,у.ро,у.a);
  у.a:=у.b;
  у.ро:=ро;
  у.роду:=уАдрС
КОН АдрСАдрСвАдрС;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ПереписатьПерВРег(у+:Узел.нВид):ЦЕЛ;
(*
 * Цель:  переписать значение переменной <у> в регистр,
 *        оставляя возможность повторного использования переменной <у> 
 * До:    у.роду В {уАдрО,уАдрС,уАдрСС,уАдрСАдрС}
 * После: у.роду В {уАдрС,уАдрСС}
 * Возвр: регистр, содержащий полученное значение
 *)
ПЕР
  цр:ЦЕЛ; (* целевой регистр *)
УКАЗ
  ПРОВЕРИТЬ(НЕ (у.роду В {уРег,уПост}));
  ЕСЛИ у.роду = уАдрСАдрС ТО
    АдрСАдрСвАдрС(у)
  АЕСЛИ у.роду В {уАдрО,уЗадача} ТО
    АдрОвАдрС(у)
  КОН;
  Рег.Занять(цр);
  ЕСЛИ у.роду = уАдрСС ТО
    ВЫБРАТЬ у.вид.родв ИЗ
      Данные.вЯчейка,Данные.вЗнак,Данные.вКлюч:
        Код.ПЗС(Код.LDRB,цр,у.ро,у.a,у.b)
    | Данные.вЦел16:
        (* у.а заменили на цр *)
        Код.ОД(Код.MOV,цр,0,у.a,Код.LSL,у.b+16);  (* LSL y.b *)
        Код.УЗС(Код.LDRSH,цр,у.ро,цр)
    | Данные.вДоступ,Данные.вЗадача,Данные.вЦел32,Данные.вМнож:
        Код.ПЗС(Код.LDR,цр,у.ро,у.a,у.b)
    КОН
  ИНАЧЕ (* у.роду = уАдрС *)
    ВЫБРАТЬ у.вид.родв ИЗ
      Данные.вЯчейка,Данные.вЗнак,Данные.вКлюч:
        Код.ПЗС1(Код.LDRB,цр,у.ро,у.a)
    | Данные.вЦел16:
        Код.УЗС1(Код.LDRSH,цр,у.ро,у.a)
    | Данные.вДоступ,Данные.вЗадача,Данные.вЦел32,Данные.вМнож:
        Код.ПЗС1(Код.LDR,цр,у.ро,у.a)
    КОН
  КОН;
  ВОЗВРАТ цр
КОН ПереписатьПерВРег;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ЗагрузитьВРег-(у+:Узел.нВид);
(*
 * зугружает <у> в регистр
 * До:    у.роду В {уРег,уПост,уКодУсл,уАдрС,уАдрСС,уАдрСАдрС}
 * После: у.роду В {уРег}
 *)  
ПЕР
  ку:ЦЕЛ; (* код условия *)
  цр:ЦЕЛ; (* целевой регистр *)
  метка:ЦЕЛ;
УКАЗ
  ЕСЛИ у.роду = уРег ТО ВОЗВРАТ КОН;
  ЕСЛИ у.роду = уКодУсл ТО
    ку:=у.ро;
    Рег.Занять(цр);
    ЕСЛИ (у.a = 0) И (у.b = 0) ТО
      (* метки пусты, можно отработать попроще *)
      Код.будетКУ:=Код.ОбратныйКУ(ку);
      Код.ОД1(Код.MOV,цр,0,0);
      Код.будетКУ:=ку;
      Код.ОД1(Код.MOV,цр,0,1)
    ИНАЧЕ
      метка:=Код.ПолучитьМетку();
      Код.ПереходПоКУ(у.b,Код.ОбратныйКУ(ку));
Код.ПоставитьМетку(у.a);
      Код.ОД1(Код.MOV,цр,0,1);
      Код.ПереходНа(метка);
Код.ПоставитьМетку(у.b);
      Код.ОД1(Код.MOV,цр,0,0);
Код.ПоставитьМетку(метка);
    КОН
  АЕСЛИ у.роду = уПост ТО
    Рег.Занять(цр);
    Код.ЗагрузитьПост(цр,у.a)
  ИНАЧЕ
    (* у.роду В {уАдрС,уАдрСС,уАдрСАдрС} *)
    цр:=ПереписатьПерВРег(у);
    Освободить(у)
  КОН;
  у.ро:=цр;
  у.роду:=уРег;
КОН ЗагрузитьВРег;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ЗагрузитьВТребРег(у+:Узел.нВид; р:ЦЕЛ);
(* загружает <у> в регистр <р>
 * До:    у.роду В {уКодУсл,уРег,уПост,уАдрС,уАдрСС,уАдрСАдрС}
 * После: у.роду В {уРег} *)
УКАЗ
  Рег.Нужен(р);
  ЗагрузитьВРег(у);
  ЕСЛИ у.ро # р ТО
    Рег.Нужен(р);
    Рег.Занять(р);
    Код.ОД(Код.MOV,р,0,у.ро,0,0);
    Рег.Освободить(у.ро);
    у.ро:=р
  КОН
КОН ЗагрузитьВТребРег;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Переписать-(уа+,уб+:Узел.нВид); 
(* Цель:  уб:=уа
 * До:    уб.роду В {уРег,уАдрО,уАдрС,уАдрСС,уАдрЗС,уАдрСАдрС}
 * После: уа и уб пустые *)
УКАЗ
  ЕСЛИ уб.роду = уРег ТО
    Рег.Освободить(уб.ро);
    ЗагрузитьВТребРег(уа,уб.ро)
  ИНАЧЕ
    ЗагрузитьВРег(уа);
    ЕСЛИ уб.роду = уАдрСАдрС ТО
      АдрСАдрСвАдрС(уб)
    АЕСЛИ уб.роду В {уАдрО,уЗадача} ТО
      АдрОвАдрС(уб)
    КОН;
    ЕСЛИ уб.роду = уАдрСС ТО
      ВЫБРАТЬ уб.вид.родв ИЗ
        Данные.вЯчейка,Данные.вЗнак,Данные.вКлюч:
          Код.ПЗС(Код.STRB,уа.ро,уб.ро,уб.a,уб.b)
      | Данные.вЦел16:
          Код.ОД(Код.MOV,уб.a,0,уб.a,Код.LSL,уб.b+16); (* LSL уб.b *)
          Код.УЗС(Код.STRH,уа.ро,уб.ро,уб.a)
      | Данные.вДоступ,Данные.вЗадача,Данные.вЦел32,Данные.вМнож:
          Код.ПЗС(Код.STR,уа.ро,уб.ро,уб.a,уб.b)
      КОН
    АЕСЛИ уб.роду = уАдрЗС ТО
      Код.ВСтек(уа.ро)
    ИНАЧЕ
      ВЫБРАТЬ уб.вид.родв ИЗ
        Данные.вЯчейка,Данные.вЗнак,Данные.вКлюч:
          Код.ПЗС1(Код.STRB,уа.ро,уб.ро,уб.a)
      | Данные.вЦел16:
          Код.УЗС1(Код.STRH,уа.ро,уб.ро,уб.a)
      | Данные.вДоступ,Данные.вЗадача,Данные.вЦел32,Данные.вМнож:
          Код.ПЗС1(Код.STR,уа.ро,уб.ро,уб.a)
      КОН
    КОН
  КОН;
  Освободить(уа);
  Освободить(уб)
КОН Переписать;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ВыставитьКУ(у+:Узел.нВид);
УКАЗ
  ЕСЛИ у.вид.родв # Данные.вКлюч ТО
    Ошибка.Отметить(Ошибка.ОЖИДАЕТСЯ_КЛЮЧ)
  КОН;
  ЕСЛИ у.роду # уКодУсл ТО
    ЕСЛИ у.роду = уПост ТО
      ЕСЛИ у.a = 0 ТО
        СоздатьКУ(у,Код.NV)
      ИНАЧЕ
        СоздатьКУ(у,Код.AL)
      КОН
    ИНАЧЕ
      ЗагрузитьВРег(у);
      Код.будетS:=ВКЛ;
      Код.ОД1(Код.CMP,0,у.ро,0);
      Освободить(у);
      СоздатьКУ(у,Код.NE)
    КОН
  КОН
КОН ВыставитьКУ;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА СнятьКУ-(у+:Узел.нВид);
УКАЗ
  ЕСЛИ у.роду = уКодУсл ТО
    ЕСЛИ  у.ро = Код.AL ТО
      у.роду:=уПост;
      у.a:=1 (* ВКЛ *)
    АЕСЛИ у.ро = Код.NV ТО
      у.роду:=уПост;
      у.a:=0 (* ОТКЛ *)
    КОН
  КОН
КОН СнятьКУ;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ЗагрузитьАдр-(у+:Узел.нВид);
(*
 * загружает адрес <у> в регистр
 * До:    у.роду В {уПост+вЦепь,уАдрО,уАдрС,уАдрСС,уАдрСАдрС}
 * После: у.роду В {уРег}
 *)
ПЕР
  цр:ЦЕЛ; (* целевой регистр *)
УКАЗ
  ЕСЛИ (у.роду = уПост) И (у.вид.родв = Данные.вЦепь) ТО
    Рег.Занять(цр);
    ЕСЛИ у.понД.адр = 0 ТО
      Код.ВводЦепочки(у.понД)
    КОН;
    Код.ЗагрузитьЦепьАдр(цр,у.понД.адр)
  ИНАЧЕ
    ЕСЛИ у.роду В {уАдрО,уЗадача} ТО
      АдрОвАдрС(у)
    КОН;
    ЕСЛИ у.ро = Рег.FP ТО
      Рег.Занять(цр)
    ИНАЧЕ
      цр:=у.ро
    КОН;
    ВЫБРАТЬ у.роду ИЗ
      уАдрС:
        ЕСЛИ у.a # 0 ТО
          Код.ОД1(Код.ADD,цр,у.ро,у.a)
        АЕСЛИ цр # у.ро ТО
          Код.ОД(Код.MOV,цр,0,у.ро,0,0)
        КОН
    | уАдрСС:
        Код.ОД(Код.ADD,цр,у.ро,у.a,Код.LSL,у.b+16) 
    | уАдрСАдрС:
        Код.ПЗС1(Код.LDR,цр,у.ро,у.a);
        ЕСЛИ у.b # 0 ТО
          Код.ОД1(Код.ADD,цр,цр,у.b)
        КОН
    КОН;
    ЕСЛИ цр # у.ро ТО
      Рег.Освободить(у.ро)
    КОН
  КОН;
  у.роду:=уРег;
  у.ро:=цр
КОН ЗагрузитьАдр;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВСтек-(у+:Узел.нВид); 
(* Цель:  сохраняет <у> в стеке
 * До:    у.роду В {уРег,уПост,уКодУсл,уАдрС,уАдрСС,уАдрСАдрС}
 * После: у пустой *)
УКАЗ
  ЗагрузитьВРег(у);
  Код.ВСтек(у.ро);
  Освободить(у)
КОН ВСтек;

(*----------------------------------------------------------------------------*)
ЗАДАЧА РазмерЦепи(у+:Узел.нВид); 
(* Цель:  находит размер для цепи
 * До:    у.вид.родв = Данные.вЦепь
 * До:    у.роду В {уРег,уПост,уКодУсл,уАдрС,уАдрСС,уАдрСАдрС}
 * После: у.роду В {уПост,уАдрС}
 *        значение регистров не изменяется *)
УКАЗ
  ПРОВЕРИТЬ(у.вид.родв = Данные.вЦепь);
  ЕСЛИ у.вид.размер = 0 ТО (* оЦепь *)
    ПРОВЕРИТЬ(у.роду = уАдрСАдрС);
    у.роду:=уАдрС;
    УВЕЛИЧИТЬ(у.a,4);
    у.вид:=Данные.цел32вид
  ИНАЧЕ
    СоздатьЦелПост(у,у.вид.размер)
  КОН
КОН РазмерЦепи;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ОД(нкд:ЦЕЛ; уа+,уб+:Узел.нВид);
(* Цель:  уа':=уа нкд уб
 * После: уб пустой *)
УКАЗ
  ЗагрузитьВРег(уа);
  ЕСЛИ уб.роду = уПост ТО
    Код.ОД1(нкд,уа.ро,уа.ро,уб.a)
  ИНАЧЕ
    ЗагрузитьВРег(уб);
    Код.ОД(нкд,уа.ро,уа.ро,уб.ро,0,0);
    Освободить(уб)
  КОН
КОН ОД;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ОДсОбрЗап(нкд:ЦЕЛ; уа+,уб+:Узел.нВид);
(* Цель:  уа:=уа нкд уб
 * После: уб пустой *)
ПЕР
  уа1:Узел.нВид;
УКАЗ
  ПРОВЕРИТЬ(НЕ (уа.роду В {уРег,уПост}));
  уа1.роду:=уРег;
  уа1.вид:=уа.вид;
  уа1.ро:=ПереписатьПерВРег(уа);
  ЕСЛИ уб.роду = уПост ТО
    Код.ОД1(нкд,уа1.ро,уа1.ро,уб.a)
  ИНАЧЕ
    ЗагрузитьВРег(уб);
    Код.ОД(нкд,уа1.ро,уа1.ро,уб.ро,0,0);
    Освободить(уб)
  КОН;
  Переписать(уа1,уа)
КОН ОДсОбрЗап;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Сравнить(уа+,уб+:Узел.нВид; ку:ЦЕЛ);
(* Цель:  уа:=уа ? уб
 * До:    ку - код условия для сравнения
 * После: уа.роду=УКодУсл, уб пустой *)
УКАЗ
  ЗагрузитьВРег(уа);
  ЕСЛИ уб.роду = уПост ТО
    Код.будетS:=ВКЛ;
    Код.ОД1(Код.CMP,0,уа.ро,уб.a)
  ИНАЧЕ
    ЗагрузитьВРег(уб);
    Код.будетS:=ВКЛ;
    Код.ОД(Код.CMP,0,уа.ро,уб.ро,0,0);
    Освободить(уб)
  КОН;
  Освободить(уа);
  СоздатьКУ(уа,ку)
КОН Сравнить;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ОпредЦелВид-(у+:Узел.нВид);
УКАЗ
  ЕСЛИ (-8000H <= у.a) И (у.a <= 7FFFH) ТО
    у.вид:=Данные.цел16вид
  ИНАЧЕ
    у.вид:=Данные.цел32вид
  КОН
КОН ОпредЦелВид;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА АдрПерРяда-(уа+,уб+:Узел.нВид);
(*
 *     уа <- адрес уа[уб]
 *)
ПЕР
  овид:Данные.ДкВидуВид;   (* вид переменных ряда *)

  показательСтепени2:ЦЕЛ;  (* побочный ответ подЗадачи ПроверкаНаСтепень2х(N) *)
                           (* такая, что 2^показательСтепени2 = овид.размер   *)
     родв:ЦЕЛ;
     смещ:ЦЕЛ;
  размеро:ЦЕЛ;
       уп:Узел.нВид;

(*----------------------------------------- подЗадача (проверка N на степень 2-х) ---*)
  ЗАДАЧА ПроверкаНаСтепень2х(N:ЦЕЛ):КЛЮЧ;
  (*
   * Цель:  пытается найти представление <N> в виде 2^v
   * До:           <N> - исследуемое число
   * После: <показательСтепени2> - найденное v, если это возможно
   * Ответ: ВКЛ, если N = 2^v
   *)
  УКАЗ
                  показательСтепени2:=0;
    ЕСЛИ N > 0 ТО
      ПОКА ЧЕТ(N) ВЫП
               N:=N ДЕЛИТЬ 2;
        УВЕЛИЧИТЬ(показательСтепени2)
      КОН;
      ЕСЛИ     N = 1 ТО
        ВОЗВРАТ ВКЛ
      КОН
    КОН;
    ВОЗВРАТ ОТКЛ
  КОН ПроверкаНаСтепень2х;
(*
  ЗАДАЧА Степень2(остаток:ЦЕЛ):КЛЮЧ;
  УКАЗ
                показательСтепени2:=0;
    ПОКА ЧЕТ(остаток) ВЫП
      остаток:=остаток ДЕЛИТЬ 2;
      УВЕЛИЧИТЬ(показательСтепени2)
    КОН;
    ВОЗВРАТ остаток = 1
  КОН Степень2;
*)
УКАЗ
  ЕСЛИ НЕ (уб.вид.родв В множЦелых) ТО
    Ошибка.Отметить(Ошибка.НОМЕР_НЕ_ЦЕЛЫЙ)
  КОН;
  родв:=уа.вид.родв;
  ЕСЛИ родв В {Данные.вРяд,Данные.вЦепь,Данные.вЯчейки} ТО
    овид:=уа.вид.овид
  ИНАЧЕ
    Ошибка.Отметить(Ошибка.ЭТО_НЕ_РЯД)
  КОН;
  размеро:=овид.размер;
  ЕСЛИ уб.роду = уПост ТО
    смещ:=уб.a*размеро;
    ЕСЛИ (смещ < 0) ИЛИ
         ((родв = Данные.вРяд) ИЛИ (родв = Данные.вЦепь) И (уа.вид.размер # 0)) И (смещ >= уа.вид.размер) ТО
      Ошибка.Отметить(Ошибка.ВЫХОД_ЗА_ГРАНИЦЫ_РЯДА)
    КОН;
    ЕСЛИ уа.роду = уАдрСАдрС ТО
      УВЕЛИЧИТЬ(уа.b,смещ)
    ИНАЧЕ
      ПРОВЕРИТЬ(уа.роду В {уАдрС,уАдрО});
      УВЕЛИЧИТЬ(уа.a,смещ)
    КОН
  ИНАЧЕ
    ЗагрузитьВРег(уб);
    ЗагрузитьАдр(уа);
    ЕСЛИ ПроверкаНаСтепень2х(размеро) ТО
      уа.роду:=уАдрСС;
      уа.a:=уб.ро;
      уа.b:=показательСтепени2
    ИНАЧЕ
      СоздатьЦелПост(уп,размеро);
      ЗагрузитьВРег(уп);
      Код.Умн(Код.MLA,уа.ро,уп.ро,уб.ро,уа.ро);
      Освободить(уб);
      Освободить(уп);
      уа.роду:=уАдрС;
      уа.a:=0
    КОН
  КОН;
  уа.вид:=овид
КОН АдрПерРяда;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Свойство-(у+:Узел.нВид; понД:Данные.ДкВидуПонятие);
(*
 *    у.вид.родв = Данные.вНабор,
 * понД.родп     = Данные.пСвойство
 *)
УКАЗ
  ПРОВЕРИТЬ(понД.родп = Данные.пСвойство);
  ЕСЛИ у.роду = уАдрО ТО
    АдрОвАдрС(у);
    УВЕЛИЧИТЬ(у.a,понД.адр)
  АЕСЛИ у.роду = уАдрС ТО
    УВЕЛИЧИТЬ(у.a,понД.адр)
  АЕСЛИ у.роду = уАдрСАдрС ТО
    УВЕЛИЧИТЬ(у.b,понД.адр)
  АЕСЛИ понД.адр # 0 ТО
    ЗагрузитьАдр(у);
    у.роду:=уАдрС;
       у.a:=понД.адр
  КОН;
  ЕСЛИ (у.вид.нвхотд # 0) И (Данные.прТолькоЧт В понД.признаки) ТО
    у.толькочт:=ВКЛ
  ИНАЧЕ
    у.толькочт:=ОТКЛ
  КОН;
  у.вид:=понД.вид;
  у.понД:=понД     (* было ПУСТО *)
КОН Свойство;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Ссылка-(у+:Узел.нВид);
УКАЗ
  ЕСЛИ у.вид.родв # Данные.вДоступ ТО
    Ошибка.Отметить(Ошибка.ССЫЛКА_НЕ_ОТ_ДОСТУПА)
  КОН; 
  ЕСЛИ у.роду = уАдрС ТО
    у.роду:=уАдрСАдрС;
    у.b:=0
  ИНАЧЕ
    ЗагрузитьВРег(у);
    у.роду:=уАдрС;
    у.a:=0
  КОН;
  у.вид:=у.вид.овид;
  у.понД:=у.вид.понвида
КОН Ссылка;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВМнож-(уа+,уб+:Узел.нВид);
(* Цель:  уа:=уа В уб
 * После: уа.роду = уКодУсл
 *        уб пустой *)
ПЕР
  вр:ЦЕЛ; (* временный регистр *)
  ку:ЦЕЛ; (* код условия *)
УКАЗ
  ЕСЛИ НЕ (уа.вид.родв В множЦелых) ИЛИ (уб.вид.родв # Данные.вМнож) ТО
    Ошибка.Отметить(Ошибка.ВИД_НЕ_ДЛЯ_В)
  КОН;
  ку:=Код.NV;
  ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
    ЕСЛИ (уа.a < 0) ИЛИ (уа.a > 31) ТО
      Ошибка.Отметить(Ошибка.ГРАНИЦЫ_МНОЖЕСТВА)
    КОН;
    ЕСЛИ уа.a В ОБХОД.Значение(МНОЖ,уб.a) ТО
      ку:=Код.AL
    КОН
  АЕСЛИ уа.роду = уПост ТО
    ЕСЛИ (уа.a < 0) ИЛИ (уа.a > 31) ТО
      Ошибка.Отметить(Ошибка.ГРАНИЦЫ_МНОЖЕСТВА)
    КОН;
    ЗагрузитьВРег(уб);
    Код.ОД1(Код.TST,0,уб.ро,Асм.Сдвиг(1,уа.a));
    Освободить(уб);
    ку:=Код.NE
  ИНАЧЕ
    ЗагрузитьВРег(уа);
    ЗагрузитьВРег(уб);
    Рег.Занять(вр);
    Код.ОД1(Код.MOV,вр,0,1);
    Код.ОД(Код.TST,0,уб.ро,вр,Код.LSL,уа.ро); (* TST уб.ро, вр LSL уа.ро *)
    (* +1 -> ро*10H - рег *)
    Освободить(уб);
    Освободить(уа);
    Рег.Освободить(вр);
    ку:=Код.NE
  КОН;
  СоздатьКУ(уа,ку)
КОН ВМнож;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Внести1-(уа+,уб+:Узел.нВид);
(* Цель:  внести во множество 1 элемент (уа:={уб})
 * После: уа.роду В {уРег,уПост}
 *        уб пустой *)
УКАЗ
  ЕСЛИ НЕ (уб.вид.родв В множЦелых) ТО
    Ошибка.Отметить(Ошибка.МНОЖЕСТВО_НЕ_ИЗ_ЦЕЛЫХ)
  КОН;
  ЕСЛИ уб.роду = уПост ТО
    ЕСЛИ (уб.a < 0) ИЛИ (уб.a > 31) ТО
      Ошибка.Отметить(Ошибка.ГРАНИЦЫ_МНОЖЕСТВА)
    КОН;
    уа.роду:=уПост;
    уа.a:=Асм.Сдвиг(1,уб.a)
  ИНАЧЕ
    уа.роду:=уРег;
    Рег.Занять(уа.ро);
    Код.ОД1(Код.MOV,уа.ро,0,1);
    ЗагрузитьВРег(уб);
    Код.ОД(Код.MOV,уа.ро,0,уа.ро,Код.LSL,уб.ро); (* MOV уа.ро,уа.ро LSL уб.ро *)
    Освободить(уб)
  КОН; 
  уа.вид:=Данные.множвид
КОН Внести1;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВнестиНеск-(уа+,уб+,ув+:Узел.нВид);
(* Цель:  внести во множество несколько элементов (уа:={уб..ув})
 * После: уа.роду В {уРег,уПост}
 *        уб и ув пустой *)
ПЕР
  вр:ЦЕЛ; (* временный регистр *)
УКАЗ
  ЕСЛИ НЕ (уб.вид.родв В множЦелых) ИЛИ НЕ (ув.вид.родв В множЦелых) ТО
    Ошибка.Отметить(Ошибка.МНОЖЕСТВО_НЕ_ИЗ_ЦЕЛЫХ)
  КОН;
  ЕСЛИ (уб.роду = уПост) И (ув.роду = уПост) ТО
    ЕСЛИ (уб.a < 0) ИЛИ (уб.a > 31) ИЛИ (ув.a < 0) ИЛИ (ув.a > 31) ТО
      Ошибка.Отметить(Ошибка.ГРАНИЦЫ_МНОЖЕСТВА)
    АЕСЛИ уб.a > ув.a ТО
      Ошибка.Отметить(Ошибка.ПЕРЕПУТАНЫ_ГРАНИЦЫ)
    КОН;
    уа.роду:=уПост;
    уа.a:=Асм.Сдвиг(-1,уб.a)-Асм.Сдвиг(-2,ув.a)
  ИНАЧЕ
    уа.роду:=уРег;
    ЕСЛИ уб.роду = уПост ТО
      уб.a:=Асм.Сдвиг(-1,уб.a);
      ЗагрузитьВРег(уб);
      уа.ро:=уб.ро
    ИНАЧЕ
      Рег.Занять(уа.ро);
      Код.ОД1(Код.MVN,уа.ро,0,0); (* MOV уа.ро,-1 *)
      ЗагрузитьВРег(уб);
      Код.ОД(Код.MOV,уа.ро,0,уа.ро,Код.LSL,уб.ро); (* MOV уа.ро,-1 LSL уб.ро *)
      Освободить(уб)
    КОН;
    ЕСЛИ ув.роду = уПост ТО
      Код.ОД1(Код.BIC,уа.ро,уа.ро,Асм.Сдвиг(-2,ув.a)) (* BIC уа.ро,уа.ро,ув *)
    ИНАЧЕ
      Рег.Занять(вр);
      Код.ОД1(Код.MVN,вр,0,1); (* MOV вр,-2 *)
      ЗагрузитьВРег(ув);
      Код.ОД(Код.BIC,уа.ро,уа.ро,вр,Код.LSL,ув.ро); (* BIC уа.ро,уа.ро,-2 LSL ув.ро *)
      Освободить(ув);
      Рег.Освободить(вр)
    КОН
  КОН;
  уа.вид:=Данные.множвид
КОН ВнестиНеск;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Действие1-(действие:ЦЕЛ; у+:Узел.нВид);
(* действие с одним данным *)
ПЕР
  множ:МНОЖ; 
  родв,a:ЦЕЛ; 
УКАЗ
  родв:=у.вид.родв;
  ВЫБРАТЬ действие ИЗ
  | Слово.плюс:
      ЕСЛИ НЕ (родв В множЦелых) ТО
        Ошибка.Отметить(Ошибка.ПЛЮС_НЕПРИМЕНИМ)
      КОН
  | Слово.минус:
      ЕСЛИ родв В множЦелых ТО
        ЕСЛИ у.роду = уПост ТО
          у.a:=-у.a;
          ОпредЦелВид(у)
        ИНАЧЕ
          ЗагрузитьВРег(у);
          Код.ОД1(Код.RSB,у.ро,у.ро,0)
        КОН
      АЕСЛИ родв = Данные.вМнож ТО
        ЕСЛИ у.роду = уПост ТО
          множ:=ОБХОД.Значение(МНОЖ,у.a);
          у.a:=ОБХОД.Значение(ЦЕЛ,-множ)
        ИНАЧЕ
          ЗагрузитьВРег(у);
          Код.ОД(Код.MVN,у.ро,0,у.ро,0,0)
        КОН
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.МИНУС_НЕПРИМЕНИМ)
      КОН
  | Слово.и:
      ВыставитьКУ(у);
      Код.ПереходПоКУ(у.b,Код.ОбратныйКУ(у.ро));
      Код.ПоставитьМетку(у.a); (*!*)
  | Слово.или:
      ВыставитьКУ(у);
      Код.ПереходПоКУ(у.a,у.ро);
      Код.ПоставитьМетку(у.b); (*!*)
  | Слово.не:
      ВыставитьКУ(у);
      у.ро:=Код.ОбратныйКУ(у.ро);
      a:=у.a;
      у.a:=у.b;
      у.b:=a
  | Слово.равно..Слово.бравно:
      ЕСЛИ у.роду = уКодУсл ТО
        ЗагрузитьВРег(у)
      КОН
  КОН
КОН Действие1;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ЗнакВЦепь-(у+:Узел.нВид);
ПЕР
  цепьД:Пустой.ДкЦепи;
УКАЗ
  ЕСЛИ (у.вид.родв = Данные.вЗнак) И (у.роду = уПост) ТО
    СОЗДАТЬ(цепьД,2);
    цепьД[0]:=ВЗНАК(у.a);
    цепьД[1]:=0X;
    у.понД:=Данные.СоздатьПостЦепь(цепьД);
    у.вид:=у.понД.вид
  КОН
КОН ЗнакВЦепь;

(*----------------------------------------------------------------------------*)
ЗАДАЧА СравнитьЦепочки(уа+,уб+:Узел.нВид; ку:ЦЕЛ);
(* После: уа.роду=уКодУ, уб пустой *)
ПЕР
  ра,рб:ЦЕЛ;          (* регистры для считанных из цепочек знаков *)
  мПовтор,мВыход:ЦЕЛ; (* метки *)
УКАЗ
  ЗнакВЦепь(уа);
  ЗнакВЦепь(уб);
  ЗагрузитьАдр(уа);
  ЗагрузитьАдр(уб);
  мВыход:=Код.ПолучитьМетку();
  мПовтор:=Код.ПолучитьМетку();
  (* уа.роду = уРег, уб.роду = уРег *)
  Рег.Занять(ра);
  Рег.Занять(рб);
Код.ПоставитьМетку(мПовтор);
  Код.ПЗС1(Код.LDRBp,ра,уа.ро,1);
  Код.ПЗС1(Код.LDRBp,рб,уб.ро,1);
  Код.будетS:=ВКЛ;
  Код.ОД1(Код.CMP,0,ра,0);
  Код.ПереходПоКУ(мВыход,Код.EQ);    (* идём на выход, если ра = 0 *)
  Код.будетS:=ВКЛ;
  Код.ОД(Код.CMP,0,ра,рб,0,0);
  Код.ПереходПоКУ(мПовтор,Код.EQ);   (* идём на повтор, если ра = рб *)
Код.ПоставитьМетку(мВыход);
  Код.будетS:=ВКЛ;
  Код.ОД(Код.CMP,0,ра,рб,0,0);     (* пригодится если ра = 0 *)
  Рег.Освободить(ра);
  Рег.Освободить(рб);
  Освободить(уа);
  Освободить(уб);
  СоздатьКУ(уа,ку)
КОН СравнитьЦепочки;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ДелОст(уа+,уб+:Узел.нВид; делить:КЛЮЧ);
(* Цель:  вызов СРЕДА.Делить(уа,уб) и СРЕДА.Остаток(уа,уб)
 * После: уа - ответ (уа.роду = уРег) *)
ПЕР
  цр:ЦЕЛ;
  р0:ЦЕЛ; (* регистр для хранения текущего R0 *)
УКАЗ
  (* если R0 занят не нашими узлами *)
  ЕСЛИ (0 В Рег.Заняты()) И 
    НЕ ((уа.роду = уРег) И (уа.ро = 0) ИЛИ (уб.роду = уРег) И (уб.ро = 0)) ТО
    (* сохраним R0 *)
    Рег.Занять(р0);
    Код.ОД(Код.MOV,р0,0,0,0,0);
    Рег.Освободить(0)
  ИНАЧЕ
    (* R0 сохранять не нужно *)
    р0:=-1
  КОН;
  (* вызов СРЕДА.Делить(уа,уб) и СРЕДА.Остаток(уа,уб) *)
  ВСтек(уа);
  Освободить(уа);
  ВСтек(уб);  
  Освободить(уб);
  ЕСЛИ делить ТО
    Код.ВызовПоИмени("|.СРЕДА.Делить|")
  ИНАЧЕ
    Код.ВызовПоИмени("|.СРЕДА.Остаток|")
  КОН;
  (* ответ в узел уа *)
  уа.роду:=уРег;
  Рег.Нужен(0);
  Рег.Занять(уа.ро);
  (* восстанавливаем при необходимости старый R0 *)
  ЕСЛИ р0 # -1 ТО
    (* переносим уа из R0 *)
    Рег.Занять(цр);
    Код.ОД(Код.MOV,цр,0,0,0,0);
    Рег.Освободить(0);
    уа.ро:=цр;
    (* восстанавливаем R0 из р0 *)
    Код.ОД(Код.MOV,0,0,р0,0,0);
    Рег.Освободить(р0);
    (* займём хозяину R0 *)
    Рег.Нужен(0);
    Рег.Занять(р0)
  КОН
КОН ДелОст;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Действие-(действие:ЦЕЛ; уа+,уб+:Узел.нВид);
ПЕР
  родва,родвб:ЦЕЛ; 
  показательСтепени2:ЦЕЛ;  (* побочный ответ подЗадачи ПроверкаНаСтепень2х(N) *)
  а,б:ЦЕЛ;

(*----------------------------------------- подЗадача (проверка N на степень 2-х) ---*)
  ЗАДАЧА ПроверкаНаСтепень2х(N:ЦЕЛ):КЛЮЧ;
  (*
   * Цель:  пытается найти представление <N> в виде 2^v
   * До:           <N> - исследуемое число
   * После: <показательСтепени2> - найденное v, если это возможно
   * Ответ: ВКЛ, если N = 2^v
   *)
  УКАЗ
                  показательСтепени2:=0;
    ЕСЛИ N > 0 ТО
      ПОКА ЧЕТ(N) ВЫП
               N:=N ДЕЛИТЬ 2;
        УВЕЛИЧИТЬ(показательСтепени2)
      КОН;
      ЕСЛИ     N = 1 ТО
        ВОЗВРАТ ВКЛ
      КОН
    КОН;
    ВОЗВРАТ ОТКЛ
  КОН ПроверкаНаСтепень2х;

(*----------------------------------------- подЗадача ----*)
  ЗАДАЧА Цепочки():КЛЮЧ;
  (* возвращает ВКЛ, если <уа> и <уб> являются цепочками *)
  УКАЗ 
    ВОЗВРАТ
    (((родва = Данные.вЦепь) ИЛИ (родва = Данные.вЗнак) И (уа.роду = уПост)) И
     ((родвб = Данные.вЦепь) ИЛИ (родвб = Данные.вЗнак) И (уб.роду = уПост)))
  КОН Цепочки;

(*----------------------------------------- подЗадача ----*)
  ЗАДАЧА Родня(а0,б0:Данные.ДкВидуВид):КЛЮЧ;
  (*
   * Цель:  определить, являются ли наборы между собой родственниками
   * До:    а0.родв = вНабор, б0.родв = вНабор
   * Ответ: ВКЛ, если являются
   *)
  ПЕР
    а,б:Данные.ДкВидуВид;
  УКАЗ
    а:=а0;
    ПОКА а # ПУСТО ВЫП
      б:=б0;
      ПОКА б # ПУСТО ВЫП
        ЕСЛИ а = б ТО
          ВОЗВРАТ ВКЛ
        КОН;
        б:=б.овид
      КОН;
      а:=а.овид
    КОН;
    ВОЗВРАТ ОТКЛ
  КОН Родня;

УКАЗ
  родва:=уа.вид.родв;
  родвб:=уб.вид.родв;
                                            (* проверим на соответствие видов *)
  ЕСЛИ уа.вид # уб.вид ТО
    ВЫБРАТЬ родва ИЗ
    | Данные.вЦел16:
        ЕСЛИ родвб = Данные.вЦел16 ТО
        АЕСЛИ родвб = Данные.вЦел32 ТО
          ЕСЛИ уа.роду # уПост ТО
            ЗагрузитьВРег(уа)
          КОН
        ИНАЧЕ
          Ошибка.Отметить(Ошибка.НЕСОВМЕСТИМЫЕ_ВИДЫ)
        КОН
    | Данные.вЦел32:
        ЕСЛИ родвб = Данные.вЦел16 ТО 
          ЕСЛИ уб.роду # уПост ТО
            ЗагрузитьВРег(уб)
          КОН;
          родвб:=родва;
          уб.вид:=уа.вид
        АЕСЛИ родвб = Данные.вЦел32 ТО
        ИНАЧЕ
          Ошибка.Отметить(Ошибка.НЕСОВМЕСТИМЫЕ_ВИДЫ)
        КОН
    | Данные.вПусто:
        ЕСЛИ НЕ (родвб В {Данные.вДоступ,Данные.вЗадача}) ТО
          Ошибка.Отметить(Ошибка.НЕСОВМЕСТИМЫЕ_ВИДЫ)
        КОН
    | Данные.вДоступ:
        ЕСЛИ родвб = Данные.вДоступ ТО
          ЕСЛИ НЕ Родня(уа.вид.овид,уб.вид.овид) ТО
            Ошибка.Отметить(Ошибка.НЕСОВМЕСТИМЫЕ_ВИДЫ)
          КОН
        АЕСЛИ родвб # Данные.вПусто ТО
          Ошибка.Отметить(Ошибка.НЕСОВМЕСТИМЫЕ_ВИДЫ)
        КОН
    | Данные.вЗадача:
        ЕСЛИ родвб # Данные.вПусто ТО
          Ошибка.Отметить(Ошибка.НЕСОВМЕСТИМЫЕ_ВИДЫ)
        КОН
    |  Данные.вНеопр,Данные.вРяд,Данные.вЦепь:
    ИНАЧЕ
      Ошибка.Отметить(Ошибка.НЕСОВМЕСТИМЫЕ_ВИДЫ)
    КОН
  КОН;
  ВЫБРАТЬ действие ИЗ
    Слово.умножить:
      ЕСЛИ родва В множЦелых ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          а:=уа.a;
          б:=уб.a;
          ЕСЛИ (а = 0) ИЛИ (б = 0) ИЛИ
               (а > 0) И (б > 0) И ( б <= МАКС(ЦЕЛ) ДЕЛИТЬ   а) ИЛИ
               (а > 0) И (б < 0) И ( б >= МИН(ЦЕЛ)  ДЕЛИТЬ   а) ИЛИ
               (а < 0) И (б > 0) И ( а >= МИН(ЦЕЛ)  ДЕЛИТЬ   б) ИЛИ
               (а < 0) И (б < 0) И (-а <= МАКС(ЦЕЛ) ДЕЛИТЬ (-б)) ТО
            уа.a:=а*б;
            ОпредЦелВид(уа)
          ИНАЧЕ
            Ошибка.Отметить(Ошибка.БОЛЬШОЕ_ПРОИЗВЕДЕНИЕ)
          КОН
        ИНАЧЕ
          ЕСЛИ                     (уа.роду = уПост)
               И
                ПроверкаНаСтепень2х(уа.a)
          ТО
            ЗагрузитьВРег(уб);
            ЕСЛИ
                  показательСтепени2 # 0
            ТО
              Код.ОД(Код.MOV,уб.ро,0,уб.ро,Код.LSL,показательСтепени2+16)
            КОН;
            уа:=уб;
                уб.роду:=уПустой (* защита от освобождения регистра *)
          АЕСЛИ
                                   (уб.роду = уПост)
               И
                ПроверкаНаСтепень2х(уб.a)
          ТО
            ЗагрузитьВРег(уа);
            ЕСЛИ показательСтепени2 # 0 ТО
              Код.ОД(Код.MOV,уа.ро,0,уа.ро,Код.LSL,показательСтепени2+16)
            КОН
          ИНАЧЕ
            ЗагрузитьВРег(уа);
            ЗагрузитьВРег(уб);
            Код.Умн(Код.MUL,уа.ро,уб.ро,уа.ро,0)
          КОН
        КОН
      АЕСЛИ родва = Данные.вМнож ТО
        ОД(Код.AND,уа,уб)
      АЕСЛИ родва # Данные.вНеопр ТО
        Ошибка.Отметить(Ошибка.УМНОЖЕНИЕ_НЕПРИМЕНИМО)
      КОН
  | Слово.косая:
      ЕСЛИ родва = Данные.вМнож ТО
        ОД(Код.EOR,уа,уб)
      АЕСЛИ родва # Данные.вНеопр ТО
        Ошибка.Отметить(Ошибка.ДЕЛЕНИЕ_НЕПРИМЕНИМО)
      КОН
  | Слово.делить:
      ЕСЛИ
           родва В множЦелых
      ТО
        ЕСЛИ  (уб.роду = уПост)
             И
              (уб.a = 0)
        ТО
          Ошибка.Отметить(Ошибка.ДЕЛЕНИЕ_НА_НОЛЬ)
        КОН;
        ЕСЛИ
              (уа.роду = уПост)
             И
              (уб.роду = уПост)
        ТО
          уа.a:=уа.a ДЕЛИТЬ уб.a;
          ОпредЦелВид(уа)
        АЕСЛИ                    (уб.роду = уПост)
             И
              ПроверкаНаСтепень2х(уб.a)
        ТО
          ЗагрузитьВРег(уа);
          Код.ОД(Код.MOV,уа.ро,0,уа.ро,Код.ASR,показательСтепени2+16) (* MOV уа.ро,уа.ро ASR показательСтепени2 *)
        ИНАЧЕ
          ДелОст(уа,уб,ВКЛ)
        КОН
      АЕСЛИ родва # Данные.вНеопр ТО
        Ошибка.Отметить(Ошибка.ДЕЛИТЬ_НЕПРИМЕНИМО)
      КОН
  | Слово.остаток:
      ЕСЛИ родва В множЦелых ТО
        ЕСЛИ (уб.роду = уПост) И (уб.a = 0) ТО
          Ошибка.Отметить(Ошибка.ДЕЛЕНИЕ_НА_НОЛЬ)
        КОН;
        ЕСЛИ  (уа.роду = уПост) И (уб.роду = уПост)
        ТО
          уа.a:=уа.a ОСТАТОК уб.a;
          уа.вид:=уб.вид
        АЕСЛИ
              (уб.роду = уПост) И ПроверкаНаСтепень2х(уб.a)
        ТО
          уб.a:=Асм.ЗнаковыйСдвиг(-1,показательСтепени2);
          ЗагрузитьВРег(уа);
          Код.ОД1(Код.BIC,уа.ро,уа.ро,уб.a)
        ИНАЧЕ
          ДелОст(уа,уб,ОТКЛ)
        КОН
      АЕСЛИ родва # Данные.вНеопр ТО
        Ошибка.Отметить(Ошибка.ОСТАТОК_НЕПРИМЕНИМО)
      КОН
  | Слово.и:
      ВыставитьКУ(уб);
      ЕСЛИ уа.ро # Код.NV ТО
        уа.ро:=уб.ро
      КОН;
      уа.a:=уб.a
  | Слово.или:
      ВыставитьКУ(уб);
      ЕСЛИ уа.ро # Код.AL ТО
        уа.ро:=уб.ро
      КОН;
      уа.b:=уб.b
  | Слово.плюс:
      ЕСЛИ родва В множЦелых ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          ЕСЛИ (уб.a >= 0) И (уа.a <= МАКС(ЦЕЛ)-уб.a) ИЛИ
               (уб.a <  0) И (уа.a >= МИН(ЦЕЛ) -уб.a) ТО
            УВЕЛИЧИТЬ(уа.a,уб.a);
            ОпредЦелВид(уа)
          ИНАЧЕ
            Ошибка.Отметить(Ошибка.БОЛЬШАЯ_СУММА)
          КОН
        ИНАЧЕ
          ЗагрузитьВРег(уа);
          ОД(Код.ADD,уа,уб)
        КОН
      АЕСЛИ родва = Данные.вМнож ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          уа.a:=ОБХОД.Значение(ЦЕЛ,ОБХОД.Значение(МНОЖ,уа.a)+ОБХОД.Значение(МНОЖ,уб.a))
        ИНАЧЕ
          ОД(Код.ORR,уа,уб)
        КОН
      АЕСЛИ родва # Данные.вНеопр ТО
        Ошибка.Отметить(Ошибка.ПЛЮС_НЕПРИМЕНИМ)
      КОН
  | Слово.минус:
      ЕСЛИ родва В множЦелых ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          ЕСЛИ (уб.a >= 0) И (уа.a >= МИН(ЦЕЛ) +уб.a) ИЛИ
               (уб.a <  0) И (уа.a <= МАКС(ЦЕЛ)+уб.a) ТО
            УМЕНЬШИТЬ(уа.a,уб.a);
            ОпредЦелВид(уа)
          ИНАЧЕ
            Ошибка.Отметить(Ошибка.БОЛЬШАЯ_РАЗНОСТЬ)
          КОН
        ИНАЧЕ
          ОД(Код.SUB,уа,уб)
        КОН
      АЕСЛИ родва = Данные.вМнож ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          уа.a:=ОБХОД.Значение(ЦЕЛ,ОБХОД.Значение(МНОЖ,уа.a)-ОБХОД.Значение(МНОЖ,уб.a))
        ИНАЧЕ
          ОД(Код.BIC,уа,уб)
        КОН
      АЕСЛИ родва # Данные.вНеопр ТО
        Ошибка.Отметить(Ошибка.МИНУС_НЕПРИМЕНИМ)
      КОН
  | Слово.равно:
      ЕСЛИ родва В {Данные.вНеопр,Данные.вЯчейка,Данные.вКлюч,Данные.вЗнак,Данные.вЦел16,Данные.вЦел32,Данные.вМнож,Данные.вПусто,Данные.вДоступ,Данные.вЗадача} ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          ЕСЛИ уа.a = уб.a ТО
            СоздатьКУ(уа,Код.AL)
          ИНАЧЕ
            СоздатьКУ(уа,Код.NV)
          КОН
        ИНАЧЕ
          Сравнить(уа,уб,Код.EQ)
        КОН
      АЕСЛИ Цепочки() ТО
        СравнитьЦепочки(уа,уб,Код.EQ)
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.СРАВНЕНИЕ_НЕПРИМЕНИМО)
      КОН
  | Слово.неравно:
      ЕСЛИ родва В {Данные.вНеопр,Данные.вЯчейка,Данные.вКлюч,Данные.вЗнак,Данные.вЦел16,Данные.вЦел32,Данные.вМнож,Данные.вПусто,Данные.вДоступ,Данные.вЗадача} ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          ЕСЛИ уа.a # уб.a ТО
            СоздатьКУ(уа,Код.AL)
          ИНАЧЕ
            СоздатьКУ(уа,Код.NV)
          КОН
        ИНАЧЕ
          Сравнить(уа,уб,Код.NE)
        КОН
      АЕСЛИ Цепочки() ТО
        СравнитьЦепочки(уа,уб,Код.NE)
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.СРАВНЕНИЕ_НЕПРИМЕНИМО)
      КОН
  | Слово.меньше:
      ЕСЛИ родва В множЦелых ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          ЕСЛИ уа.a < уб.a ТО
            СоздатьКУ(уа,Код.AL)
          ИНАЧЕ
            СоздатьКУ(уа,Код.NV)
          КОН
        ИНАЧЕ
          Сравнить(уа,уб,Код.LT)
        КОН
      АЕСЛИ родва = Данные.вЗнак ТО
        Сравнить(уа,уб,Код.CC)
      АЕСЛИ Цепочки() ТО
        СравнитьЦепочки(уа,уб,Код.CC)
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.СРАВНЕНИЕ_НЕПРИМЕНИМО)
      КОН
  | Слово.мравно:
      ЕСЛИ родва В множЦелых ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          ЕСЛИ уа.a <= уб.a ТО
            СоздатьКУ(уа,Код.AL)
          ИНАЧЕ
            СоздатьКУ(уа,Код.NV)
          КОН
        ИНАЧЕ
          Сравнить(уа,уб,Код.LE)
        КОН
      АЕСЛИ родва = Данные.вЗнак ТО
        Сравнить(уа,уб,Код.LS)
      АЕСЛИ Цепочки() ТО
        СравнитьЦепочки(уа,уб,Код.LS)
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.СРАВНЕНИЕ_НЕПРИМЕНИМО)
      КОН
  | Слово.больше:
      ЕСЛИ родва В множЦелых ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          ЕСЛИ уа.a > уб.a ТО
            СоздатьКУ(уа,Код.AL)
          ИНАЧЕ
            СоздатьКУ(уа,Код.NV)
          КОН
        ИНАЧЕ
          Сравнить(уа,уб,Код.GT)
        КОН
      АЕСЛИ родва = Данные.вЗнак ТО
        Сравнить(уа,уб,Код.HI)
      АЕСЛИ Цепочки() ТО
        СравнитьЦепочки(уа,уб,Код.HI)
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.СРАВНЕНИЕ_НЕПРИМЕНИМО)
      КОН
  | Слово.бравно:
      ЕСЛИ родва В множЦелых ТО
        ЕСЛИ (уа.роду = уПост) И (уб.роду = уПост) ТО
          ЕСЛИ уа.a >= уб.a ТО
            СоздатьКУ(уа,Код.AL)
          ИНАЧЕ
            СоздатьКУ(уа,Код.NV)
          КОН
        ИНАЧЕ
          Сравнить(уа,уб,Код.GE)
        КОН
      АЕСЛИ родва = Данные.вЗнак ТО
        Сравнить(уа,уб,Код.CS)
      АЕСЛИ Цепочки() ТО
        СравнитьЦепочки(уа,уб,Код.CS)
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.СРАВНЕНИЕ_НЕПРИМЕНИМО)
      КОН
  КОН;
  Освободить(уб)
КОН Действие;


(********* Встроенные задачи **************************************************)

(*----------------------------------------------------------------------------*)
ЗАДАЧА Образ(ир,пр,рр:ЦЕЛ);
(* Цель: переписывает
 * До:   ир - регистр с адресом источника данных 
 *       пр - регистр с адресом приёмника данных
 *       рр - регистр с заданным размером *)
ПЕР
  мВыход:ЦЕЛ;
УКАЗ
  мВыход:=Код.ПолучитьМетку();
  Код.будетS:=ВКЛ;
  Код.ОД1(Код.CMP,0,рр,0);
  Код.ПереходПоКУ(мВыход,Код.LE); (* на выход, если рр <= 0 *)
  Код.ПереписатьПамять(ир,пр,рр);
Код.ПоставитьМетку(мВыход)
КОН Образ;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Списать(уи+,уп+:Узел.нВид);
(* Цель: переписывает цепочку, в конце приёмника всегда ставит 0
 * До:    уи  - узел источника данных 
 *        уп  - узел приёмника данных
 * После: СПИСАТЬ(уи,уп) *)
ПЕР
  ури:Узел.нВид; (* узел размера источника *)
  урп:Узел.нВид; (* узел размера приёмника *)
  ир:ЦЕЛ;  (* регистр с адресом источника данных  *)
  пр:ЦЕЛ;  (* регистр с адресом приёмника данных  *)
  рир:ЦЕЛ; (* регистр с размером источника данных *)
  рпр:ЦЕЛ; (* регистр с размером приёмника данных *)
  зр:ЦЕЛ;  (* регистр с прочитанным знаком *)
  мПовтор,мВыход,мУменьшение:ЦЕЛ; (* метки *)
УКАЗ
  (* загрузим размеры в новые регистры *)
  ури:=уи;
  урп:=уп;
  РазмерЦепи(ури);
  РазмерЦепи(урп);
  ЗагрузитьВРег(ури);
  ЗагрузитьВРег(урп);
  рир:=ури.ро;
  рпр:=урп.ро;
  (* загрузим адреса в регистры *)
  ЗагрузитьАдр(уи);
  ЗагрузитьАдр(уп);
  ир:=уи.ро;
  пр:=уп.ро;
  (* получим метки *)
  мПовтор:=Код.ПолучитьМетку();
  мУменьшение:=Код.ПолучитьМетку();
  мВыход:=Код.ПолучитьМетку();
  (* рир:=МИН(рир,рпр) *)
  Код.будетS:=ВКЛ;
  Код.ОД(Код.CMP,0,рир,рпр,0,0);
  Код.будетКУ:=Код.GT;
  Код.ОД(Код.MOV,рир,0,рпр,0,0);
  зр:=рпр;
  (* на выход, если рир <= 0 *)
  Код.будетS:=ВКЛ;
  Код.ОД1(Код.CMP,0,рир,0);
  Код.ПереходПоКУ(мВыход,Код.LE);
  (* на уменьшение рир *)
  Код.ПереходНа(мУменьшение);
Код.ПоставитьМетку(мПовтор);
  Код.ПЗС1(Код.LDRBp,зр,ир,1);
  Код.ПЗС1(Код.STRBp,зр,пр,1);
Код.ПоставитьМетку(мУменьшение);
  Код.будетS:=ВКЛ;
  Код.ОД1(Код.SUB,рир,рир,1);
  Код.ПереходПоКУ(мПовтор,Код.NE); (* идём на мПовтор, если рир # 0 *)
  Код.ПЗС1(Код.STRB,рир,пр,0);     (* записываем в конце 0 (рир=0)  *)
Код.ПоставитьМетку(мВыход);
  Освободить(ури);
  Освободить(урп)               
КОН Списать;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Длина(уи+:Узел.нВид);
(* Цель: переписывает цепочку, в конце приёмника всегда ставит 0
 * До:    уи - узел источника данных 
 * После: уи - ДЛИНА(уи) *)
ПЕР
  ури:Узел.нВид; (* узел размера источника *)
  ир:ЦЕЛ;  (* регистр с адресом источника данных  *)
  рир:ЦЕЛ; (* регистр с размером источника данных *)
  зр:ЦЕЛ;  (* регистр с прочитанным знаком *)
  рхр:ЦЕЛ; (* регистр с размером хвоста *)
  мПовтор,мВыход:ЦЕЛ; (* метки *)
УКАЗ
  (* загрузим размеры в новые регистры *)
  ури:=уи;
  РазмерЦепи(ури);
  ЗагрузитьВРег(ури);
  рир:=ури.ро;
  (* загрузим адреса в регистры *)
  ЗагрузитьАдр(уи);
  ир:=уи.ро;
  (* получим метки *)
  мПовтор:=Код.ПолучитьМетку();
  мВыход:=Код.ПолучитьМетку();
  (* получим регистры *)
  Рег.Занять(зр); 
  Рег.Занять(рхр); 
  (* подготовимся *)
  Код.ОД(Код.MOV,рхр,0,рир,0,0);
Код.ПоставитьМетку(мПовтор);
  Код.ПЗС1(Код.LDRBp,зр,ир,1);
  Код.будетS:=ВКЛ;
  Код.ОД1(Код.CMP,0,зр,0);
  Код.ПереходПоКУ(мВыход,Код.EQ);  (* идём на мВыход, если зр = 0 *)
  Код.будетS:=ВКЛ;
  Код.ОД1(Код.SUB,рхр,рхр,1);
  Код.ПереходПоКУ(мПовтор,Код.NE); (* идём на мПовтор, если рхр # 0 *)
Код.ПоставитьМетку(мВыход);
  Код.ОД(Код.SUB,ир,рир,рхр,0,0);
  Освободить(ури);
  Рег.Освободить(зр); 
  Рег.Освободить(рхр); 
  уи.вид:=Данные.цел32вид
КОН Длина;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВстрПриёмник0-(задача:ЦЕЛ; у0+:Узел.нВид);
(* ошибки надо отметить сразу *)
ПЕР
  родв:ЦЕЛ; 
УКАЗ
  родв:=у0.вид.родв;
  ВЫБРАТЬ задача ИЗ
  | Данные.зСоздать:
      ЕСЛИ (родв # Данные.вДоступ) ИЛИ
        НЕ (у0.вид.овид.родв В {Данные.вНабор,Данные.вРяд}) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      ЗагрузитьАдр(у0);
      ВСтек(у0);         (* адрес *)
      Освободить(у0);
      СоздатьЦелПост(у0,у0.вид.овид.размер);
      ВСтек(у0);         (* размер *)
      Освободить(у0);
      Код.ВызовПоИмени("|.СРЕДА.Создать|");
      у0.вид:=Данные.нетвид
  | Данные.зОбнулить:
      ЕСЛИ НЕ (родв В {Данные.вНабор,Данные.вРяд}) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      (* работа ! ! *)
  | Данные.зМодуль:
      ЕСЛИ НЕ (родв В множЦелых) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      ЕСЛИ у0.роду = уПост ТО
        у0.a:=МОДУЛЬ(у0.a)
      ИНАЧЕ
        ЗагрузитьВРег(у0);
        Код.будетS:=ВКЛ;
        Код.ОД1(Код.CMP,0,у0.ро,0);
        Код.будетКУ:=Код.LT;
        Код.ОД1(Код.RSB,у0.ро,у0.ро,0)
      КОН
  | Данные.зВЦел:
      ЕСЛИ НЕ (родв В {Данные.вЗнак,Данные.вЯчейка}) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      ЕСЛИ у0.роду # уПост ТО
        ЗагрузитьВРег(у0)
      КОН;
      у0.вид:=Данные.цел32вид
  | Данные.зВЗнак:
      ЕСЛИ НЕ (родв В {Данные.вЯчейка,Данные.вЦел16,Данные.вЦел32}) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      ЕСЛИ у0.роду # уПост ТО
        ЗагрузитьВРег(у0)
      КОН;
      у0.вид:=Данные.знаквид
  | Данные.зЧет:
      ЕСЛИ НЕ (родв В множЦелых) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      ЗагрузитьВРег(у0);
      Код.ОД1(Код.TST,0,у0.ро,1);
      Освободить(у0);
      СоздатьКУ(у0,Код.EQ)
  | Данные.зАдрес:
      ЗагрузитьАдр(у0);
      у0.вид:=Данные.цел32вид
  | Данные.зМин:
      ЕСЛИ у0.роду # уВид ТО
        Ошибка.Отметить(Ошибка.ЭТО_НЕ_ВИД)
      КОН;
      у0.роду:=уПост;
      ВЫБРАТЬ родв ИЗ
        Данные.вКлюч,Данные.вЗнак:
          у0.a:=0
      | Данные.вЦел16:
          у0.a:=МИН(ОБХОД.Цел16)
      | Данные.вЦел32:
          у0.a:=МИН(ЦЕЛ)
      | Данные.вМнож:
          у0.a:=МИН(МНОЖ);
          у0.вид:=Данные.цел32вид
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН
  | Данные.зМакс:
      ЕСЛИ у0.роду # уВид ТО
        Ошибка.Отметить(Ошибка.ЭТО_НЕ_ВИД)
      КОН;
      у0.роду:=уПост;
      ВЫБРАТЬ родв ИЗ
        Данные.вКлюч:
          у0.a:=1
      | Данные.вЗнак:
          у0.a:=0FFH
      | Данные.вЦел16:
          у0.a:=МАКС(ОБХОД.Цел16)
      | Данные.вЦел32:
          у0.a:=МАКС(ЦЕЛ)
      | Данные.вМнож:
          у0.a:=МАКС(МНОЖ);
          у0.вид:=Данные.цел32вид
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН
  | Данные.зУзк:
      ЕСЛИ родв # Данные.вЦел32 ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      ЕСЛИ у0.роду = уПост ТО
        ОпредЦелВид(у0);
        ЕСЛИ у0.вид.родв # Данные.вЦел16 ТО
          Ошибка.Отметить(Ошибка.БОЛЬШОЕ_ЧИСЛО)
        КОН
      ИНАЧЕ
        ЗагрузитьВРег(у0);
        у0.вид:=Данные.цел16вид; 
        (* MOVы, которые сохраняют правильным знак числа *)
        Код.ОД(Код.MOV,у0.ро,0,у0.ро,Код.LSL,16+16); (* MOV у0.ро,у0.ро LSL 16 *)
        Код.ОД(Код.MOV,у0.ро,0,у0.ро,Код.ASR,16+16)  (* MOV у0.ро,у0.ро ASR 16 *)
      КОН 
  | Данные.зДлина:
      ЗнакВЦепь(у0);
      ЕСЛИ у0.вид.родв # Данные.вЦепь ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      ЕСЛИ у0.роду = уПост ТО
        СоздатьЦелПост(у0,ДЛИНА(у0.понД.цепьД^))
      ИНАЧЕ
        Длина(у0)
      КОН
  | Данные.зЗадано:
      ЗнакВЦепь(у0);
      ЕСЛИ (у0.вид.родв # Данные.вЦепь) ИЛИ (у0.роду # уПост) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      у0.вид:=Данные.ключвид;
      ЕСЛИ Настрой.ЕстьКлюч(у0.понД.цепьД^) ТО
        у0.a:=1
      ИНАЧЕ
        у0.a:=0
      КОН
(* остались *)  
  | Данные.зИзПамяти,Данные.зВПамять,Данные.зОбраз:
      ЕСЛИ НЕ (родв В множЦелых) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН
  | Данные.зЗначение:
      ЕСЛИ у0.роду # уВид ТО
        Ошибка.Отметить(Ошибка.ЭТО_НЕ_ВИД)
      КОН
  | Данные.зСписать:
      ЗнакВЦепь(у0);
      ЕСЛИ у0.вид.родв # Данные.вЦепь ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН
  | Данные.зПоставить,Данные.зСместить:
      ЕСЛИ родв # Данные.вБегунок ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН
  | Данные.зУвеличить,Данные.зУменьшить:
      ЕСЛИ у0.роду >= уПост ТО
        Ошибка.Отметить(Ошибка.ЭТО_НЕ_ПЕРЕМЕННАЯ)
      АЕСЛИ НЕ (родв В множЦелых) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН
  | Данные.зРазмер:
      ЕСЛИ НЕ (родв В {Данные.вРяд,Данные.вЦепь}) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН
  ИНАЧЕ
    Ошибка.Отметить(Ошибка.МНОГО_ИСТОЧНИКОВ)
  КОН
КОН ВстрПриёмник0;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВстрПриёмник1-(задача:ЦЕЛ; у0+,у1+:Узел.нВид);
ПЕР
  родв:ЦЕЛ; 
УКАЗ
  родв:=у1.вид.родв;
  ВЫБРАТЬ задача ИЗ
  | Данные.зИзПамяти:
      ЗагрузитьВРег(у0);
      у0.роду:=уАдрС;
      у0.a:=0;
      ЕСЛИ у1.роду >= уПост ТО
        Ошибка.Отметить(Ошибка.ЭТО_НЕ_ПЕРЕМЕННАЯ)
      АЕСЛИ у1.вид.родв В {Данные.вНеопр..Данные.вЦел32,Данные.вМнож,Данные.вДоступ,Данные.вЗадача} ТО
        у0.вид:=у1.вид;
        Переписать(у0,у1)
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН; 
      у0.вид:=Данные.нетвид
  | Данные.зВПамять:
      ЗагрузитьВРег(у0);
      у0.роду:=уАдрС;
      у0.a:=0;
      ЕСЛИ у1.вид.родв В {Данные.вНеопр..Данные.вЦел32,Данные.вМнож,Данные.вДоступ,Данные.вЗадача} ТО
        у0.вид:=у1.вид;
        Переписать(у1,у0)
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      у0.вид:=Данные.нетвид
  | Данные.зЗначение:
      ЕСЛИ (у0.вид.размер > у1.вид.размер) И (у1.роду В {уАдрС,уАдрСАдрС,уАдрЗС}) ТО
        (* возможны трудности с выравниванием *)
        ЕСЛИ ((у1.роду В {уАдрС,уАдрЗС}) И (у1.a ОСТАТОК у0.вид.размер # 0)) ИЛИ
          ((у1.роду = уАдрСАдрС) И (у1.b ОСТАТОК у0.вид.размер # 0)) ТО
          Ошибка.Отметить(Ошибка.НЕТ_ВЫРАВНИВАНИЯ)
        КОН
      КОН;
      у1.вид:=у0.вид;
      у0:=у1
  | Данные.зСписать:
      ЕСЛИ родв # Данные.вЦепь ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН;
      Списать(у0,у1);
      у0.вид:=Данные.нетвид
  | Данные.зСместить:
      ЕСЛИ (у1.роду # уПост) ИЛИ НЕ (родв В множЦелых) ТО
        Ошибка.Отметить(Ошибка.ИСТОЧНИК_НЕ_ЦЕЛАЯ_ПОСТ)
      КОН;
      (* работа ! ! *)
(* остались *)
  | Данные.зПоставить:
      ЕСЛИ родв # Данные.вРяд ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН
  | Данные.зОбраз:
      ЕСЛИ НЕ (родв В множЦелых) ТО
        Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
      КОН
  | Данные.зУвеличить,Данные.зУменьшить:
      ЕСЛИ у1.вид # у0.вид ТО
        ЕСЛИ родв В множЦелых ТО
          у1.вид:=у0.вид
        ИНАЧЕ
          Ошибка.Отметить(Ошибка.ИСТОЧНИК_НЕ_ЦЕЛАЯ_ПОСТ)
        КОН
      КОН
  | Данные.зРазмер:
      ЕСЛИ (у1.роду # уПост) ИЛИ НЕ (родв В множЦелых) ТО
        Ошибка.Отметить(Ошибка.ИСТОЧНИК_НЕ_ЦЕЛАЯ_ПОСТ)
      КОН
  ИНАЧЕ
    Ошибка.Отметить(Ошибка.МНОГО_ИСТОЧНИКОВ)
  КОН
КОН ВстрПриёмник1;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВстрПриёмник2-(задача:ЦЕЛ; у0+,у1+,у2+:Узел.нВид);
УКАЗ
  ЕСЛИ задача = Данные.зОбраз ТО
    ЕСЛИ НЕ (у2.вид.родв В множЦелых) ТО
      Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
    КОН; 
    ЗагрузитьВРег(у0);
    ЗагрузитьВРег(у1);
    ЗагрузитьВРег(у2);
    Образ(у0.ро,у1.ро,у2.ро);
    у0.вид:=Данные.нетвид
  АЕСЛИ задача = Данные.зПоставить ТО
    ЕСЛИ НЕ (у2.вид.родв В множЦелых) ТО
      Ошибка.Отметить(Ошибка.НЕ_СОВМЕСТИМО_С_ЗАДАЧЕЙ)
    КОН; 
(*  работа ! !
    ЗагрузитьВРег(у0);
    ЗагрузитьВРег(у1);
    ЗагрузитьВРег(у2);
    Образ(у0.ро,у1.ро,у2.ро);
*)
    у0.вид:=Данные.нетвид
  ИНАЧЕ
    Ошибка.Отметить(Ошибка.МНОГО_ИСТОЧНИКОВ)
  КОН
КОН ВстрПриёмник2;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Увеличить-(уа+,уб+:Узел.нВид);
(* Цель:  уа:=уа+уб *)
УКАЗ
  ОДсОбрЗап(Код.ADD,уа,уб)
КОН Увеличить;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Уменьшить-(уа+,уб+:Узел.нВид);
(* Цель:  уа:=уа-уб *)
УКАЗ
  ОДсОбрЗап(Код.SUB,уа,уб)
КОН Уменьшить;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВстрПриёмникN-(задача,приёмников:ЦЕЛ; у0+,у1+,у2+:Узел.нВид);
ПЕР
  размерность:ЦЕЛ;
  вид:Данные.ДкВидуВид; 
УКАЗ
  ВЫБРАТЬ задача ИЗ
  | Данные.зУвеличить,Данные.зУменьшить:
      ЕСЛИ приёмников = 1 ТО
        СоздатьЦелПост(у1,1)
      КОН;
      ЕСЛИ задача = Данные.зУвеличить ТО
        Увеличить(у0,у1)
      ИНАЧЕ
        Уменьшить(у0,у1)
      КОН;
      у0.вид:=Данные.нетвид
  | Данные.зРазмер:
      ЕСЛИ приёмников = 1 ТО
        ЕСЛИ у0.вид.родв = Данные.вЦепь ТО
          РазмерЦепи(у0)
        ИНАЧЕ
          СоздатьЦелПост(у0,у0.вид.размер ДЕЛИТЬ у0.вид.овид.размер)
        КОН
      ИНАЧЕ
        вид:=у0.вид;
        размерность:=у1.a;
        ЕСЛИ вид.родв = Данные.вЦепь ТО
          ЕСЛИ размерность # 0 ТО
            Ошибка.Отметить(Ошибка.НЕВЕРНАЯ_РАЗМЕРНОСТЬ)
          КОН;
          РазмерЦепи(у0)
        ИНАЧЕ
          ПОКА (размерность > 0) И (вид.родв = Данные.вРяд) ВЫП
            вид:=вид.овид;
            УМЕНЬШИТЬ(размерность)
          КОН;
          ЕСЛИ (размерность # 0) ИЛИ (вид.родв # Данные.вРяд) ТО
            Ошибка.Отметить(Ошибка.НЕВЕРНАЯ_РАЗМЕРНОСТЬ)
          КОН;
          СоздатьЦелПост(у0,вид.размер ДЕЛИТЬ вид.овид.размер)
        КОН
      КОН
  ИНАЧЕ
  КОН
КОН ВстрПриёмникN;

КОН Узел.
