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

ИСПОЛЬЗУЕТ 
  Данные,
  Узел,
  Код,
  Рег,
  Ошибка;

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

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

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

(*----------------------------------------------------------------------------*)
ЗАДАЧА ЦелВСтек(ц:ЦЕЛ); 
(* Заносит <ц> в стек. *)
ПЕР
  y:Узел.нВид;
УКАЗ
  Узел.СоздатьЦелПост(y,ц);
  Узел.ВСтек(y)
КОН ЦелВСтек;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Переписать(уа+,уб+:Узел.нВид; размер:ЦЕЛ); 
(* Переписывает из <уа> <размер> байт в <уб>. *)
ПЕР
  вр:ЦЕЛ; (* временный регистр *)
  рр:ЦЕЛ; (* регистр для размера *)
УКАЗ
  ЕСЛИ размер > 0 ТО

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

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Присвоить-(уа+,уб+:Узел.нВид); 
(* уа:=уб *)
ПЕР
  вида,видб:Данные.ДкВидуВид;
  родва,родвб:ЦЕЛ; 
  овида,овидб:Данные.ДкВидуВид;
  размерб:ЦЕЛ;

УКАЗ
   вида:=уа.вид;
   видб:=уб.вид;
  родва:=вида.родв;
  родвб:=видб.родв;
  овида:=вида.овид;
  овидб:=видб.овид;

  ЕСЛИ
        уа.роду = Узел.уПост
  ТО
    Ошибка.Отметить(Ошибка.ПРИСВАИВАНИЕ_НЕ_ПЕРЕМЕННОЙ)
  АЕСЛИ
        уа.толькочт
  ТО
    Ошибка.Отметить(Ошибка.ПЕР_ДЛЯ_ЧТЕНИЯ)
  АЕСЛИ
       (уб.роду = Узел.уЗадача)
      И
       (родва # Данные.вЗадача)
  ТО
    Ошибка.Отметить(Ошибка.ОТВЕТ_НЕ_ИСПОЛЬЗОВАН)
  КОН;

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

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

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

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

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

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

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

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

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

КОН ВКод.
