(*~\Глагол\приложкемяLink\МПГ2009 (компилируется, но НЕ раб.)\~~~~~~~~~~~~~~~~*)
(**)                                                    ОТДЕЛ ВКод;
(****************************************************************************** 
 * НАЗНАЧЕНИЕ: преобразование в код сложных выражений
 ******************************************************************************)

ИСПОЛЬЗУЕТ 
  Ядро,
  Данные,
  Настрой,
  Узел,           (* недоделанный отдел *)
  Код,
  Рег,
  Ошибка;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       РасширенОт-(рв,ов:Данные.ДкВиду);
(*
 * Цель:  проверить является ли набор <рв> расширением <ов>
 * После: если это не так, то ошибка
 *)
УКАЗ
  ПОКА рв # ов ВЫП
    ЕСЛИ рв = Данные.неопрвид ТО
      Ошибка.Отметить(Ошибка.ЭТО_НЕ_РАСШИРЕНИЕ)
    КОН;
    рв:=рв.овид
  КОН
КОН РасширенОт;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       УровеньРасширения-(вид:Данные.ДкВиду):ЦЕЛ;
(*
 * Ответ: уровень расширения вида набор (от 0)
 *)
ПЕР
  уровень:ЦЕЛ;
УКАЗ
  уровень:=0;
  ПОКА вид # Данные.неопрвид ВЫП
    УВЕЛИЧИТЬ(уровень);
    вид:=вид.овид
  КОН;
  ВОЗВРАТ уровень-1
КОН УровеньРасширения;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ВозможнаОхрана-(понп,понв:Данные.ДкПонятию);
(*
 * Цель:  проверить возможность охраны вида
 * До:
 *        <понп>      - переменная
 *        <понв>      - вид охраны
 *)

 (*................................................подЗАДАЧА...*)
  ЗАДАЧА ОхранаНабора(видп,
                      видв   :Данные.ДкВиду;
                      одоступ:КЛЮЧ);
  (* До:
   *        <видп>    - объявленный вид переменной (родв = вНабор)
   *        <видв>    - вид охраны (родв = вНабор)
   *        <одоступ> - доступ осуществляется по ОБХОД.Доступ *)
  ПЕР 
    вид:Данные.ДкВиду;
  УКАЗ
    (* проверка на сужение вида *)
    вид:=видп;
    ПОКА вид # Данные.неопрвид ВЫП
      ЕСЛИ вид = видв ТО
        ВОЗВРАТ
      КОН;
      вид:=вид.овид
    КОН;
    (* проверка на расширение вида *)
    ЕСЛИ НЕ одоступ ТО 
      РасширенОт(видв,видп)
    КОН
  КОН ОхранаНабора;

УКАЗ
  ЕСЛИ понв.родп # Данные.пВид ТО
    Ошибка.Отметить(Ошибка.ЭТО_НЕ_ВИД)
  АЕСЛИ понп.вид.родв = Данные.вДоступ ТО
    ЕСЛИ понв.вид.родв = Данные.вДоступ ТО
      ОхранаНабора(понп.вид.овид,понв.вид.овид,понп.вид = Данные.одоствид)
    ИНАЧЕ
      Ошибка.Отметить(Ошибка.ОХРАНА_НЕ_У_ДОСТУПА)
    КОН
  АЕСЛИ (понп.вид.родв = Данные.вНабор) И (понп.родп = Данные.пСсылка) 
      И (понв.вид.родв = Данные.вНабор) ТО (* приёмник ссылки на набор *)
    ОхранаНабора(понп.вид,понв.вид,ОТКЛ)
  ИНАЧЕ
    Ошибка.Отметить(Ошибка.ОХРАНА_НЕВОЗМОЖНА)
  КОН
КОН ВозможнаОхрана;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ОхранаВида-(   у+:Узел.нВид;
                   понв :Данные.ДкПонятию;
                нуженКУ :КЛЮЧ);
(*
 * До:
 *        <у>    - переменная
 *        <понв> - вид охраны
 * После: 
 *        <у> - КУ, если <нуженКУ>
 * Прим:  первоначальный <у> сохраняется
 *)

 (*................................................подЗАДАЧА...*)
  ЗАДАЧА ОхранаНабора(видп,
                      видв:Данные.ДкВиду;
                    доступ:КЛЮЧ);
  (* До:
   *        <видп>    - объявленный вид переменной (родв = вНабор)
   *        <видв>    - вид охраны (родв = вНабор)
   *        <доступ>  - охрана была по доступу *)
  ПЕР 
    вид:Данные.ДкВиду;
    уовп,уовв:Узел.нВид; (* описатель вида для вида переменной и вида охраны *)
  УКАЗ
    (* проверка на сужение вида *)
    вид:=видп;
    ПОКА вид # Данные.неопрвид ВЫП
      ЕСЛИ вид = видв ТО
        ЕСЛИ нуженКУ ТО
          Узел.СоздатьКУ(у,Код.AL)
        КОН;
        ВОЗВРАТ
      КОН;
      вид:=вид.овид
    КОН;
    (* ОВ для <у> *)
    ЕСЛИ доступ ТО
      уовп.роду:=Узел.уАдрС;
      уовп.ро:=Узел.ПереписатьВРег(у);
      уовп.a:=-4    (* ОВ до размещённого набора *)
    ИНАЧЕ (* приёмник переменной набора *)
      ЕСЛИ Данные.быстрая ТО
        уовп.роду:=Узел.уРпер;
        уовп.ро:=у.ро+1
      ИНАЧЕ
        ПРОВЕРИТЬ(у.ро = Рег.FP);
        уовп.роду:=Узел.уАдрС;
        уовп.ро:=у.ро;
        уовп.a:=у.a+4 (* ОВ после адреса набора *)
      КОН
    КОН;
    уовп.вид:=Данные.цел32вид;
    уовп.пон:=у.пон;
    Узел.ПеренестиВРег(уовп);
    уовп.роду:=Узел.уАдрС;
    уовп.a:=УровеньРасширения(видв)*4;
    Узел.ПеренестиВРег(уовп);
    (* ОВ для <видв> *)
    уовв.роду:=Узел.уРон;
    уовв.вид:=Данные.цел32вид;
    Рег.ЗанятьРОН(уовв.ро);
    Код.ЗагрузитьОВ(уовв.ро,видв);

    Код.будетS:=ВКЛ;
    Код.ОД(Код.CMP,0,уовп.ро,уовв.ро,0,0);
    Узел.Освободить(уовп);
    Узел.Освободить(уовв);
    ЕСЛИ нуженКУ ТО
      Узел.СоздатьКУ(у,Код.EQ)
    ИНАЧЕ
      Код.Ловушка(Код.NE,Ядро.лОхрана)
    КОН
  КОН ОхранаНабора;

УКАЗ
  ВозможнаОхрана(у.пон,понв);
  ЕСЛИ у.вид.родв = Данные.вДоступ ТО
    ОхранаНабора(у.вид.овид,понв.вид.овид,ВКЛ)
  ИНАЧЕ
    ОхранаНабора(у.вид,понв.вид,ОТКЛ)
  КОН
КОН ОхранаВида;

(******************************************************************************)
ЗАДАЧА ДляВида-(у+:Узел.нВид; мТабл:ЦЕЛ);
(* Цель: по таблице <мТабл> выбор ветки выполнения в соответствии с 
 *       размещённым видом переменной из <у> *)
ПЕР
  рп:ЦЕЛ; (* регистр для ОВ переменной на УРВ *)
  рв:ЦЕЛ; (* регистр для ОВ табличного вида охраны *)
  рт:ЦЕЛ; (* регистр для указателя таблицы *)
  мПовтор:ЦЕЛ;
УКАЗ
(*LDR   ро,ОВп
  LDR   рт,мТабл
мПовтор
  LDR   рв,[рт]
  LDR   рп,[ро+(рв LSL 2)]
  LDR   рв,[рт,#4]!
  CMPS  рв,рп
  LDREQ PC,[рт,#4]!
  ADD   рт,рт,#8
  B     мПовтор
мТабл
  DCD УРВ1
  DCD ОВ1
  DCD м1
  DCD УРВ2
  DCD ОВ2
  DCD м2
  ...
  DCD 0
  DCD ОВп
  DCD мИначе *)  

  (* Заносим ОВп в <у> *)
  ЕСЛИ у.вид.родв = Данные.вДоступ ТО
    Узел.ПеренестиВРег(у);
    у.роду:=Узел.уАдрС;
    у.a:=-4          (* ОВ до размещённого набора *)
  ИНАЧЕ (* приёмник переменной набора *)
    ЕСЛИ Данные.быстрая ТО
      у.роду:=Узел.уРпер;
      УВЕЛИЧИТЬ(у.ро)
    ИНАЧЕ
      у.роду:=Узел.уАдрС;
      УВЕЛИЧИТЬ(у.a,4) (* ОВ после адреса набора *)
    КОН
  КОН;
  у.вид:=Данные.цел32вид;
  Узел.ПеренестиВРег(у);

  Рег.ЗанятьРОН(рп);
  Рег.ЗанятьРОН(рт);
  Рег.ЗанятьРОН(рв);
  Код.ЗагрузитьМетку(рт,мТабл);
  мПовтор:=Код.ПолучитьМетку();
  Код.ПоставитьМетку(мПовтор);
  Код.ПЗС1(Код.LDR,рв,рт,0);
  Код.ПЗС(Код.LDR,рп,у.ро,рв,2);
  Код.будетВ:=ВКЛ;
  Код.ПЗС1(Код.LDR,рв,рт,4);
  Код.будетS:=ВКЛ;
  Код.ОД(Код.CMP,0,рв,рп,0,0);
  Код.будетКУ:=Код.EQ;
  Код.будетВ:=ВКЛ;
  Код.ПЗС1(Код.LDR,Рег.PC,рт,4);
  Код.ОД1(Код.ADD,рт,рт,8);
  Код.ПереходНа(мПовтор);

  Рег.ОсвободитьРОН(рп); 
  Рег.ОсвободитьРОН(рв); 
  Рег.ОсвободитьРОН(рт); 
  Узел.Освободить(у); 
  Код.СбросПост
КОН ДляВида;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       СравнитьПриёмники-(па,пб:Данные.ДкПонятию);

 (*................................................подЗАДАЧА...*)
  ЗАДАЧА СравнитьВиды(вида,
                      видб:Данные.ДкВиду);
  УКАЗ
    ЕСЛИ вида # видб ТО
      ЕСЛИ (вида.родв = Данные.вЗадача)
          И
           (видб.родв = Данные.вЗадача)
      ТО
        СравнитьПриёмники(вида.первпон,видб.первпон)

      АЕСЛИ (вида.родв В {Данные.вРяд,Данные.вОРяд})
           И
            (видб.родв В {Данные.вРяд,Данные.вОРяд})
      ТО
        СравнитьВиды(вида.овид,видб.овид)

      АЕСЛИ (вида.родв = Данные.вЦепь)
           И 
            (видб.родв = Данные.вЦепь)
           И
            (вида.размер = видб.размер)
      ТО
        (* хорошо *)
      ИНАЧЕ
        Ошибка.Отметить(Ошибка.НЕСООТВЕТСТВИЕ_ПРИЕМНИКА)
      КОН
    КОН
  КОН СравнитьВиды;

УКАЗ
  ПОКА па # ПУСТО ВЫП
    ЕСЛИ (пб = ПУСТО)
        ИЛИ
         (па.родп # пб.родп)
    ТО
      Ошибка.Отметить(Ошибка.НЕСООТВЕТСТВИЕ_ПРИЕМНИКА)
    КОН;

    СравнитьВиды(па.вид,пб.вид);

    пб:=пб.след;
    па:=па.след
  КОН;
  ЕСЛИ Данные.ЭтоПриёмник(пб) ТО
    Ошибка.Отметить(Ошибка.НЕСООТВЕТСТВИЕ_ПРИЕМНИКА)
  КОН
КОН СравнитьПриёмники;

(******************************************************************************)
ЗАДАЧА Переписать(уа+,уб+:Узел.нВид; размер:ЦЕЛ); 
(* Переписывает из <уа> <размер> байт в <уб>. *)
ПЕР
  вр:ЦЕЛ; (* временный регистр *)
  рр:ЦЕЛ; (* регистр для размера *)
УКАЗ
  ЕСЛИ размер > 0 ТО
    Узел.АдресВРег(уб);
    Узел.АдресВРег(уа);
    (* переносим побайтно *)
    ЕСЛИ размер < 3 ТО
      (* 1 и 2 ячейки переносим вручную *)
      Рег.ЗанятьРОН(вр);
      ПОКА размер > 0 ВЫП
        Код.ПЗС1(Код.LDRBp,вр,уа.ро,1);
        Код.ПЗС1(Код.STRBp,вр,уб.ро,1);
        УМЕНЬШИТЬ(размер)
      КОН;
      Рег.ОсвободитьРОН(вр)
    ИНАЧЕ
      Рег.ЗанятьРОН(рр);
      Код.ЗагрузитьПост(рр,размер);
      Код.ПереписатьПамять(уа.ро,уб.ро,рр);
      Рег.ОсвободитьРОН(рр)
    КОН
  КОН
КОН Переписать;

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

(******************************************************************************)
ЗАДАЧА Передать-(уи+:Узел.нВид; пп:Данные.ДкПонятию; быстрая:КЛЮЧ);
(* Передает источник <уи> приёмнику <пп> *)
ПЕР
  уп:Узел.нВид; (* узел приёмника *)
  уд:Узел.нВид; (* дополнительный узел размера источника оряд или ОВ набора *)
  естьУд:КЛЮЧ; (* есть <уд> *)
  рд:ЦЕЛ;      (* регистр для <уд> *)
УКАЗ
  естьУд:=ОТКЛ;
  ЕСЛИ пп.родп # Данные.пСсылка ТО
    ЕСЛИ быстрая ТО
      уп.роду:=Узел.уРпер;
      уп.ро:=пп.адр
    ИНАЧЕ
      уп.роду:=Узел.уАдрЗС;
      уп.ро:=Рег.SP;
      уп.a:=-4
    КОН;
    уп.вид:=пп.вид;
    Присвоить(уп,уи)
  ИНАЧЕ
    ЕСЛИ НЕ (Данные.прНеизменяемая В пп.признаки) И уи.толькочт ТО
      Ошибка.Отметить(Ошибка.ПЕР_ДЛЯ_ЧТЕНИЯ)
    АЕСЛИ уи.роду > Узел.уПост ТО
      Ошибка.Отметить(Ошибка.ЭТО_НЕ_ПЕРЕМЕННАЯ)
    АЕСЛИ (уи.роду = Узел.уПост) И НЕ ((пп.вид.родв = Данные.вЦепь) ИЛИ (пп.вид.родв = Данные.вОЯчейки)) ТО
      Ошибка.Отметить(Ошибка.ЭТО_НЕ_ПЕРЕМЕННАЯ)
    АЕСЛИ (пп.вид.родв = Данные.вНабор) И (уи.вид.родв = Данные.вНабор) ТО
      естьУд:=ВКЛ;
      ЕСЛИ быстрая ТО
        рд:=Рег.ЗанятьСледПер()
      КОН;
      РасширенОт(уи.вид,пп.вид);
      ЕСЛИ (уи.роду В {Узел.уАдрС,Узел.уАдрСАдрС}) И (уи.пон = Данные.поДоступу) ТО
        (* в переменной или приёмнике переменной была ссылка на набор *)
        уд:=уи;
        ЕСЛИ уи.роду = Узел.уАдрС ТО
          уд.a:=-4
        ИНАЧЕ
          уд.b:=-4
        КОН
      АЕСЛИ (уи.роду = Узел.уАдрСАдрС) И (уи.пон # Данные.поДоступу) ТО
        (* приёмник переменной набора *)
        уд.роду:=Узел.уАдрС;
        уд.ро:=уи.ро;
        уд.a:=уи.a+4
      ИНАЧЕ
        (* просто набор *)
        уд.роду:=Узел.уРон;
        ЕСЛИ быстрая ТО
          Рег.Нужен(рд) (* убыстрение *)
        КОН;
        Рег.ЗанятьРОН(уд.ро);
        Код.ЗагрузитьОВ(уд.ро,уи.вид)
      КОН;
      уд.вид:=Данные.цел32вид
    АЕСЛИ пп.вид.родв = Данные.вЦепь ТО
      ЕСЛИ (уи.роду = Узел.уПост) И (уи.вид.родв = Данные.вЗнак) ТО
        Узел.ЗнакВЦепь(уи)
      КОН;
      ЕСЛИ уи.вид.родв # Данные.вЦепь ТО
        Ошибка.Отметить(Ошибка.ВИД_ПРИЕМНИКА)
      КОН;
      ЕСЛИ пп.вид.размер = 0 ТО (* оЦепь *)
        естьУд:=ВКЛ;
        ЕСЛИ быстрая ТО
          рд:=Рег.ЗанятьСледПер()
        КОН;
        ЕСЛИ уи.вид.размер = 0 ТО (* оЦепь *)
          уд.вид:=Данные.цел32вид;
          уд.роду:=Узел.уАдрС;
          уд.ро:=уи.ро;
          уд.a:=уи.a+4
        ИНАЧЕ
          Узел.СоздатьЦелПост(уд,уи.вид.размер ДЕЛИТЬ Настрой.рЗнак)
        КОН
      АЕСЛИ пп.вид.размер # уи.вид.размер ТО
        Ошибка.Отметить(Ошибка.ВИД_ПРИЕМНИКА)
      КОН
    АЕСЛИ пп.вид.родв = Данные.вОЯчейки ТО
      естьУд:=ВКЛ;
      ЕСЛИ быстрая ТО
        рд:=Рег.ЗанятьСледПер()
      КОН;
      ЕСЛИ (уи.роду = Узел.уПост) И (уи.вид.родв = Данные.вЗнак) ТО
        Узел.ЗнакВЦепь(уи)
      КОН;
      (* уи - оряд *)
      ЕСЛИ (уи.вид.родв = Данные.вОЯчейки) ИЛИ (уи.вид.родв = Данные.вЦепь) И (уи.вид.размер = 0) ТО
        уд.вид:=Данные.цел32вид;
        уд.роду:=Узел.уАдрС;
        уд.ро:=уи.ро;
        уд.a:=уи.a+4;
        ЕСЛИ уи.вид.родв = Данные.вЦепь ТО
          ЕСЛИ быстрая ТО
            Рег.Нужен(рд) (* убыстрение *)
          КОН;
          Узел.ПеренестиВРОН(уд);
          ЕСЛИ быстрая ТО
            Рег.Нужен(-1) (* убыстрение *)
          КОН;
          Код.ОД(Код.MOV,уд.ро,0,уд.ро,Код.LSL,1+16) (* MOV уд.ро,уд.ро LSL 1 *)
        КОН
      ИНАЧЕ
        Узел.СоздатьЦелПост(уд,уи.вид.размер)
      КОН
    (* всё верно, если: *)
    АЕСЛИ (пп.вид = Данные.одоствид) И (уи.вид.родв = Данные.вДоступ) ТО
    АЕСЛИ уи.вид = пп.вид ТО
    АЕСЛИ (пп.вид.родв = Данные.вЯчейка) И (уи.вид.родв = Данные.вЦел8) ТО
    ИНАЧЕ
      Ошибка.Отметить(Ошибка.ВИД_ПРИЕМНИКА)
    КОН;
    ЕСЛИ быстрая ТО
      ЕСЛИ естьУд ТО
        Узел.ПеренестиВТребРег(уд,рд)
      КОН;
      Рег.Нужен(пп.адр); (* убыстрение *)
      Узел.АдресВРег(уи);
      Узел.ПеренестиВТребРег(уи,пп.адр);
      Рег.Нужен(-1) (* убыстрение *)
    ИНАЧЕ
      ЕСЛИ естьУд ТО
        Узел.ВСтог(уд)
      КОН;
      Узел.АдресВРег(уи);
      Узел.ВСтог(уи)
    КОН
  КОН
КОН Передать;

(******************************************************************************)
ЗАДАЧА Вызов-(у+:Узел.нВид; быстрая:КЛЮЧ);
ПЕР 
  разница:ЦЕЛ; (* разница в уровнях текущей и вызываемой задач *)
  р:ЦЕЛ;
  ус:Узел.нВид; (* для SL - связи окон по уровням *)
УКАЗ
  ЕСЛИ у.роду = Узел.уЗадача ТО
    ЕСЛИ (у.пон.обл.уровень > 0) И (* вызываем вложенную задачу *)
         (НЕ быстрая) ТО (* у быстрых SL уже хранится в FP *)
      разница:=Данные.уровень-у.пон.обл.уровень;
      (* нужно сохранить SL *)
      ус.роду:=Узел.уРон;
      ус.ро:=Рег.FP;
      ус.вид:=Данные.цел32вид;
      ЕСЛИ разница > 0 ТО (* SL не в FP, а глубже *)
        Рег.ЗанятьРОН(р); 
        ПОКА разница > 0 ВЫП
          Код.ПЗС1(Код.LDR,р,ус.ро,8);
          ус.ро:=р;
          УМЕНЬШИТЬ(разница)
        КОН
      КОН;
      Узел.ВСтог(ус)
    КОН;
    Код.Вызов(у.пон)
  АЕСЛИ (у.вид # ПУСТО) И (у.вид.родв = Данные.вЗадача) ТО
    Узел.ПеренестиВРег(у);
    Код.ОД(Код.MOV,Рег.LR,0,Рег.PC,0,0);
    Код.ОД(Код.MOV,Рег.PC,0,у.ро,0,0);
    у.вид:=у.вид.овид
  ИНАЧЕ
    Ошибка.Отметить(Ошибка.ЭТО_НЕ_ЗАДАЧА)
  КОН
КОН Вызов;

(******************************************************************************)
ЗАДАЧА Вход-(размерПеременных:ЦЕЛ; быстрая:КЛЮЧ);
(* вход в задачу *)
УКАЗ
  ЕСЛИ НЕ быстрая ТО
    (* сохраняем FP и LR *)
    Код.СЗС(Код.STMDB,Рег.SP,ВКЛ,{Рег.FP,Рег.LR});
    (* устанавливаем новый FP *)
    Код.ОД(Код.MOV,Рег.FP,0,Рег.SP,0,0);
    (* освобождаем место для своих переменных *)
    ЕСЛИ размерПеременных > 0 ТО
      Код.ОД1(Код.SUB,Рег.SP,Рег.SP,размерПеременных)
    КОН
  КОН
КОН Вход;

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

(******************************************************************************)
ЗАДАЧА Возврат-(размерПриёмников:ЦЕЛ; быстрая:КЛЮЧ);
УКАЗ
  ЕСЛИ быстрая ТО
    Код.ОД(Код.MOV,Рег.PC,0,Рег.LR,0,0)
  ИНАЧЕ
    Код.ОД(Код.MOV,Рег.SP,0,Рег.FP,0,0);
    ЕСЛИ размерПриёмников > 0 ТО
      (* восстанавливаем FP *)
      Код.ПЗС1(Код.LDRp,Рег.FP,Рег.SP,4); 
      (* возврат *)
      Код.ПЗС1(Код.LDRp,Рег.PC,Рег.SP,4+размерПриёмников)
    ИНАЧЕ
      Код.СЗС(Код.LDMIA,Рег.SP,ВКЛ,{Рег.FP,Рег.PC})
    КОН
  КОН
КОН Возврат;

(******************************************************************************)
ЗАДАЧА ПолучитьОтвет-(сохрРеги:МНОЖ; у+:Узел.нВид);
УКАЗ
  Рег.БудутЗаняты(сохрРеги+{0});
  (* ответ в регистр *)
  у.роду:=Узел.уРон;
  ЕСЛИ 0 В сохрРеги ТО
    (* чтобы не затереть ответ, переносим его из R0 в др. регистр *)
    Рег.ЗанятьРОН(у.ро);
    Код.ОД(Код.MOV,у.ро,0,0,0,0)
  ИНАЧЕ
    у.ро:=0
  КОН;
  ЕСЛИ сохрРеги # {} ТО
    Код.СЗС(Код.LDMIA,Рег.SP,ВКЛ,сохрРеги)
  КОН
КОН ПолучитьОтвет;

(******************************************************************************)
ЗАДАЧА СохранитьРеги-():МНОЖ;
(* работает до вызова задачи с ответом *)
ПЕР
  сохрРеги:МНОЖ;
УКАЗ
  сохрРеги:=Рег.Заняты();
  ЕСЛИ сохрРеги # {} ТО
    Код.СЗС(Код.STMDB,Рег.SP,ВКЛ,сохрРеги)
  КОН;
  Рег.БудутЗаняты({});
  ВОЗВРАТ сохрРеги
КОН СохранитьРеги;

(******************************************************************************)
ЗАДАЧА ВДопПер-(у+:Узел.нВид);
(* Переносит <у> в новую дополнительную (стоговую) переменную *)
УКАЗ
  Узел.ВСтог(у);
  у.роду:=Узел.уАдрС;
  у.ро:=Рег.SP;
  у.a:=0;
  у.вид:=Данные.цел32вид
КОН ВДопПер;

(******************************************************************************)
ЗАДАЧА УбратьДопПер-(п:ЦЕЛ);
(* Убирает из стога <п> дополнительных переменных *)
УКАЗ
  ПРОВЕРИТЬ(п >= 0);
  ЕСЛИ Данные.быстрая ТО
    Рег.ОсвободитьПер(п)
  ИНАЧЕ
    ЕСЛИ п > 0 ТО
      Код.ОД1(Код.ADD,Рег.SP,Рег.SP,п*4)
    КОН
  КОН
КОН УбратьДопПер;

(******************************************************************************)
ЗАДАЧА Выбрать-(у+:Узел.нВид; мОт,мДо,мТабл,мИначе:ЦЕЛ);
ПЕР
  гр:ЦЕЛ; (* регистр для границы *)
УКАЗ
(*MOV ур,...
  LDR гр,[До]
  CMP ур,гр
  BGT мИначе
  LDR гр,[От]
  CMP ур,гр
  BLT мИначе
  SUB ур,ур,гр
  LDR гр,[Табл]
  LDR PC,[гр+(ур<<2)]
Табл dcd мТабл
До   dcd мДо
От   dcd мОт
  ...
мОт  equ от
мДо  equ до
мТабл
  DCD м1
  DCD м2 *)  
  Узел.ПеренестиВРОН(у);
  Рег.ЗанятьРОН(гр);

Код.ЗагрузитьМетку(гр,мДо);

  Код.будетS:=ВКЛ;
  Код.ОД(Код.CMP,0,у.ро,гр,0,0);
 Код.ПереходПоКУ(мИначе,Код.GT);

Код.ЗагрузитьМетку(гр,мОт);

  Код.ОД(Код.CMP,0,у.ро,гр,0,0);
 Код.ПереходПоКУ(мИначе,Код.LT);
  Код.ОД(Код.SUB,у.ро,у.ро,гр,0,0);

Код.ЗагрузитьМетку(гр,мТабл);

  Код.ПЗС(Код.LDR,Рег.PC,гр,у.ро,2);
  Узел.Освободить(у);
  Рег.ОсвободитьРОН(гр); 
  Код.Примечание("От До Таблица");
  Код.СбросПост
КОН Выбрать;

(******************************************************************************)
ЗАДАЧА
       ПринимаемаяЗадача-(задача:Данные.ДкПонятию;
                          внешнееИмя-:ЦЕПЬ;
                    размерПриёмников :ЦЕЛ);

  ЗАДАЧА Передать(пон:Данные.ДкПонятию; номер:ЦЕЛ);
  (* Цель:  передача в обратном порядке источников (приёмников нашей задачи)
   *        в принимаемую задачу
   * До:    <пон>   - понятие приёмника  нашей задачи
   *        <номер> - номер этого приёмника (от 0) *)
  ПЕР
    у:Узел.нВид;
  УКАЗ
    ЕСЛИ пон = ПУСТО ТО ВОЗВРАТ КОН;
    Передать(пон.след,номер+1);
    (* создаём узел источника *)
    у.роду:=Узел.уАдрС;
    у.ро:=Рег.FP;
    у.a:=пон.адр;
    у.вид:=Данные.цел32вид;
    (* записываем *)
    ЕСЛИ номер < 4 ТО
      Узел.ПеренестиВТребРег(у,номер)
    ИНАЧЕ
      Узел.ВСтог(у)
    КОН
  КОН Передать;

УКАЗ
  (* начало кода задачи *)
  Код.ПоставитьИмя(задача);
  Вход(0,ОТКЛ); (* без переменных *)
  (* код нашей задачи (передача приёмников) *)
  Передать(задача.первпон,0);
  Код.ВызовВнешнегоИмени(внешнееИмя);
  (* конец кода задачи *)
  Возврат(размерПриёмников,ОТКЛ);
  Код.СбросПост
КОН ПринимаемаяЗадача;

(******************************************************************************)
ЗАДАЧА ПередаваемаяЗадача-(задача:Данные.ДкПонятию);
(* Вывод промежуточного кода между ОС и задачей Глагола.
 * В стог сохраненяются используемые регистры и перезаписываются
 * в нужном порядке приёмники задачи.
 ------------------------------------------------------------------------------
 № | Стог     | Указ |  № | № | Метка | Код
 ------------------------------------------------------------------------------
 5   Пр6      | <-sp    5 |            EXPORT |Задача|                         
     Пр5      |           |    |Задача|                                        
     Пр4(r3)  |           | 1          mov   r12,sp                            
     Пр3(r2)  |           | 2          stmdb sp!,{r4-r10,fp,r12,lr}                             
     Пр2(r1)  |           | 3          add   fp, sp, #32                       
     Пр1(r0)  |           | 4          str   r0,[sp,#-4]! ; приёмник в регистре     
 2   r4       | <-sp  2 6 |            ...                                     
     r5       |           |            ldr   r10,[fp,#8]  ; приёмник в стоге                       
     r6       |           |            str   r10,[sp,#-4]!                     
     r7       |           |            ...                                     
     r8       |           | 5          bl    |.Отдел.Задача|                   
     r9       |           | 6          sub   sp, fp, #32                       
     r10      |           | 7          ldmia sp, {r4-r10,fp,sp ,pc}            
     r11(fp') |           |    |.Отдел.Задача|                                                              
     r12=sp'  | <-fp    3 |            ...   ; код задачи Глагола                                 
     r14(lr') |           |
 1   .. (Пр5) | <-sp  1 7 |
     .. (Пр6) |           | *)
ПЕР
  приёмник:Данные.ДкПонятию; (* понятие приёмника нашей задачи *)
  номер:ЦЕЛ; (* номер этого приёмника (от 0) *)
  у:Узел.нВид;
УКАЗ
  (* 1 *)
  Код.ПоставитьВнешнееИмя(задача.имя);
  Код.ОД(Код.MOV,12,0,Рег.SP,0,0);
  (* 2 *)
  Код.СЗС(Код.STMDB,Рег.SP,ВКЛ,{4..10,Рег.FP,12,Рег.LR});
  (* 3 *)
  Код.ОД1(Код.ADD,Рег.FP,Рег.SP,8*4);
  (* 4 *)
  у.вид:=Данные.цел32вид;
  номер:=0;
  приёмник:=задача.первпон;
  ПОКА Данные.ЭтоПриёмник(приёмник) ВЫП
    ЕСЛИ номер < 4 ТО
      у.роду:=Узел.уРон;
      у.ро:=номер
    ИНАЧЕ
      у.роду:=Узел.уАдрС;
      у.ро:=Рег.FP;
      у.a:=8+(номер-4)*4
    КОН;
    Узел.ВСтог(у);
    Узел.Освободить(у);
    УВЕЛИЧИТЬ(номер);
    приёмник:=приёмник.след
  КОН;
  (* 5 *)
  Код.Вызов(задача);
  (* 6 *)
  Код.ОД1(Код.SUB,Рег.SP,Рег.FP,8*4);
  (* 7 *)
  Код.СЗС(Код.LDMIA,Рег.SP,ОТКЛ,{4..10,Рег.FP,Рег.SP,Рег.PC});
  Код.СбросПост
КОН ПередаваемаяЗадача;

(******************************************************************************)
ЗАДАЧА ОстановПриложения-;
УКАЗ
  Код.ВызовСреды("Стоп")
КОН ОстановПриложения;

КОН ВКод.
