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

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

  Настрой,
  Данные,
  Рег,
  Обмен,
  Ошибка;

(*------ номера используемых кодов действий (нкд) ----------------------------*)
ПОСТ   
                                       (* Простая Загрузка и Сохранение (ПЗС) *)
  LDR-  = 1;
  STR-  = 2;
  LDRB- = 3;
  STRB- = 4;
  LDRp- = 5; (* вычисление адреса после доступа *)
  STRp- = 6; (* вычисление адреса после доступа *)
  LDRBp-= 7; (* вычисление адреса после доступа *)
  STRBp-= 8; (* вычисление адреса после доступа *)
                                         (* Узкая Загрузка и Сохранение (УЗС) *)
  LDRSH-= 9;
  LDRSB-=10;
  STRH- =11;
                                     (* Составная Загрузка и Сохранение (СЗС) *)
  LDMIA-=12;
  STMDB-=14;
                        (* Обработка Данных (ОД) *)
                (* у всех, кроме MOV, д.б. ВКЛ S-разряд *)
  MOV-  =15;
  MVN-  =16;
  TST-  =17;
  CMP-  =18; 
  ADD-  =19;
  SUB-  =20; 
  AND-  =21; 
  EOR-  =22; 
  ORR-  =23;
  RSB-  =24;
  BIC-  =25;
               (* умножение *)
  MUL-  =26;
  MLA-  =27;

(*------ коды условий (КУ) ---------------------------------------------------*)
ПОСТ
  EQ-= 0; (*    =    *)
  NE-= 1; (*    #    *)
  CS-= 2; (*    >=   *)
  CC-= 3; (*    <    *)
  MI-= 4; (*         *)
  PL-= 5; (*         *)
  VS-= 6; (*         *)
  VC-= 7; (*         *)
  HI-= 8; (*    >    *) 
  LS-= 9; (*    <=   *)
  GE-=10; (* зн >=   *)
  LT-=11; (* зн <    *)
  GT-=12; (* зн >    *)
  LE-=13; (* зн <=   *)
  AL-=14; (* всегда  *)
  NV-=15; (* никогда *) 

(*------ способы сдвигов (СС) ------------------------------------------------*)
ПОСТ
  LSL-= 1; (* логический влево            *)
  LSR-= 2; (* логический вправо           *)
  ASR-= 3; (* арифметический вправо       *)
  ROR-= 4; (* вращение вправо             *)
  RRX-= 5; (* расширенное вращение вправо *)

(*------ цепочки знаков отдела -----------------------------------------------*)
ПОСТ
  БайтЦепочкам=10000; (* выделяется памяти под все цепочки отдела *)

ПЕР
  цепочки:ЦЕПЬ[БайтЦепочкам]; (* память        *)
  байтЦепочек:ЦЕЛ;            (* занято памяти *)

(*------ скопления постоянных ------------------------------------------------*)
ПОСТ
  СловПост=1024; (* размер скопления *)
                                        (* разновидности постоянных:          *)
  пЧисло  =0; (* числовая постоянная    *)
  пЦепьАдр=1; (* адрес цепочки знаков   *)
  пОбщАдр =2; (* адрес общей переменной *)

ВИД
  Пост = НАБОР
    родп:ЦЕЛ;                  (* пЧисло, пЦепьАдр, пОбщАдр *)
    знач:ЦЕЛ;                  (* число, смещ. цепочки      *)
    метка:ЦЕЛ;                 (* метка у постоянной        *)
    понД:Данные.ДкВидуПонятие  (* общая переменная *)
  КОН;

ПЕР
  разрешёнСбросПост:ЦЕЛ;      (* если >=0, то сброс разрешён  *)
  пост:РЯД СловПост ИЗ Пост;  (* текущее скопление постоянных *)
  словПост:ЦЕЛ;               (* счётчик постоянных в <пост>  *)
  удалениеПост:ЦЕЛ;           (* смещение от постоянной до самой удалённой LDR *)

(*----------------------------------------------------------------------------*)
ПЕР
  СК-:ЦЕЛ;      (* счётчик выработанных команд *)
  будетКУ+:ЦЕЛ; (* КУ для следующей команды (после сбрасывается в AL)   *)
  будетS+:КЛЮЧ; (* S признак для следующей команды (после сбрасывается) *)
  текМетка:ЦЕЛ; (* номер выданной метки *)


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

ЗАДАЧА ^ПроверитьЗаполнениеПост;
ЗАДАЧА ^СбросПост-;
ЗАДАЧА ^ПЗС1-(нкд,рн,ро,смещ:ЦЕЛ);
ЗАДАЧА ^ОД1-(нкд,рн,р1,пост:ЦЕЛ); 


(*
 * Далее задачи для вывода текста на машинном языке. Для преобразования
 * нескольких аргументов используется особое описание. Описание содержит
 * обычные знаки, которые просто переписываются в текст и следующие описатели
 * аргументов (после знака '%'):
 *  н - НМК
 *  р - регистр
 *  м - числовая метка
 *  у - код условия
 *  д - десятичное целое
 *  с - сдвиг
 *  ш - шестнадцатеричное целое
 *  з - знак
 *  о - отступ
 *  ^ - новая строка
 *)

(*----------------------------------------------------------------------------*)
ЗАДАЧА Вывод5(описание-:ЦЕПЬ; а0,а1,а2,а3,а4:ЦЕЛ);
(* Вывод в текст 5-и аргументов *)
ПОСТ
  (* признаки последующей обработки *)
  прСледАрг =0;
  прСледЗнак=1;
ПЕР
  дло:ЦЕЛ;      (* длина <описание>                      *)
  позо:ЦЕЛ;     (* позиции текущего знака в <описание>   *)
  зно:ЗНАК;     (* знак, прочитанный из <описание>       *)
  номарг:ЦЕЛ;   (* номер текущего аргумента              *)
  арг:ЦЕЛ;      (* текущий аргумент                      *)
  признаки:МНОЖ;(* множ. признаков последующей обработки *)
  оарг:ЦЕПЬ[100]; (* описание для тек. аргумента         *)
  тку:ЦЕПЬ[3];  (* текстовое представление КУ            *)

(*------------------------------------- подЗадача ---*)
  ЗАДАЧА СледЗнак;
  (* чтение следующего знака из <описание> *)
  УКАЗ
    ЕСЛИ позо < дло ТО
      зно:=описание[позо];
      УВЕЛИЧИТЬ(позо)
    ИНАЧЕ
      зно:=0X
    КОН
  КОН СледЗнак;

(*------------------------------------- подЗадача ---*)
  ЗАДАЧА КУвТКУ(ку:ЦЕЛ);
  (* преобразование кода условия <ку> в текстовый вид <тку> *)
  УКАЗ
    ВЫБРАТЬ ку ИЗ
    | EQ: тку:="EQ" | NE: тку:="NE" | CS: тку:="CS" | CC: тку:="CC"
    | MI: тку:="MI" | PL: тку:="PL" | VS: тку:="VS" | VC: тку:="VC"
    | HI: тку:="HI" | LS: тку:="LS" | GE: тку:="GE" | LT: тку:="LT"
    | GT: тку:="GT" | LE: тку:="LE" | AL: тку:="" 
    КОН
  КОН КУвТКУ;

УКАЗ
  дло:=ДЛИНА(описание);
  позо:=0;
  номарг:=0;
  арг:=а0;
  КОЛЬЦО
    СледЗнак;
    ПОКА зно = '%' ВЫП
      СледЗнак;
      ВЫБРАТЬ зно ИЗ
      | 'м':
        оарг:="|%d|";
        признаки:={прСледАрг,прСледЗнак}
      | 'р':
        ВЫБРАТЬ арг ИЗ
        | Рег.PC: оарг:="PC"
        | Рег.LR: оарг:="LR"
        | Рег.SP: оарг:="SP"
        | Рег.FP: оарг:="FP"
        ИНАЧЕ
          оарг:="R%d"
        КОН;
        признаки:={прСледАрг,прСледЗнак}
      | 'с':
        ВЫБРАТЬ арг ИЗ
        | LSL: оарг:="LSL"
        | LSR: оарг:="LSR"
        | ASR: оарг:="ASR"
        | ROR: оарг:="ROR"
        | RRX: оарг:="RRX"
        КОН;
        признаки:={прСледАрг,прСледЗнак}
      | 'д':
        оарг:="%d";
        признаки:={прСледАрг,прСледЗнак}
      | 'ш':
        оарг:="0x%x";
        признаки:={прСледАрг,прСледЗнак}
      | 'н':  
        ВЫБРАТЬ арг ИЗ
        | AND:  оарг:="AND"
        | EOR:  оарг:="EOR"
        | SUB:  оарг:="SUB"
        | RSB:  оарг:="RSB"
        | ADD:  оарг:="ADD"
        | TST:  оарг:="TST"
        | CMP:  оарг:="CMP"
        | ORR:  оарг:="ORR"
        | MOV:  оарг:="MOV"
        | BIC:  оарг:="BIC"
        | MVN:  оарг:="MVN"
        | MUL:  оарг:="MUL"
        | MLA:  оарг:="MLA"
        | LDR:
            оарг:="LDR"
        | STR:  оарг:="STR"
        | LDRB: оарг:="LDRB"
        | STRB: оарг:="STRB"
        | STRH: оарг:="STRH"
        | LDRSH:оарг:="LDRSH"
        | LDRSB:оарг:="LDRSB"
        | LDMIA:оарг:="LDMIA"
        | STMDB:оарг:="STMDB"
        КОН;
        КУвТКУ(будетКУ);
        оЦепи.ДобавитьВКонец(оарг,тку);
        будетКУ:=AL;
        ЕСЛИ будетS ТО
          оЦепи.ДобавитьВКонец(оарг,"S");
          будетS:=ОТКЛ
        КОН;
        признаки:={прСледАрг,прСледЗнак}
      | 'з':
        ЕСЛИ оЗнака.ВСлове(ВЗНАК(арг)) ТО
          оарг:='"%c"'
        ИНАЧЕ
          оарг:="0x%x"
        КОН;
        признаки:={прСледАрг,прСледЗнак}
      | 'у':
        КУвТКУ(арг);
        СПИСАТЬ(тку,оарг);
        признаки:={прСледАрг,прСледЗнак}
      | 'о':
        Обмен.КодЗнак(09X);
        признаки:={прСледЗнак}
      ИНАЧЕ
        ЕСЛИ зно = '%' ТО
          Обмен.КодЗнак(зно);
          признаки:={прСледЗнак}
        ИНАЧЕ
          признаки:={}
        КОН;
      КОН;
      ЕСЛИ прСледЗнак В признаки ТО
        СледЗнак
      КОН;
      ЕСЛИ прСледАрг В признаки ТО
        Обмен.КодЦел(оарг,арг);
        ЕСЛИ номарг < 4 ТО
          УВЕЛИЧИТЬ(номарг)
        КОН;
        ВЫБРАТЬ номарг ИЗ
        | 1: арг:=а1
        | 2: арг:=а2
        | 3: арг:=а3
        | 4: арг:=а4
        КОН
      КОН
    КОН;
    ЕСЛИ зно = 0X ТО ВЫХОД КОН;
    Обмен.КодЗнакЦепи(зно)
  КОН
КОН Вывод5;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Вывод4(описание-:ЦЕПЬ; а0,а1,а2,а3:ЦЕЛ);
УКАЗ Вывод5(описание,а0,а1,а2,а3,0) КОН Вывод4;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Вывод3(описание-:ЦЕПЬ; а0,а1,а2:ЦЕЛ);
УКАЗ Вывод5(описание,а0,а1,а2,0,0) КОН Вывод3;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Вывод2(описание-:ЦЕПЬ; а0,а1:ЦЕЛ);
УКАЗ Вывод5(описание,а0,а1,0,0,0) КОН Вывод2;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Вывод1(описание-:ЦЕПЬ; а0:ЦЕЛ);
УКАЗ Вывод5(описание,а0,0,0,0,0) КОН Вывод1;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Вывод0(описание-:ЦЕПЬ);
УКАЗ Вывод5(описание,0,0,0,0,0) КОН Вывод0;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ВыводПолногоИмени(понД:Данные.ДкВидуПонятие);

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

УКАЗ
  Вывод0("|");
  ИмяОбласти(понД.обл);
  Вывод0(понД.имя);
  Вывод0("|")
КОН ВыводПолногоИмени;

(*----------------------------------------------------------------------------*)
(*                        обслуживание меток и переходов                      *)
(*----------------------------------------------------------------------------*)

(*----------------------------------------------------------------------------*)
ЗАДАЧА УвеличитьСК;
(* увеличить <СК> и пересчитать <удалениеПост> *)
УКАЗ
  УВЕЛИЧИТЬ(СК);
  ЕСЛИ удалениеПост >= 0 ТО
    УВЕЛИЧИТЬ(удалениеПост)
  КОН
КОН УвеличитьСК;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПолучитьМетку-():ЦЕЛ;
(* создаёт новую метку *)
УКАЗ
  УВЕЛИЧИТЬ(текМетка);
  ВОЗВРАТ текМетка
КОН ПолучитьМетку;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПоставитьМетку-(метка:ЦЕЛ);
(* вывод числовой метки *)
УКАЗ
  Вывод1("%м^",метка)
КОН ПоставитьМетку;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПоставитьИмя-(понД:Данные.ДкВидуПонятие);
(* вывод текстовой метки *)
УКАЗ
  ВыводПолногоИмени(понД);
  Вывод0("^")
КОН ПоставитьИмя;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПоставитьПер-(понД:Данные.ДкВидуПонятие);
(* вывод метки для переменной *)
ПЕР
  размер:ЦЕЛ;
УКАЗ
  размер:=понД.вид.размер;
  УВЕЛИЧИТЬ(размер,(-размер) ОСТАТОК 4);
  ВыводПолногоИмени(понД);
  Вывод1("%о%% %ш^",размер)
КОН ПоставитьПер;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПереходПоКУ-(метка+,ку:ЦЕЛ); 
(* Цель:  вывод кода условного перехода "B" на метку <метка> или новую метку
 * До:    <метка> - существующая метка перехода или 0 для новой метки
 *        <ку>    - код условия перехода 
 * После: <метка> - если до <метка> была =0, то значение новой метки *)
УКАЗ
  ЕСЛИ ку # NV ТО
    ПроверитьЗаполнениеПост;
    Вывод2("%оB%у%о%м^",ку,метка);
    УвеличитьСК
  КОН
КОН ПереходПоКУ;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПереходНа-(метка+:ЦЕЛ); 
(* Цель: вывод кода безусловного перехода "B" на метку <метка>
 * До:   <метка> - метка перехода или 0 *)
УКАЗ
  ПереходПоКУ(метка,AL)
КОН ПереходНа;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Вызов-(понД:Данные.ДкВидуПонятие); 
(* Цель: вывод кода безусловного перехода с возвратом "BL"
 * До:   <понД> - вызываемая задача *)
УКАЗ
  ПроверитьЗаполнениеПост;
  Вывод0("%оBL%о");
  ВыводПолногоИмени(понД);
  Вывод0("^");
  УвеличитьСК
КОН Вызов;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВызовПоИмени-(имя-:ЦЕПЬ); 
(* Цель: вывод кода безусловного перехода с возвратом "BL"
 * До:   <имя> - имя вызываемой задачи *)
УКАЗ
  ПроверитьЗаполнениеПост;
  Вывод0("^%оBL%о");
  Вывод0(имя);
  Вывод0("^");
  УвеличитьСК
КОН ВызовПоИмени;

(*----------------------------------------------------------------------------*)
(*                      обслуживание скоплений постоянных                     *)
(*----------------------------------------------------------------------------*)

(*----------------------------------------------------------------------------*)
ЗАДАЧА ПроверитьЗаполнениеПост;
(* если постоянных в <пост> уже очень много, то сбрасывает их в область кода
 * и перешагивает через них *)
ПЕР
  метка:ЦЕЛ;
УКАЗ
  ЕСЛИ разрешёнСбросПост < 0 ТО
    ВОЗВРАТ
  КОН;
  ЕСЛИ удалениеПост >= СловПост-15 ТО
    метка:=ПолучитьМетку();
    УМЕНЬШИТЬ(разрешёнСбросПост);
    ПереходНа(метка);
    СбросПост;
ПоставитьМетку(метка);
    УВЕЛИЧИТЬ(разрешёнСбросПост)
  КОН
КОН ПроверитьЗаполнениеПост;

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

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА СбросПост-;
(* сбрасывает скопление <пост> в область кода *)
ПЕР
  ц:ЦЕЛ; (* счётчик *)
УКАЗ
  (* выдаём все постоянные в область кода *)
  ОТ ц:=0 ДО словПост-1 ВЫП
    Вывод1("%м%оDCD%о",пост[ц].метка);
    ВЫБРАТЬ пост[ц].родп ИЗ
    | пЧисло:   
        Вывод1("%д^",пост[ц].знач)
    | пЦепьАдр: 
        (* 0-я метка + смещение *)
        Вывод2("%м+%ш^",0,пост[ц].знач)
    | пОбщАдр: 
        ВыводПолногоИмени(пост[ц].понД);
        Вывод0("^")
    КОН;
    УВЕЛИЧИТЬ(СК)
  КОН;
  (* готовимся к новому заполнению скопления *)
  словПост:=0;
  удалениеПост:=-1
КОН СбросПост;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ВычисляемаяПост(число:ЦЕЛ):КЛЮЧ;
(* пытается представить <число> в виде правого вращения
 * 8 разрядной беззнаковой постоянной, т.е. <число> = <ц8> >> (2*<вр2>)
 * возвращает ВКЛ, если такое возможно *)
ПЕР
  вр2:ЦЕЛ;
УКАЗ
  вр2:=0;
  ПОКА (вр2 < 15) И НЕ ((число >= 0) И (число <= 255)) ВЫП
    число:=Асм.Вращение(число,-2);
    УВЕЛИЧИТЬ(вр2)
  КОН;
  ВОЗВРАТ (число >= 0) И (число <= 255)
КОН ВычисляемаяПост;

(*----------------------------------------------------------------------------*)
ЗАДАЧА LDRпоPC(р,метка:ЦЕЛ);
(* LDR в регистр <р> постоянной, расположенной рядом с PC *)
ПЕР
  будетS:КЛЮЧ;
УКАЗ
  ПРОВЕРИТЬ((р >= 0) И (р <= 15));
  (* задержим S *)
  будетS:=Код.будетS;
  Код.будетS:=ОТКЛ;
  (* смещение должно быть в байтах *)
  Вывод3("%о%н%о%р,%м^",LDR,р,метка);
  (* отпустим S *)
  Код.будетS:=будетS;
  УвеличитьСК
КОН LDRпоPC;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ЗагрузитьПост-(р,число:ЦЕЛ);
УКАЗ
  ЕСЛИ ВычисляемаяПост(число) ТО
    ОД1(MOV,р,0,число) 
  ИНАЧЕ
    LDRпоPC(р,ВводПост(пЧисло,число,ПУСТО))
  КОН
КОН ЗагрузитьПост;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВводЦепочки-(понД:Данные.ДкВидуПонятие);
(* ввод цепочки в областьи цепочек и присваивание ей адреса в области цепочек *)
ПЕР
  поз:ЦЕЛ;
УКАЗ
  понД.адр:=байтЦепочек;
                                                (* конечный 0 тоже записываем *)
  ОТ поз:=0 ДО РАЗМЕР(понД.цепьД^)-1 ВЫП
    ЕСЛИ
         байтЦепочек >= БайтЦепочкам
    ТО
      Ошибка.Отметить(Ошибка.МНОГО_ПОСТОЯННЫХ)
    КОН;
    цепочки[байтЦепочек]:=понД.цепьД[поз];
    УВЕЛИЧИТЬ(байтЦепочек)
  КОН
КОН ВводЦепочки;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ЗагрузитьЦепьАдр-(р,цепьАдр:ЦЕЛ);
(*
 * вывод кода загрузки адреса цепочки в регистр <р>.
 * <цепьАдр> - адрес в области цепочек
 *)
УКАЗ
  LDRпоPC(р,ВводПост(пЦепьАдр,цепьАдр,ПУСТО))
КОН ЗагрузитьЦепьАдр;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ЗагрузитьОбщАдр-(р:ЦЕЛ; понД:Данные.ДкВидуПонятие);
УКАЗ
  LDRпоPC(р,ВводПост(пОбщАдр,0,понД))
КОН ЗагрузитьОбщАдр;


(*----------------------------------------------------------------------------*)
(* Далее:
 *   нкд - номер кода действия
 *   рн  - регистр назначения
 *   ро  - регистр основы
 *   рд  - регистр данных
 *   рс  - регистр сдвига
 *   ц8  - 8 разрядное целое число *)


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ОбратныйКУ-(ку:ЦЕЛ):ЦЕЛ; 
(* меняет смысл условия из <ку> на противоположный *)
УКАЗ
  ЕСЛИ ЧЕТ(ку) ТО
    ВОЗВРАТ ку+1
  ИНАЧЕ
    ВОЗВРАТ ку-1
  КОН
КОН ОбратныйКУ;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ПослеДоступа(нкд+:ЦЕЛ):КЛЮЧ; 
(* Если вычисление адреса Загрузки и Сохранения после доступа, то смена <нкд> *)
УКАЗ
  ВЫБРАТЬ нкд ИЗ
  | LDRp: нкд:=LDR
  | STRp: нкд:=STR
  | LDRBp:нкд:=LDRB
  | STRBp:нкд:=STRB
  ИНАЧЕ
    ВОЗВРАТ ОТКЛ
  КОН;
  ВОЗВРАТ ВКЛ
КОН ПослеДоступа;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВСтек-(рн:ЦЕЛ); 
(* Цель:  сохраняет регистр данных <рн> в стеке *)
УКАЗ
  ПроверитьЗаполнениеПост;
  Вывод4("%о%н%о%р,[%р,##%д]!^",STR,рн,Рег.SP,-4);
  УвеличитьСК
КОН ВСтек;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПЗС-(нкд,рн,ро,рс,сдвиг:ЦЕЛ); 
(* Простая Загрузка и Сохранение со смещением в регистре <рс>
 * с логическим сдвигом влево на <сдвиг> *)
УКАЗ
  ПРОВЕРИТЬ((рн >= 0) И (рн <= 15) И (ро >= 0) И (ро <= 15) И (рс >= 0) И (рс <= 15));
  ПроверитьЗаполнениеПост;
  ЕСЛИ ПослеДоступа(нкд) ТО
    Вывод5("%о%н%о%р,[%р],%р,LSL ##%ш^",нкд,рн,ро,рс,сдвиг);
  ИНАЧЕ
    Вывод5("%о%н%о%р,[%р,%р,LSL ##%ш]^",нкд,рн,ро,рс,сдвиг);
  КОН;
  УвеличитьСК
КОН ПЗС;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПЗС1-(нкд,рн,ро,смещ:ЦЕЛ); 
(* Простая Загрузка и Сохранение с непосредственным смещением *)
ПЕР
  р:ЦЕЛ;
УКАЗ
  ПРОВЕРИТЬ((рн >= 0) И (рн <= 15) И (ро >= 0) И (ро <= 15));
  ПроверитьЗаполнениеПост;
  ЕСЛИ МОДУЛЬ(смещ) >= 4096 ТО
    УМЕНЬШИТЬ(разрешёнСбросПост);
    Рег.Занять(р);
    ЗагрузитьПост(р,смещ);
    ПЗС(нкд,рн,ро,р,0);
    Рег.Освободить(р);
    УВЕЛИЧИТЬ(разрешёнСбросПост)
  ИНАЧЕ
    ЕСЛИ ПослеДоступа(нкд) ТО
      Вывод4("%о%н%о%р,[%р],##%д^",нкд,рн,ро,смещ)
    ИНАЧЕ
      Вывод4("%о%н%о%р,[%р,##%д]^",нкд,рн,ро,смещ)
    КОН;
    УвеличитьСК
  КОН
КОН ПЗС1;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА УЗС-(нкд,рн,ро,рс:ЦЕЛ);
(* Узкая Загрузка и Сохранение со смещением в регистре <рс> *)
УКАЗ
  ПРОВЕРИТЬ((рн >= 0) И (рн <= 15) И (ро >= 0) И (ро <= 15) И (рс >= 0) И (рс <= 15));
  ПроверитьЗаполнениеПост;
  ЕСЛИ ПослеДоступа(нкд) ТО
    Вывод4("%о%н%о%р,[%р],%р^",нкд,рн,ро,рс)
  ИНАЧЕ
    Вывод4("%о%н%о%р,[%р,%р]^",нкд,рн,ро,рс)
  КОН;
  УвеличитьСК
КОН УЗС;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА УЗС1-(нкд,рн,ро,смещ:ЦЕЛ); 
(* Узкая Загрузка и Сохранение (полуслов) с непосредственным смещением *)
ПЕР
  р:ЦЕЛ;
УКАЗ
  ПРОВЕРИТЬ((рн >= 0) И (рн <= 15) И (ро >= 0) И (ро <= 15));
  ПроверитьЗаполнениеПост;
  ЕСЛИ МОДУЛЬ(смещ) >= 256 ТО
    УМЕНЬШИТЬ(разрешёнСбросПост);
    Рег.Занять(р);
    ЗагрузитьПост(р,смещ);
    УЗС(нкд,рн,ро,р);
    Рег.Освободить(р);
    УВЕЛИЧИТЬ(разрешёнСбросПост)
  ИНАЧЕ
    ЕСЛИ ПослеДоступа(нкд) ТО
      Вывод4("%о%н%о%р,[%р],##%д^",нкд,рн,ро,смещ)
    ИНАЧЕ
      Вывод4("%о%н%о%р,[%р,##%д]^",нкд,рн,ро,смещ)
    КОН;
    УвеличитьСК
  КОН
КОН УЗС1;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА СЗС-(нкд,ро:ЦЕЛ; реги:МНОЖ);
(* Составная Загрузка и Сохранение с записью <ро> *)
ПЕР
  р:ЦЕЛ;
  сзапятой:КЛЮЧ; 
УКАЗ
  ПРОВЕРИТЬ((ро >= 0) И (ро <= 15));
  ПроверитьЗаполнениеПост;
  сзапятой:=ОТКЛ;
  Вывод2("%о%н%о%р!,{",нкд,ро);
  ОТ р:=0 ДО 15 ВЫП
    ЕСЛИ р В реги ТО
      ЕСЛИ сзапятой ТО
        Вывод0(",");
      КОН;
      Вывод1("%р",р);
      сзапятой:=ВКЛ
    КОН
  КОН;
  Вывод0("}^");
  УвеличитьСК
КОН СЗС;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Умн-(нкд,рн,р1,р2,р3:ЦЕЛ); 
(* Умножение *)
УКАЗ
  ПроверитьЗаполнениеПост;
  ПРОВЕРИТЬ((рн >= 0) И (рн <= 15) И (р1 >= 0) И (р1 <= 15) И (р2 >= 0) И (р2 <= 15));
  ПРОВЕРИТЬ(рн # р1);
  ПРОВЕРИТЬ(НЕ (Рег.PC В {рн,р1,р2}));
  ЕСЛИ нкд = MLA ТО
    (* р3 = добавляемый регистр *)
    Вывод5("%о%н%о%р,%р,%р,%р^",нкд,рн,р1,р2,р3)
  ИНАЧЕ
    Вывод4("%о%н%о%р,%р,%р^",нкд,рн,р1,р2)
  КОН;
  УвеличитьСК
КОН Умн;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ОД-(нкд,рн,р1,р2,сс,рс:ЦЕЛ); 
(* Обработка Данных со вторым данным в регистрах *)
УКАЗ
  ПроверитьЗаполнениеПост;
  ПРОВЕРИТЬ((рн >= 0) И (рн <= 15) И (р1 >= 0) И (р1 <= 15) И (р2 >= 0) И (р2 <= 15));
  Вывод1("%о%н%о",нкд);
  ЕСЛИ (нкд # TST) И (нкд # CMP) ТО
    Вывод1("%р,",рн)
  КОН;
  ЕСЛИ (нкд # MOV) И (нкд # MVN) ТО
    Вывод1("%р,",р1)
  КОН;
  Вывод1("%р",р2);
  ЕСЛИ сс # 0 ТО
    ЕСЛИ рс > 15 ТО (* непосредственный сдвиг *)
      УМЕНЬШИТЬ(рс,16);
      Вывод2(",%с ##%д",сс,рс)
    ИНАЧЕ
      Вывод2(",%с %р",сс,рс)
    КОН
  КОН;
  Вывод0("^");
  УвеличитьСК
КОН ОД;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ОД1-(нкд,рн,р1,пост:ЦЕЛ); 
(* Обработка Данных с непосредственным вторым данным *)
ПЕР
  р:ЦЕЛ;
УКАЗ
  ПРОВЕРИТЬ((рн >= 0) И (рн <= 15) И (р1 >= 0) И (р1 <= 15));
  ЕСЛИ (нкд = ADD) И (пост < 0) ТО
    нкд:=SUB;
    пост:=-пост
  АЕСЛИ (нкд = SUB) И (пост < 0) ТО
    нкд:=ADD;
    пост:=-пост
  КОН;
  ПроверитьЗаполнениеПост;
  ЕСЛИ ВычисляемаяПост(пост) ТО
    Вывод1("%о%н%о",нкд);
    ЕСЛИ (нкд # TST) И (нкд # CMP) ТО
      Вывод1("%р,",рн)
    КОН;
    ЕСЛИ (нкд # MOV) И (нкд # MVN) ТО
      Вывод1("%р,",р1)
    КОН;
    Вывод1("##%ш^",пост);
    УвеличитьСК
  ИНАЧЕ
    УМЕНЬШИТЬ(разрешёнСбросПост);
    Рег.Занять(р);
    ЗагрузитьПост(р,пост);
    ОД(нкд,рн,р1,р,0,0);
    Рег.Освободить(р);
    УВЕЛИЧИТЬ(разрешёнСбросПост)
  КОН
КОН ОД1;

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

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ВнешниеПер-;
УКАЗ
КОН ВнешниеПер;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Начало-;
(* начало области указаний задач *)
УКАЗ
  Вывод0("^; начало области указаний задач");
  Вывод0("^%оAREA%о|.text|,CODE^");
КОН Начало;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Открыть-(испСреда:КЛЮЧ);
(* испСреда=ВКЛ, если нужно использовать задачи отдела СРЕДА *)
ПЕР
  нвхотд:ЦЕЛ;
  понД:Данные.ДкВидуПонятие;
УКАЗ
  (* начальные значения *)
  СК:=0;
  словПост:=0;
  байтЦепочек:=0;
  удалениеПост:=-1;
  разрешёнСбросПост:=0;
  текМетка:=0;
  будетКУ:=AL;
  будетS:=ОТКЛ;
  Обмен.КодОткрыть;
  (* заголовок *)
  Вывод0("; Преобразователь Сокращенного Глагола в ARM код^");
  Вывод0("; Выпуск www.glagol.nad.ru от 11.09.2006^");
  Вывод0("; ***************************************************************^");
  (* используемые переменные и задачи *)
  Вывод0("^; используемые переменные и задачи^");
  ЕСЛИ испСреда ТО
    Вывод0("%оIMPORT%о|.СРЕДА.Делить|^");
    Вывод0("%оIMPORT%о|.СРЕДА.Остаток|^");
    Вывод0("%оIMPORT%о|.СРЕДА.Создать|^");
    Вывод0("%оIMPORT%о|.СРЕДА.Стоп|^")
  КОН;
  ОТ нвхотд:=0 ДО Данные.чвхотд-1 ВЫП
         понД:=Данные.вхотд[нвхотд].обл.первпон;
    ПОКА понД # ПУСТО ВЫП
      ЕСЛИ понД.родп В {Данные.пПер,Данные.пЗадача} ТО
        Вывод0("%оIMPORT%о");
        ВыводПолногоИмени(понД);
        Вывод0("^")
      КОН;
      понД:=понД.слеД
    КОН
  КОН;
  (* переименование регистра *)
  Вывод0("^; переименование регистра");
  Вывод0("^%оFP%оRN%оR12^");
  (* начало области переменных отдела *)
  Вывод0("^; начало области переменных отдела");
  Вывод0("^%оAREA%о|.bss|,NOINIT^")
КОН Открыть;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ЗапускПриложения-;
ПЕР
  нвхотд:ЦЕЛ;
  имя:Настрой.Имя;
  имягз:ЦЕПЬ[Настрой.рИмени*2+10];
УКАЗ
  ОТ нвхотд:=1 ДО Данные.чвхотд-1 ВЫП
    (* полное имя главной задачи *)
    имя:=Данные.вхотд[нвхотд].имя;
    имягз:="|.";
    оЦепи.ДобавитьВКонец(имягз,имя);
    оЦепи.ДобавитьВКонец(имягз,".");
    оЦепи.ДобавитьВКонец(имягз,имя);
    оЦепи.ДобавитьВКонец(имягз,"!|^");
    (* вызов *)
    Вывод0("%оIMPORT%о");
    Вывод0(имягз);
    Вывод0("%оBL%о");
    Вывод0(имягз)
  КОН
КОН ЗапускПриложения;

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

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Закрыть-;
ПЕР
  ц,поз:ЦЕЛ;
  понД:Данные.ДкВидуПонятие;
УКАЗ
  (* цепочки отдела на 0-ю метку *)
  Вывод0("^; цепочки отдела^");
  ПоставитьМетку(0);
  ц:=0;
  КОЛЬЦО
    ОТ поз:=0 ДО 15 ВЫП
      ЕСЛИ ц >= байтЦепочек ТО
        ВЫХОД
      КОН;
      ЕСЛИ поз = 0 ТО
        Вывод1('^%оDCB%о%з',ВЦЕЛ(цепочки[ц]))
      ИНАЧЕ
        Вывод1(',%з',ВЦЕЛ(цепочки[ц]))
      КОН;
      УВЕЛИЧИТЬ(ц)
    КОН
  КОН;
  Вывод0("^");
  (* общедоступные понятия *)
  Вывод0("^; общедоступные понятия^");
       понД:=Данные.текОбласть.первпон;
  ПОКА понД # ПУСТО ВЫП
    ЕСЛИ Данные.прОбщедоступное В понД.признаки ТО
      ЕСЛИ понД.родп В {Данные.пПер,Данные.пЗадача} ТО
        Вывод0("%оEXPORT%о");
        ВыводПолногоИмени(понД);
        ЕСЛИ понД.родп = Данные.пПер ТО
          Вывод0("%о[DATA]")
        КОН;
        Вывод0("^")
      КОН
    КОН;
    понД:=понД.слеД
  КОН;
                              (*  в с ё  конец *)
  Вывод0("^%оEND^");
  Обмен.КодЗакрыть
КОН Закрыть;

КОН Код.
