(*~\Глагол\ПриложенияLink\ПГ\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(**)                              ОТДЕЛ КУ;
(*============================================================================*)
(* НАЗНАЧЕНИЕ: Код Указаний                                                   *)
(*============================================================================*)

ИСПОЛЬЗУЕТ 
        (*  \Глагол\              *)
 оЦепи    ИЗ "..\..\Отделы\Иное\",

  ВД,ЗК,НП,СК,Coff,МР,СС,ПЗ;

ПОСТ
                    (*      Род понятий (нПонятие.родп). Из ВД. *)
  пОтдел     =0;
  пОбласть   =1;
  пВид       =2;
  пПост      =3;
  пПер       =4;
  пПрСсылки  =5;
  пЗадача    =6;
  пВстрЗадача=7;
  пСвойство  =8;
(*
  родп       | n адр   пост    след     область
  ============================================================================
  пОтдел     | 0                        верх    Отдел
  пОбласть   | 1 нстр                   первпер Область действия
  пВид       | 2                                Именованный вид
  пПост      | 3       val                      Постоянная
  пПер       | 4 адр           next             Переменная или приёмник значения
  пПрСсылки  | 5 vadr          next             Приемник переменной
  пЗадача    | 6 сно   sizes   firstpar область Задача
  пВстрЗадача| 7 fno   sizes                    Встроенная задача
  пСвойство  | 8 off           next             Свойство набора

  <сно> является номером в символьной таблице COFF (если <сно> <= 0, то это - адр для связки заготовок)
*)

                    (* Признаки понятия (нПонятие.признаки). Из ВД. *)
  прОбщедоступная=0;
  прНеизменяемая =1;
  прОбъявлена    =2;
  прВложенная    =3;
  прГоловная     =4;
  прПередаваемая =5;
(*
  прОбщедоступная- действует во всех отделах
  прНеизменяемая - только для чтения
  прОбъявлена    - для полностью объявленных задач
  прВложенная    - для вложенных задач
  прГоловная     - для задачи _Zapusk 
  прПередаваемая - для иноязычных приложений
*)

  (*                        Род видов (нВид.родв). Из ВД.
 Причём:
          вЯчейка <= вЦел8 <= вЗнак <= вЦел16 <= вЦел32 <= вЦел64.
   *)
  вНеопр  =0;
  вЯчейка =1;
  вКлюч   =2;
  вЗнак   =3;
  вЦел8   =4;
  вЦел16  =5;
  вЦел32  =6;
  вЦел64  =7;
  вВещ32  =8;
  вВещ64  =9;
  вМнож   =10;
  вПЦепь  =11;
  вПусто  =12;
  вНет    =13;
  вДоступ =14;
  вЗадача =15;
  вБегунок=16;
  вРяд    =17;
  вОРяд   =18;
  вНабор  =19;
  вКон    =20; (* вКон для ДВ. При изменении вКон нужно 3 преобразования с уборка:=ОТКЛ. *)
(*
  родв    | n          овид      след     вхнотд  адрОВ    текстп
  ===============================================================
  вНеопр  | 0
  вЯчейка | 1
  вКлюч   | 2
  вЗнак   | 3
  вЦел8   | 4
  вЦел16  | 5
  вЦел32  | 6
  вЦел64  | 7
  вВещ32  | 8
  вВещ64  | 9
  вМнож   | 10
  вПЦепь  | 11
  вПусто  | 12
  вНет    | 13
  вДоступ | 14         PBaseTyp           вхнотд           текстп
  вЗадача | 15         ResTyp    params   вхнотд           текстп
  вБегунок| 16 шаг     основание          вхнотд  адрОВ    текстп
  вРяд    | 17 nofel   ElemTyp            вхнотд           текстп
  вОРяд   | 18 dim     ElemTyp            вхнотд  lenoff   текстп
  вНабор  | 19         RBaseTyp  fields   вхнотд  адрОВ    текстп
*)

  множЦел={вЦел8..вЦел64};
  множВещ={вВещ32,вВещ64};

      (*
         Способы адресации 80386 (нItem.тип). Не должны пересекаться с
                  номерами ВД.Понятие.родп. Из ЗК.
       *)
  DArr   =16;
  Coc    =17;
  Stk    =18;
  FStk   =19;     (* real on floating-point-stack   *)
  Reg    =20;     (*      bas(+inx*2^32)            *)
  Abs    =21;     (* [адр                         ] *)
  RegI   =22;     (* [    bas+          disp      ] *)
  RegX   =23;     (* [    bas+inx*2^адр+disp      ] *)
  Inx    =24;     (* [        inx*2^адр+disp      ] *)
  AbsRel =25;     (* [адр+                   reloc] *)
  RegIRel=26;     (* [    bas+          disp+reloc] *)
  RegXRel=27;     (* [    bas+inx*2^адр+disp+reloc] *)
  InxRel =28;     (* [        inx*2^адр+disp+reloc] *)

           (* Условия (cc) 80386. Из ЗК. *)
  NOV   =1;
  CST   =2;
  CCL   =3;
  EQL   =4;
  NEQ   =5;
  LSS   =12;
  GEQ   =13;
  LEQ   =14;
  GTR   =15;
  ULSS  =2;
  UGEQ  =3;
  ULEQ  =6;
  UGTR  =7;
  ALWAYS=16;
  NEVER =17;

        (* названия 32-х разрядных регистров
                                 процессора i386 М и их машинные коды. Из МР. *)
  EAX=0;  (* арифметический *)
  ECX=1;  (* арифметический *)
  EDX=2;  (* арифметический *)
  EBX=3;  (* арифметический *)

  ESP=4;
  EBP=5;
  ESI=6;  (* индексный *)
  EDI=7;  (* индексный *)

                          (* Программные ловушки (аварийные остановы). Из СК. *)
  пределыАвОст=1;
    номерАвОст=2;
    арифмАвОст=3;
   охранаАвОст=4;
    пустоАвОст=5;
      дляАвОст=6;
  выбратьАвОст=7;
    ответАвОст=8;
проверитьАвОст=9;
     нольАвОст=10;
  бегунокАвОст=11;
                        (* Номера задач ОБХОД отдела (нУзел.подроду). Из ПД. *)
  зПолучитьАдрес=23;
  зИзПамяти     =24;
  зВПамять      =25;
  зЗначение     =26;
  зОбраз        =27;

ВИД
                     (* сохраненных рабочие греги при вызовах задач с ответом *)
  ДкСохрРеги=ДОСТУП К (*нСохрРеги;
                        нСохрРеги =*) НАБОР
    греги:МР.НаборГРегов;
     пред:ДкСохрРеги            (* для построения стопки из вложенных вызовов *)
                                      КОН;
ПЕР
  сохрРегиД:ДкСохрРеги;                        (* стопка из вложенных вызовов *)


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Field-(       x+:ЗК.нItem;
              смещение :ЦЕЛ);
(*
 *  Цель: свойство набора
 *    До: x.тип В {пПрСсылки,пПер,Abs,RegI,RegX,Inx}
 * После: x.тип В {Abs,RegI,RegX,Inx}
 *)
УКАЗ
  СК.LoadAdr(x);
  СК.IncAdr(x,смещение)
КОН Field;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА LoadTypDescAdr(вид:ВД.ДкВиду;
                       x+:ЗК.нItem);
(*
 *  Цель: загрузить адрес описателя вида
 *    До: <вид> содержит вид данных
 * После: <x> содержит адрес ОВ
 *)
УКАЗ
  ПРОВЕРИТЬ((вид.вхнОтд >= 0) И (вид.вхнОтд < ВД.чВхОтд));
  x.тип:=AbsRel;
  x.адр:=вид.адрОВ;
  x.reloc:=Coff.СКР_ПОСТ;
  x.relocInx:=вид.вхнОтд
КОН LoadTypDescAdr;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(* 64 *)
ЗАДАЧА Convert-(x+:ЗК.нItem; нв:ЦЕЛ);
(*
 *  Цель: convertes the value of 'x' to new type 'нв'
 *    До: x = value to be converted
 *        нв = новый род вида
 * После: x.тип В {FStk,Reg}
 *)
ПЕР
  св:ЦЕЛ;
УКАЗ
  св:=x.вид.родв;
  ЕСЛИ  нв В множВещ ТО
    СК.ValToFStk(x)
  АЕСЛИ св В множВещ ТО
    СК.RealToInt(x,нв = вЦел64)
  ИНАЧЕ
    СК.ValToReg(x);
    ЕСЛИ  (св = вЦел64) И (нв # вЦел64) ТО
      ЕСЛИ НП.клПровПределов ТО
        СК.CheckRange(x,нв)
      КОН;
      МР.ОсвободитьРег(x.inx)
    АЕСЛИ (св = вЦел32) И (нв = вЦел16) ТО
      ЕСЛИ НП.клПровПределов ТО
        СК.CheckRange(x,нв)
      КОН
    АЕСЛИ (св = вЦел16) И (нв = вЦел8) ТО
      ЕСЛИ НП.клПровПределов ТО
        СК.CheckRange(x,нв)
      КОН
    АЕСЛИ (св # вЦел64) И (нв = вЦел64) ТО
      x.inx:=МР.ЗанятьОпредРег({EDX});
      МР.РегВОпредМРег(x.bas,EAX);
      ЗК.PutO(099H); (* CDQ *)
      МР.УстДопМРеги(x.bas,МР.МРеги);
      МР.УстДопМРеги(x.inx,МР.МРеги)
    КОН
  КОН
КОН Convert;


(*=============== mono operations ======================*)


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Элемент-(x+:ЗК.нItem);
(*
 *  Цель: returns a set СС.в which the element 'x' является set
 *    До: x = element to be set
 * После: x = set, with element 'x' set
 *)
ПЕР
  y:ЗК.нItem;
УКАЗ
  ЕСЛИ x.тип = пПост ТО
    x.тип:=Reg;
    x.bas:=МР.ЗанятьРег();
    СК.ClearReg(x.bas);
    ЗК.PutOMD(1,0FBAH,5H,x,x.адр) (* BTS Ed,Ib *)
  ИНАЧЕ
    Convert(x,вМнож);
    y.тип:=Reg;
    y.bas:=МР.ЗанятьРег();
    СК.ClearReg(y.bas);
    ЗК.PutORM(0FABH,x.bas,y); (* BTS Ed,Gd *)
    МР.ОсвободитьРег(x.bas);
    x.bas:=y.bas
  КОН
КОН Элемент;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       SetRange-(x+,y+,z+:ЗК.нItem);
(*
 *  Цель: returns set 'x' СС.в which elements 'y'..'z' are set
 *    До: y..z = range of elements to be set
 * После: x:={y..z}
 *)
ПЕР
  L1,L2:ЗК.Label;
УКАЗ
  x.тип:=Reg;
  x.bas:=МР.ЗанятьРег();
  СК.ClearReg(x.bas);
  Convert(y,вМнож);
  Convert(z,вМнож);
  L1:=0;
  L2:=ЗК.pc;
  ЗК.PutORM(039H,y.bas,z); (* CMP Ed,Gd *)
  ЗК.PutJmpCF(LSS,L1);
  ЗК.PutORM(0FABH,y.bas,x); (* BTS Ed,Gd *)
  ЗК.PutOM(0FFH,0H,y); (* INC Ed *)
  ЗК.PutJmpB(L2);
  ЗК.FixLink(L1)
КОН SetRange;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       Neg-(x+:ЗК.нItem);
(* 
 *  Цель: returns negated value of x
 *    До: x.вид.родв В {вМнож,множЦел,множВещ}
 * После: x:=-x
 *)
ПЕР
  f:ЦЕЛ;
  h:ЗК.нItem;
УКАЗ
  f:=x.вид.родв;
  ЕСЛИ f = вМнож ТО
    СК.ValToReg(x);
    ЗК.PutOM(0F7H,2H,x) (* NOT Ed *)
  АЕСЛИ f = вЦел64 ТО
    СК.ValToReg(x);
    h.тип:=Reg;
    h.bas:=x.inx;
    ЗК.PutOM(0F7H,2H,h);       (* NOT Ed *)
    ЗК.PutOM(0F7H,3H,x);       (* NEG Ed *)
    ЗК.PutOMD(1,083H,3H,h,-1); (* SBB Ed,Id *)
    СК.CheckOvfl
  АЕСЛИ f В множЦел ТО
    СК.ValToReg(x);
    ЗК.PutOM(0F7H,3H,x); (* NEG Ed *)
    СК.CheckOvfl
  ИНАЧЕ (* f В множВещ *)
    СК.ValToFStk(x);
    ЗК.PutO(0D9E0H) (* FCHS *)
  КОН
КОН Neg;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Not-(x+:ЗК.нItem);
(*
 *  Цель: returns inverted value of x
 *    До: x = condition code СС.или boolean value
 * После: x:= ~x // логическое отрицание
 *)
ПЕР
  h:ЦЕЛ;
УКАЗ
  ЕСЛИ x.тип = Coc ТО
    x.reloc:=СК.InvertedCoc(x.reloc);
    h:=x.адр; x.адр:=x.disp; x.disp:=h (* exchange Tjmp СС.и Fjmp *)
  ИНАЧЕ
    СК.ValToReg(x);
    ЗК.PutOMD(4,081H,6H,x,1) (* XOR Ed,Id *)
  КОН
КОН Not;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       AbsVal-(x+:ЗК.нItem);
(*
 *  Цель: returns the absolute value of x
 *    До: x.вид.родв В {множЦел,множВещ}
 * После: x:=|x|
 *)
ПЕР
  L1:ЗК.Label;
  h:ЗК.нItem;
УКАЗ
  ЕСЛИ x.вид.родв = вЦел64 ТО
    СК.ValToReg(x);
    h.тип:=Reg;
    h.bas:=x.inx;
    ЗК.PutORM(85H,h.bas,h); (* TEST Ed,Gd *)
    L1:=0;
    ЗК.PutJmpCF(GEQ,L1);
    ЗК.PutOM(0F7H,2H,h);       (* NOT Ed *)
    ЗК.PutOM(0F7H,3H,x);       (* NEG Ed *)
    ЗК.PutOMD(1,083H,3H,h,-1); (* SBB Ed,Id *)
    СК.CheckOvfl;
    ЗК.FixLink(L1)
  АЕСЛИ x.вид.родв В множЦел ТО
    СК.ValToReg(x);
    ЗК.PutORM(85H,x.bas,x); (* TEST Ed,Gd *)
    L1:=0;
    ЗК.PutJmpCF(GEQ,L1);
    ЗК.PutOM(0F7H,3H,x); (* NEG Ed *)
    СК.CheckOvfl;
    ЗК.FixLink(L1)
  ИНАЧЕ (* x.вид.родв В множВещ *)
    СК.ValToFStk(x);
    ЗК.PutO(0D9E1H) (* FABS *)
  КОН
КОН AbsVal;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Длина-(x+:ЗК.нItem);                 (*  Цель: x:=длина цепочки знаков *)
ПЕР
  дл,cx,ax:ЗК.нItem;
  L1:ЗК.Label;
УКАЗ
  L1:=0;
  cx.тип:=Reg;
  cx.bas:=МР.ЗанятьОпредРег({ECX});
  ax.тип:=Reg;
  ax.bas:=МР.ЗанятьОпредРег({EAX});
  СК.LoadSize(x,дл);
  СК.ValToReg(дл);
  ЗК.PutOMD(1,0C1H,7H,дл,1); (* SAR Ed,Ib *)
  СК.IgnoreDynArrDesc(x);
  СК.AdrToRegIDisp0(x,EDI);

  ЗК.PutORM(08BH,cx.bas,дл); (* MOV Gd,Ed    MOV ECX,дл  *)
  ЗК.PutORM(031H,ax.bas,ax); (* XOR Ed,Gd    XOR EAX,EAX *)  
  ЗК.Put2;                   (* d -> w *)
  ЗК.PutO(0F2AFH);           (* REPNE SCASD              *)
  ЗК.PutJmpCF(NEQ,L1);       (* JNE L1                   *)
  ЗК.PutOM(0FFH,1H,дл);      (* DEC Ed       DEC дл      *)
  ЗК.FixLink(L1);            (* L1:                      *)
  ЗК.PutORM(029H,cx.bas,дл); (* SUB Ed,Gd    SUB дл,ECX  *)

  ЗК.Release(ax);
  ЗК.Release(cx);
  ЗК.Release(x);
  x.тип:=Reg;
  x.bas:=дл.bas;
  x.вид:=ВД.цел32вид
КОН Длина;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Odd-(x+:ЗК.нItem);
(*
 *  Цель: проверка: x чет или чет
 *    До: x - проверяемая величина
 * После: x:=ЧЕТ(x)
 *)
УКАЗ
  СК.LoadAdr(x);
  ЕСЛИ x.тип = Reg ТО
    ЗК.PutOMD(4,0F7H,0H,x,1) (* TEST Id,Ed *)
  ИНАЧЕ
    ЗК.PutOMD(1,0F6H,0H,x,1) (* TEST Ib,Eb *)
  КОН;
  ЗК.Release(x);
  СК.SetCoc(x,EQL)
КОН Odd;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Стоп-(x+:ЗК.нItem);
(*
 *  Цель: выход из приложения
 *    До: x = возвращаемый код (x.вид.родв=вЦел32)
 *)
УКАЗ
  СК.ValToReg(x);
  МР.РегВОпредМРег(x.bas,EAX);
  ЗК.PutCall(Coff.rtsStop);
  ЗК.Release(x)
КОН Стоп;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       TypTest-(    x0+:ЗК.нItem;
                testtyp:ВД.ДкВиду;
            guard,equal:КЛЮЧ
               );
(*
 *  Цель: generate code for type test ('x' вида 'testtyp')
 *    До: x0.тип В {пПер,пПрСсылки,RegI,RegX,Abs,... }
 *        x0.вид В {ДОСТУП К вНабор,вНабор}
 *        testtyp:test type
 *        guard = охрана с ловушкой
 *        equal = 'x0' должен быть точно вида 'testtyp' (не расширением)
 *        (guard,equal) В { (T,T),(T,F),(F,F) }
 * После: 'x0' unchanged if 'guard' = TRUE
 *)
ПЕР
  x,tagItem:ЗК.нItem;
  L1:ЗК.Label;
УКАЗ
  ЗК.CopyItem(x0,x);
  ЕСЛИ guard И equal ТО
    ЕСЛИ x.тип = пПрСсылки ТО     (* пПрСсылки *)
      СК.LoadBaseAdr(x)           (* pointer to type-tag *)
    ИНАЧЕ                         (* ДОСТУП К вНабор *)
      СК.IncAdr(x,-4)             (* pointer to type-tag *)
    КОН;
    LoadTypDescAdr(testtyp,tagItem);
    СК.CmpAdr(x,tagItem);
    ЗК.Release(tagItem);
    L1:=0;
    ЗК.PutJmpCF(EQL,L1);
    ЗК.Ловушка(охранаАвОст);
    ЗК.FixLink(L1)
  ИНАЧЕ                             (* equal = FALSE *)
    ЕСЛИ testtyp.родв = вНабор ТО   (* пПрСсылки *)
      СК.LoadBaseAdr(x);            (* pointer to type-tag *)
      СК.DeRef(x)                   (* pointer to type-descriptor *)
    ИНАЧЕ                           (* вДоступ to вНабор *)
      testtyp:=testtyp.овид;
      СК.DeRef(x);                  (* pointer to object *)
      СК.IncAdr(x,-4);              (* pointer to type-tag of object *)
      СК.DeRef(x)                   (* pointer to type-descriptor of object *)
    КОН;
    СК.IncAdr(x,4*testtyp.колено);
    LoadTypDescAdr(testtyp,tagItem);
    СК.CmpAdr(x,tagItem);
    ЗК.Release(tagItem);
    ЕСЛИ guard ТО
      L1:=0;
      ЗК.PutJmpCF(EQL,L1);
      ЗК.Ловушка(охранаАвОст);
      ЗК.FixLink(L1)
    ИНАЧЕ
      ЗК.Release(x0);
      СК.SetCoc(x0,EQL)
    КОН
  КОН;
  ЗК.Release(x)
КОН TypTest;


(*===================================== double operations ====================*)


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       Add-(   x+,y+:ЗК.нItem;
            floating:КЛЮЧ);
(*
 *  Цель:  computes the addition of 'x' СС.и 'y'
 *    До: x, y = values to be added
 *         IF floating THEN floating point ELSE integer END addition
 * После: x:=x+y
 *)
ПЕР
  h:ЗК.нItem;
УКАЗ
  ЕСЛИ floating ТО
    СК.ValToFStk(x);
    СК.ValToFStk(y);
    МР.УмМатМРегов;
    ЗК.PutO(0DEC1H) (* FADDP ST(1),ST *)
  ИНАЧЕ
    ЕСЛИ x.тип = пПост ТО h:=x; x:=y; y:=h КОН;
    СК.ValToReg(x);
    ЕСЛИ y.тип = пПост ТО
      ЕСЛИ (y.адр = 1) И (x.вид.родв # вЦел64) ТО
        ЗК.PutOM(0FFH,0H,x) (* INC Ed *)
      ИНАЧЕ
        ЗК.PutOMD(4,081H,0H,x,y.адр); (* ADD Ed,Id *)
        ЕСЛИ x.вид.родв = вЦел64 ТО
          h.тип:=Reg;
          h.bas:=x.inx;
          ЗК.PutOMD(4,081H,2H,h,y.disp) (* ADC Ed,Id *)
        КОН
      КОН
    ИНАЧЕ
      ЕСЛИ (y.вид.родв = вЦел32) ИЛИ (y.вид.родв = вЦел64) ТО
        СК.LoadAdr(y)
      ИНАЧЕ
        СК.ValToReg(y)
      КОН;
      ЗК.PutORM(03H,x.bas,y); (* ADD Gd,Ed *)
      ЕСЛИ y.вид.родв = вЦел64 ТО
        ЕСЛИ y.тип = Reg ТО
          h.тип:=Reg;
          h.bas:=y.inx
        ИНАЧЕ
          h:=y;
          СК.IncAdr(h,4)
        КОН;
        ЗК.PutORM(13H,x.inx,h) (* ADC Gd,Ed *)
      КОН
    КОН;
    СК.CheckOvfl
  КОН
КОН Add;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       Sub-(x+,y+:ЗК.нItem; floating:КЛЮЧ);
(*
 *  Цель: computes the subtraction of 'y' from 'x'
 *    До: x,y = values                                              
 *        IF floating THEN floating point ELSE integer END subtraction
 * После: x:=x-y
 *)
ПЕР
  reverse:КЛЮЧ;
  h:ЗК.нItem;
УКАЗ
  ЕСЛИ floating ТО
    reverse:=(y.тип = FStk) И (x.тип # FStk);
    СК.ValToFStk(x);
    СК.ValToFStk(y);
    МР.УмМатМРегов;
    ЕСЛИ reverse ТО
      ЗК.PutO(0DEE1H) (* FSUBRP ST(1),ST *)
    ИНАЧЕ
      ЗК.PutO(0DEE9H) (* FSUBP ST(1),ST *)
    КОН
  ИНАЧЕ
    СК.ValToReg(x);
    ЕСЛИ y.тип = пПост ТО
      ЕСЛИ y.адр = 1 ТО
        ЗК.PutOM(0FFH,1H,x); (* DEC Ed *)
        ЕСЛИ x.вид.родв = вЦел64 ТО
          h.тип:=Reg;
          h.bas:=x.inx;
          ЗК.PutOMD(1,083H,3H,h,0) (* SBB Ed,Id *)
        КОН
      ИНАЧЕ
        ЗК.PutOMD(4,081H,5H,x,y.адр); (* SUB Ed,Id *)
        ЕСЛИ x.вид.родв = вЦел64 ТО
          h.тип:=Reg;
          h.bas:=x.inx;
          ЗК.PutOMD(4,081H,3H,h,y.disp) (* SBB Ed,Id *)
        КОН
      КОН
    ИНАЧЕ
      ЕСЛИ (y.вид.родв = вЦел32) ИЛИ (y.вид.родв = вЦел64) ТО
        СК.LoadAdr(y)
      ИНАЧЕ
        СК.ValToReg(y)
      КОН;
      ЗК.PutORM(02BH,x.bas,y); (* SUB Gd,Ed *)
      ЕСЛИ y.вид.родв = вЦел64 ТО
        ЕСЛИ y.тип = Reg ТО
          h.тип:=Reg;
          h.bas:=y.inx
        ИНАЧЕ
          h:=y;
          СК.IncAdr(h,4)
        КОН;
        ЗК.PutORM(01BH,x.inx,h) (* SBB Gd,Ed *)
      КОН
    КОН;
    СК.CheckOvfl
  КОН
КОН Sub;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       Increment-(x+,y+:ЗК.нItem; decrement:КЛЮЧ);
(*
 *  Цель: increments или decrements 'x' by value of 'y'
 *    До: x = variable to be changed
 *        y = value to be added или subtracted
 * После: IF decrement THEN x:=x-y ELSE x:=x+y END
 *)
ПЕР
  размер:ЦЕЛ;
  h:ЗК.нItem;
УКАЗ
  СК.LoadAdr(x);
  размер:=x.вид.размер;
  ПРОВЕРИТЬ(x.тип # Reg);
  ЕСЛИ decrement ТО
    ЕСЛИ y.тип = пПост ТО
      ЕСЛИ y.адр = 1 ТО
        ЕСЛИ размер = 1 ТО
          ЗК.PutOM(0FEH,1H,x)  (* DEC Eb *)
        АЕСЛИ размер = 2 ТО
          ЗК.Put2;             (* d -> w *)
          ЗК.PutOM(0FFH,1H,x)  (* DEC Ed *)
        АЕСЛИ размер = 4 ТО
          ЗК.PutOM(0FFH,1H,x)  (* DEC Ed *)
        АЕСЛИ размер = 8 ТО
          ЗК.PutOMD(1,083H,5H,x,1); (* SUB Ed,Id *)
          h:=x;
          СК.IncAdr(h,4);
          ЗК.PutOMD(1,083H,3H,h,0)  (* SBB Ed,Id *)
        КОН
      ИНАЧЕ
        ЕСЛИ размер = 1 ТО
          ЗК.PutOMD(1,080H,5H,x,y.адр)  (* SUB Eb,Ib *)
        АЕСЛИ размер = 2 ТО
          ЗК.PutOMD(2,081H,5H,x,y.адр)  (* SUB Ew,Iw *)
        ИНАЧЕ
          ЗК.PutOMD(4,081H,5H,x,y.адр); (* SUB Ed,Id *)
          ЕСЛИ размер = 8 ТО
            h:=x;
            СК.IncAdr(h,4);
            ЗК.PutOMD(4,081H,3H,h,y.disp) (* SBB Ed,Id *)
          КОН
        КОН
      КОН
    ИНАЧЕ
      СК.ValToReg(y);
      ЕСЛИ размер = 1 ТО
        МР.РегВоЯчМРег(y.bas);
        ЗК.PutORM(028H,y.bas,x)  (* SUB Eb,Gb *)
      ИНАЧЕ
        ЕСЛИ размер = 2 ТО
          ЗК.Put2              (* d -> w *)
        КОН;
        ЗК.PutORM(029H,y.bas,x); (* SUB Ed,Gd *)
        ЕСЛИ размер = 8 ТО
          h:=x;
          СК.IncAdr(h,4);
          ЗК.PutORM(019H,y.inx,h) (* SBB Gd,Ed *)
        КОН
      КОН
    КОН
  ИНАЧЕ
    ЕСЛИ y.тип = пПост ТО
      ЕСЛИ y.адр = 1 ТО
        ЕСЛИ размер = 1 ТО
          ЗК.PutOM(0FEH,0H,x)  (* INC Eb *)
        АЕСЛИ размер = 2 ТО
          ЗК.Put2;           (* d -> w *)
          ЗК.PutOM(0FFH,0H,x)  (* INC Ed *)
        АЕСЛИ размер = 4 ТО
          ЗК.PutOM(0FFH,0H,x)  (* INC Ed *)
        АЕСЛИ размер = 8 ТО
          ЗК.PutOMD(1,083H,0H,x,1); (* ADD Ed,Id *)
          h:=x;
          СК.IncAdr(h,4);
          ЗК.PutOMD(1,083H,2H,h,0)  (* ADC Ed,Id *)
        КОН
      ИНАЧЕ
        ЕСЛИ размер = 1 ТО
          ЗК.PutOMD(1,080H,0H,x,y.адр)  (* ADD Eb,Ib *)
        АЕСЛИ размер = 2 ТО
          ЗК.PutOMD(2,081H,0H,x,y.адр)  (* ADD Ew,Iw *)
        ИНАЧЕ
          ЗК.PutOMD(4,081H,0H,x,y.адр); (* ADD Ed,Id *)
          ЕСЛИ размер = 8 ТО
            h:=x;
            СК.IncAdr(h,4);
            ЗК.PutOMD(4,081H,2H,h,y.disp) (* ADC Ed,Id *)
          КОН
        КОН
      КОН
    ИНАЧЕ
      СК.ValToReg(y);
      ЕСЛИ размер = 1 ТО
        МР.РегВоЯчМРег(y.bas);
        ЗК.PutORM(00H,y.bas,x)  (* ADD Eb,Gb *)
      ИНАЧЕ
        ЕСЛИ размер = 2 ТО
          ЗК.Put2             (* d -> w *)
        КОН;
        ЗК.PutORM(01H,y.bas,x); (* ADD Ed,Gd *)
        ЕСЛИ размер = 8 ТО
          h:=x;
          СК.IncAdr(h,4);
          ЗК.PutORM(011H,y.inx,h) (* ADC Gd,Ed *)
        КОН
      КОН
    КОН
  КОН;
  СК.CheckOvfl
КОН Increment;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Поставить-(б+,р+,н+:ЗК.нItem);
(*
 *  Цель: поставить бегунок 'б' на переменную из ряда 'р' с номером 'н'
 * После: б+0: адр(р)+размер(р[])*н - текущее положение бегунка
 *        б+4: адр(р)               - начало ряда
 *        б+8: адр(р)+размер(р)     - конец ряда
 *)
ПЕР
  n:ЦЕЛ;      (* переменных в ряду *)
  размер:ЦЕЛ; (* размер переменной из ряда *)
  вид:ВД.ДкВиду;
УКАЗ
  вид:=р.вид;
  n:=1;
  ПОВТОРЯТЬ
    n:=вид.n*n;
    вид:=вид.овид
  ДО вид.родв # вРяд;
  размер:=вид.размер;

  СК.LoadAdr(б);
  СК.AdrToRegI(р);
  (* р.тип = RegI *)
  ЕСЛИ НП.клПровБегунка ТО
    (* нач *)
    СК.IncAdr(б,4);
    СК.AdrToRegIDisp0(р,-1);
    ЗК.PutORM(089H,р.bas,б); (* MOV Ed,Gd *)
    (* кон *)
    СК.IncAdr(б,4);
    СК.IncAdr(р, n*размер);
    СК.AdrToRegIDisp0(р,-1);
    ЗК.PutORM(089H,р.bas,б); (* MOV Ed,Gd *)
    (* возвращаем в 'р' адр. начала ряда *)
    СК.IncAdr(р,-n*размер); 
    (* возвращаем 'б' на тек. *)
    СК.IncAdr(б,-8)
  КОН;
  (* тек *)
  ЕСЛИ н.тип = пПост ТО
    СК.IncAdr(р,н.адр*размер)
  ИНАЧЕ
    СК.ValToReg(н);
    ЕСЛИ размер # 1 ТО
      ЗК.PutIMUL3(н.bas,н,размер) (* IMUL Gd,Ed,Id *)
    КОН;
    ЗК.PutORM(03H,р.bas,н)  (* ADD r32,r/m32 *)
  КОН;
  СК.AdrToRegIDisp0(р,-1);
  ЗК.PutORM(089H,р.bas,б)  (* MOV Ed,Gd *)
КОН Поставить;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Пропустить-(б+,п+:ЗК.нItem);
(*  Цель: увеличить текущее значение бегунка 'б' на 'п' переменных ряда *)
УКАЗ
  СК.LoadAdr(б);
  ЗК.PutOMD(4,081H,0H,б,п.адр*б.вид.овид.размер)  (* ADD Ed,Id *)
КОН Пропустить;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       Mul-(x+,y+:ЗК.нItem; floating:КЛЮЧ);
(*
 *  Цель: computes the multiplication of 'y' with 'x'
 *    До: x,y = values
 *        IF floating THEN floating point ELSE integer END multiplication
 * После: x:=x*y
 *)
ПЕР
  h:ЗК.нItem;
УКАЗ
  ЕСЛИ floating ТО
    СК.ValToFStk(x);
    СК.ValToFStk(y);
    МР.УмМатМРегов;
    ЗК.PutO(0DEC9H) (* FMULP ST(1),ST *)
  ИНАЧЕ
    ЕСЛИ x.тип = пПост ТО h:=x; x:=y; y:=h КОН;
    СК.ValToReg(x);
    ЕСЛИ y.вид.родв = вЦел64 ТО
      МР.РегВОпредМРег(x.bas,EAX);
      МР.РегВОпредМРег(x.inx,EDX);
      СК.ValToReg(y);
      МР.РегВОпредМРег(y.bas,ECX);
      МР.РегВОпредМРег(y.inx,EBX);
      ЗК.PutCall(Coff.rtsLMulInx);
      МР.РегВоМРег(x.bas);
      МР.РегВоМРег(x.inx);
      МР.РегВоМРег(y.bas);
      МР.РегВоМРег(y.inx);
    ИНАЧЕ
      ЕСЛИ y.тип # пПост ТО
        ЕСЛИ y.вид.родв = вЦел32 ТО
          СК.LoadAdr(y)
        ИНАЧЕ
          СК.ValToReg(y)
        КОН;
        ЗК.PutORM(0FAFH,x.bas,y) (* IMUL Gd,Ed *)
      АЕСЛИ y.адр # 1 ТО (* y.тип = пПост *)
        ЗК.PutIMUL3(x.bas,x,y.адр) (* IMUL Gd,Ed,Id *)
      КОН
    КОН;
    СК.CheckOvfl
  КОН
КОН Mul;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
        FloatDiv-(x+,y+:ЗК.нItem);
(*
 *  Цель: computes the division of 'x' by 'y'
 *    До: x,y = values
 *        IF floating THEN floating point ELSE integer END division
 * После: x:=x/y
 *)
ПЕР
  reverse:КЛЮЧ;
УКАЗ
  reverse:=(y.тип = FStk) И (x.тип # FStk);
  СК.ValToFStk(x);
  СК.ValToFStk(y);
  МР.УмМатМРегов;
  ЕСЛИ reverse ТО
    ЗК.PutO(0DEF1H) (* FDIVRP ST(1),ST *)
  ИНАЧЕ
    ЗК.PutO(0DEF9H) (* FDIVP ST(1),ST *)
  КОН
КОН FloatDiv;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       DivMod-(x+,y+:ЗК.нItem; div:КЛЮЧ);
(*
 *  Цель: вычисляет <x> ДЕЛИТЬ <y> или <x> ОСТАТОК <y>
 *    До: <div> = ВКЛ, => ДЕЛИТЬ
 * После: <x> = ответ, <y> = мусор
 *)
ПЕР
  h,l,regD:ЗК.нItem;
  L1,L2:ЗК.Label;
УКАЗ
  ЕСЛИ y.вид.родв = вЦел64 ТО
    СК.ValToReg(y);
    ЕСЛИ НП.клПровНуля ТО
      h.тип:=Reg;
      h.bas:=y.inx;
      l.тип:=Reg;
      l.bas:=МР.ЗанятьРег();
      ЗК.PutORM(08BH,l.bas,y); (* MOV Gd,Ed *)
      ЗК.PutORM(0BH,l.bas,h);  (* OR Gd,Ed *)
      ЗК.Release(l);
      L1:=0;
      ЗК.PutJmpCF(NEQ,L1); (* jump if no zero *)
      ЗК.Ловушка(нольАвОст);
      ЗК.FixLink(L1)
    КОН;
    МР.РегВОпредМРег(y.bas,ECX);
    МР.РегВОпредМРег(y.inx,EBX);
    СК.ValToReg(x);
    МР.РегВОпредМРег(x.bas,EAX);
    МР.РегВОпредМРег(x.inx,EDX);
    ЗК.PutCall(Coff.rtsLDivModInx);
    МР.РегВоМРег(x.bas);
    МР.РегВоМРег(x.inx);
    МР.РегВоМРег(y.bas);
    МР.РегВоМРег(y.inx);
    ЕСЛИ НЕ div ТО
      ЗК.Release(x);
      x:=y;
      y.тип:=0
    КОН
  ИНАЧЕ
    СК.ValToReg(x);
    МР.РегВОпредМРег(x.bas,EAX);
    regD.тип:=Reg;
    regD.bas:=МР.ЗанятьОпредРег({EDX});
    ЕСЛИ (y.тип # пПост) И (y.вид.родв = вЦел32) ТО
      СК.LoadAdr(y)
    ИНАЧЕ
      СК.ValToReg(y)
    КОН;
    ЕСЛИ НП.клПровНуля ТО
      l.тип:=Reg;
      l.bas:=МР.ЗанятьРег();
      ЗК.PutORM(08BH,l.bas,y); (* MOV Gd,Ed *)
      ЗК.PutORM(0BH,l.bas,l);  (* OR Gd,Ed *)
      ЗК.Release(l);
      L1:=0;
      ЗК.PutJmpCF(NEQ,L1); (* jump if no zero *)
      ЗК.Ловушка(нольАвОст);
      ЗК.FixLink(L1)
    КОН;
    ЗК.PutORM(08BH,regD.bas,x);   (*      MOV Gd,Ed   *)
    ЗК.PutORM(033H,regD.bas,y);   (*      XOR Gd,Ed   *)
    L1:=0;
    L2:=0;
    ЗК.PutJmpCF(GEQ,L1);          (*      JGE L1      *)
    ЗК.PutO(099H);                (*      CWD/CDQ     *)
    ЗК.PutOM(0F7H,7H,y);          (*      IDIV EAX Ed *)
    ЗК.PutORM(85H,regD.bas,regD); (*      TEST Ed,Gd  *)
    ЗК.PutJmpCF(EQL,L2);          (*      JE  L2      *)
    ЕСЛИ div ТО
      ЗК.PutOM(0FFH,1H,x)         (*      DEC Ed      *)
    ИНАЧЕ
      ЗК.PutORM(03H,regD.bas,y)   (*      ADD Gd,Ed   *)
    КОН;
    ЗК.PutJmpF(L2);               (*      JMP L2      *)
    ЗК.FixLink(L1);               (* L1:              *)
    ЗК.PutO(099H);                (*      CWD/CDQ     *)
    ЗК.PutOM(0F7H,7H,y);          (*      IDIV EAX Ed *)
    ЗК.FixLink(L2);               (* L2:              *)
    ЕСЛИ div ТО (* ответ (<x> ДЕЛИТЬ <y>) в EAX *)
      МР.ОсвободитьРег(regD.bas)
    ИНАЧЕ (* ответ (<x> ОСТАТОК <y>) в EDX *)
      МР.ОсвободитьРег(x.bas);
      x.bas:=regD.bas
    КОН;
    МР.РегВоМРег(x.bas)
  КОН
КОН DivMod;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       Ash-(x+,y+:ЗК.нItem);
(*
 *  Цель: computes the arithemetic shift of 'x' by 'y' positions
 *    До: x, y = values
 * После: x:=x*2^y
 *)
ПЕР
  L1,L2:ЗК.Label;
УКАЗ
  СК.ValToReg(x);
  ЕСЛИ x.вид.родв = вЦел64 ТО
    МР.РегВОпредМРег(x.bas,EAX);
    МР.РегВОпредМРег(x.inx,EDX);
    СК.ValToReg(y);
    МР.РегВОпредМРег(y.bas,ECX);
    ЗК.PutCall(Coff.rtsLAshInx);
    МР.РегВоМРег(x.bas);
    МР.РегВоМРег(x.inx)
  ИНАЧЕ (* НЕ вЦел64 *)
    ЕСЛИ y.тип = пПост ТО
      ЕСЛИ y.адр < 0 ТО
        ЗК.PutOMD(1,0C1H,7H,x,-y.адр) (* SAR Ed,Ib *)
      АЕСЛИ y.адр > 0 ТО
        ЗК.PutOMD(1,0C1H,4H,x,y.адр); (* SHL Ed,Ib *)
        СК.CheckOvfl
      КОН
    ИНАЧЕ
      СК.ValToReg(y);
      МР.РегВОпредМРег(y.bas,ECX);
      ЗК.PutORM(085H,y.bas,y); (*     TEST Ed,Gd *)
      L1:=0; L2:=0;
      ЗК.PutJmpCF(EQL,L2);     (*     JZ L2      *)
      ЗК.PutJmpCF(GTR,L1);     (*     JG L1      *)
      ЗК.PutOM(0F7H,3H,y);     (*     NEG Ed     *)
      ЗК.PutOM(0D3H,7H,x);     (*     SAR Ed,CL  *)
      ЗК.PutJmpF(L2);          (*     JMP L2     *)
      ЗК.FixLink(L1);          (* L1:            *)
      ЗК.PutOM(0D3H,4H,x);     (*     SHL Ed,CL  *)
      СК.CheckOvfl;
      ЗК.FixLink(L2);          (* L2:            *)
      x.вид:=ВД.цел32вид
    КОН
  КОН
КОН Ash;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       In-(x+,y+:ЗК.нItem);
(*
 *  Цель: returns the contition if element 'x' есть в set 'y'
 *    До: x = element number, y = set
 * После: x:=x В y
 *)
УКАЗ
  ЕСЛИ y.тип = пПост ТО СК.ValToReg(y) ИНАЧЕ СК.LoadAdr(y) КОН;
  ЕСЛИ x.тип = пПост ТО
    ЗК.PutOMD(1,0FBAH,4H,y,x.адр) (* BT Ed,Ib *)
  ИНАЧЕ
    СК.ValToReg(x);
    ЕСЛИ НП.клПровПределов ТО СК.CheckRange(x,вМнож) КОН;
    ЗК.PutORM(0FA3H,x.bas,y); (* BT Ed,Gd *)
    ЗК.Release(x)
  КОН;
  СК.SetCoc(x,CST)
КОН In;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       SetUnion-(x+,y+:ЗК.нItem);
(*
 *  Цель: computes the union of the sets 'x' и 'y'
 *    До: x, y = sets
 * После: x:=x OR y *)
УКАЗ
  СК.ValToReg(x);
  ЕСЛИ y.тип = пПост ТО
    ЗК.PutOMD(4,081H,1H,x,y.адр) (* OR Ed,Id *)
  ИНАЧЕ
    СК.LoadAdr(y);
    ЗК.PutORM(0BH,x.bas,y) (* OR Gd,Ed *)
  КОН
КОН SetUnion;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       SetDiff-(x+,y+:ЗК.нItem);
(*
 *  Цель: computes the difference of the sets 'x' и 'y'           
 *    До: x,y = sets                                                
 * После: x:=x & ~y
 *)
ПЕР
  i:ЦЕЛ;
УКАЗ
  СК.ValToReg(x);
  ЕСЛИ y.тип = пПост ТО
    ЕСЛИ y.адр < 0 ТО i:=-(y.адр + 1) ИНАЧЕ i:=(-y.адр) - 1 КОН;
    ЗК.PutOMD(4,081H,4H,x,i) (* AND Ed,Id *)
  ИНАЧЕ
    СК.ValToReg(y);
    ЗК.PutOM(0F7H,2H,y);     (* NOT Ed *)
    ЗК.PutORM(023H,x.bas,y); (* AND Gd,Ed *)
  КОН
КОН SetDiff;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       SetInter-(x+,y+:ЗК.нItem);
(*
 *  Цель: computes the intersection of the sets 'x' и 'y'         
 *    До: x,y = sets                                               
 * После: x:=x & y
 *)
УКАЗ
  СК.ValToReg(x);
  ЕСЛИ y.тип = пПост ТО
    ЗК.PutOMD(4,081H,4H,x,y.адр) (* AND Ed,Id *)
  ИНАЧЕ
    СК.LoadAdr(y);
    ЗК.PutORM(023H,x.bas,y) (* AND Gd,Ed *)
  КОН
КОН SetInter;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       SetSymmDiff-(x+,y+:ЗК.нItem);
(*
 *  Цель: computes the symmetric difference of the sets 'x' и 'y'  
 *    До: x,y = sets                                               
 * После: x:=x XOR y
 *)
УКАЗ
  СК.ValToReg(x);
  ЕСЛИ y.тип = пПост ТО
    ЗК.PutOMD(4,081H,6H,x,y.адр) (* XOR Ed,Id *)
  ИНАЧЕ
    СК.LoadAdr(y);
    ЗК.PutORM(033H,x.bas,y) (* XOR Gd,Ed *)
  КОН
КОН SetSymmDiff;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
ЗАДАЧА
       Msk-(x+,y+:ЗК.нItem);
(*
 *  Цель: resets в 'x' all the bits which are set в 'y'           
 *    До: x = value, y.тип = пПост                                   
 * После: x:=x & ~y
 *)
ПЕР
  h:ЗК.нItem;
  m:ЦЕЛ;

  ЗАДАЧА Neg(x:ЦЕЛ):ЦЕЛ;
  УКАЗ
    ЕСЛИ x < 0 ТО
      ВОЗВРАТ (-(x+1))
    ИНАЧЕ
      ВОЗВРАТ ((-x)-1)
    КОН
  КОН Neg;

УКАЗ
  СК.ValToReg(x);
  m:=Neg(y.адр);
  ЗК.PutOMD(4,081H,4H,x,m); (* AND Ed,Id *)
  ЕСЛИ x.вид.родв = вЦел64 ТО
    h.тип:=Reg;
    h.bas:=x.inx;
    m:=Neg(y.disp);
    ЗК.PutOMD(4,081H,4H,h,m); (* AND Ed,Id *)
  КОН
КОН Msk;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       And-(x+,y+:ЗК.нItem);
(*
 *  Цель: computes & on boolean values
 *    До: x = condition code
 *        y = condition codes или boolean values
 * После: x:=x & y,x.тип = Coc
 *)
УКАЗ
  ЕСЛИ y.тип # Coc ТО СК.BoolToCoc(y) КОН;
  ЕСЛИ y.disp # 0 ТО
    x.disp:=ЗК.MergedLink(x.disp,y.disp)
  КОН;(* Fjmp *)
  x.reloc:=y.reloc; (* cc *)
  x.адр:=y.адр      (* Tjmp *)
КОН And;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Or-(x+,y+:ЗК.нItem);
(*
 *  Цель: computes OR on boolean values
 *    До: x = condition code
 *        y = condition codes или boolean values
 * После: x:=x OR y, x.тип = Coc
 *)
УКАЗ
  ЕСЛИ y.тип # Coc ТО СК.BoolToCoc(y) КОН;
  ЕСЛИ y.адр # 0 ТО
    x.адр:=ЗК.MergedLink(x.адр,y.адр)
  КОН; (* Tjmp *)
  x.reloc:=y.reloc; (* cc *)
  x.disp:=y.disp    (* Fjmp *)
КОН Or;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       CondAnd-(x+:ЗК.нItem);
(*
 *  Цель: sets true и false jumps for AND
 *    До: x = condition code или boolean value
 * После: x = condition code
 *)
УКАЗ
  ЕСЛИ x.тип # Coc ТО СК.BoolToCoc(x) КОН;
  ЗК.PutJmpCF(СК.InvertedCoc(x.reloc),x.disp);(* Fjmp *)
  ЗК.FixLink(x.адр)                           (* Tjmp here *)
КОН CondAnd;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       CondOr-(x+:ЗК.нItem);
(*
 *  Цель: sets true и false jumps for OR
 *    До: x = condition code или boolean value
 * После: x = condition code
 *)
УКАЗ
  ЕСЛИ x.тип # Coc ТО СК.BoolToCoc(x) КОН;
  ЗК.PutJmpCF(x.reloc,x.адр); (* Tjmp *)
  ЗК.FixLink(x.disp)          (* Fjmp here *)
КОН CondOr;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Relation-(x+:ЗК.нItem);
УКАЗ
  ЕСЛИ x.тип = Coc ТО
    СК.CocToReg(x)
  АЕСЛИ x.вид.родв В множВещ ТО
    СК.ValToFStk(x)
  КОН
КОН Relation;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Len-(x+,y+:ЗК.нItem);
(*
 *  Цель: returns the length of an array
 *    До: x = array, y.тип = пПост = dimension
 * После: x:=LEN(x,y)
 *)
ПЕР
  n:ЦЕЛ;
  вид:ВД.ДкВиду;
  h:ЗК.нItem;
УКАЗ
  n:=y.адр;
  вид:=x.вид;
  ПОКА n > 0 ВЫП 
    вид:=вид.овид; 
    УМЕНЬШИТЬ(n) 
  КОН;
  ЕСЛИ вид.родв = вОРяд ТО (* x.тип В {пПер,пПрСсылки,RegI,DArr} *)
    ЕСЛИ x.тип = RegI ТО
      x.disp:=вид.адрОВ
    АЕСЛИ (x.тип = DArr) И (x.disp = RegI) ТО
      МР.ОсвободитьРег(x.bas);
      x.тип:=RegI;
      x.bas:=x.inx;
      x.disp:=вид.адрОВ
    ИНАЧЕ
      СК.LoadBaseAdr(x);
      x.disp:=x.disp+вид.адрОВ
    КОН;
    (* x.тип=RegI *)
    h.тип:=Reg;
    h.bas:=МР.ЗанятьРег();
    ЗК.PutORM(08BH,h.bas,x); (* MOV Gd,Ed *)
    ЗК.Release(x);
    x.тип:=Reg;
    x.bas:=h.bas
  ИНАЧЕ (* вид.родв = вРяд *)
    x.тип:=пПост;
    x.адр:=вид.n
  КОН;
  x.вид:=ВД.цел32вид
КОН Len;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       Cmp-(x+,y+:ЗК.нItem; rel:ЦЕЛ);
(*
 *  Цель: returns the result of the comparison of 'x' with 'y'
 *    До: x,y:values to be compared (не both are constant)
 *        rel = relation used for comparison
 * После: x:=x 'rel' y. x.тип = Coc
 *)
ПЕР
  fx,fy,coc,размер:ЦЕЛ;
  h:ЗК.нItem;
  L1,L2,L3:ЗК.Label;
  len:ЦЕЛ;
УКАЗ
  ВЫБРАТЬ rel ИЗ
    СС.равно:  coc:=EQL
  | СС.неравно:coc:=NEQ
  | СС.меньше: coc:=LSS
  | СС.мравно: coc:=LEQ
  | СС.больше: coc:=GTR
  | СС.бравно: coc:=GEQ
  КОН;
  ЕСЛИ x.тип = пПост ТО
    h:=x; x:=y; y:=h;
    coc:=СК.ExchangedCoc(coc)
  КОН;
  (* x не ПОСТ *)
  fx:=x.вид.родв;
  fy:=y.вид.родв;
  размер:=x.вид.размер;
  СК.IgnoreDynArrDesc(x);
  СК.IgnoreDynArrDesc(y);
  ЕСЛИ fx # вПЦепь ТО
    СК.LoadAdr(x)
  КОН;
  ЕСЛИ (fx В множВещ) ИЛИ (fy В множВещ) ТО
    ЕСЛИ (x.тип = FStk) ИЛИ (y.тип # FStk) ТО
      coc:=СК.ExchangedCoc(coc)
    КОН;
    coc:=СК.UnsignedCoc(coc);
    СК.ValToFStk(x);
    СК.ValToFStk(y);
    h.bas:=МР.ЗанятьОпредРег({EAX});
    МР.УмМатМРегов;
    МР.УмМатМРегов;
    ЗК.PutO(0DED9H); (* FCOMPP *)
    ЗК.PutO(0DFE0H); (* FSTSW AX *)
    ЗК.PutO(09EH);   (* SAHF *)
    МР.ОсвободитьРег(h.bas)
  АЕСЛИ fx В {вЯчейка,вЗнак} ТО (* беззнаковое сравнение *)
    СК.ValToReg(x);
    ЕСЛИ y.тип = пПост ТО
      ЗК.PutOMD(4,081H,7H,x,y.адр) (* CMP Ed,Id *)
    ИНАЧЕ
      СК.ValToReg(y);
      ЗК.PutORM(039H,y.bas,x) (* CMP Ed,Gd *)
    КОН
  АЕСЛИ fx В {вЦел8,вЦел16,вЦел32,вМнож,вПусто,вДоступ,вЗадача,вБегунок} ТО
    ЕСЛИ (размер = 1) И (x.тип = Reg) ТО
      МР.РегВоЯчМРег(x.bas)
    КОН;
    ЕСЛИ y.тип = пПост ТО
      ЕСЛИ размер = 1 ТО
        ЗК.PutOMD(1,080H,7H,x,y.адр) (* CMP Eb,Ib *)
      ИНАЧЕ
        ЕСЛИ размер = 2 ТО
          СК.ValToReg(x)
        КОН;
        ЗК.PutOMD(4,081H,7H,x,y.адр) (* CMP Ed,Id *)
      КОН
    ИНАЧЕ
      ЕСЛИ (fx = вБегунок) И НП.клПровБегунка И НЕ ((rel = СС.равно) ИЛИ (rel = СС.неравно)) ТО
        СК.ПроверкаБегунка(x);
        СК.ПроверкаБегунка(y)
      КОН;
      СК.ValToReg(y);
      ЕСЛИ размер = 1 ТО
        МР.РегВоЯчМРег(y.bas);
        ЗК.PutORM(038H,y.bas,x) (* CMP Eb,Gb *)
      ИНАЧЕ
        ЕСЛИ размер = 2 ТО
          СК.ValToReg(x)
        КОН;
        ЗК.PutORM(039H,y.bas,x) (* CMP Ed,Gd *)
      КОН
    КОН
  АЕСЛИ fx = вЦел64 ТО
    ЕСЛИ x.тип = Reg ТО
      h.тип:=Reg;
      h.bas:=x.inx
    ИНАЧЕ
      h:=x;
      СК.IncAdr(h ,4)
    КОН;
    L1:=0;
    L2:=0;
    L3:=0;
    ЕСЛИ y.тип = пПост ТО
      ЗК.PutOMD(4,081H,7H,h,y.disp); (* CMP Ed,Id *)
      ЗК.PutJmpCF(NEQ,L1);
      ЗК.PutOMD(4,081H,7H,x,y.адр);  (* CMP Ed,Id *)
    ИНАЧЕ
      СК.ValToReg(y);
      ЗК.PutORM(039H,y.inx,h);       (* CMP Ed,Gd *)
      ЗК.PutJmpCF(NEQ,L1);
      ЗК.PutORM(039H,y.bas,x)        (* CMP Ed,Gd *)
    КОН;
    (* подправляем беззнаковое сравнение в знаковое *)
    ЗК.PutJmpCF(EQL,L1);        (*     JE  L1    *)
    ЗК.PutJmpCF(CST,L2);        (*     JB  L2    *)
    h.тип:=Reg;
    h.bas:=МР.ЗанятьРег();
    ЗК.PutOMD(4,0C7H,0H,h,1);   (*     MOV Ed,Id *)
    ЗК.PutJmpF(L3);             (*     JMP L3    *)
    ЗК.FixLink(L2);             (* L2:           *)
    ЗК.PutOMD(4,0C7H,0H,h,-1);  (*     MOV Ed,Id *)
    ЗК.FixLink(L3);             (* L3:           *)
    ЗК.PutOMD(4,081H,7H,h,0);   (*     CMP Ed,Id *)
    МР.ОсвободитьРег(h.bas);
    ЗК.FixLink(L1)
  АЕСЛИ
       fx = вКлюч
  ТО                                              (* только равно или неравно *)
    ЕСЛИ x.тип = Reg ТО МР.РегВоЯчМРег(x.bas) КОН;
    ЕСЛИ y.тип = пПост ТО
      ЗК.PutOMD(1,080H,7H,x,y.адр) (* CMP Eb,Ib *)
    ИНАЧЕ
      ЕСЛИ y.тип = Coc ТО 
        СК.CocToReg(y) 
      ИНАЧЕ 
        СК.ValToReg(y);
        МР.РегВоЯчМРег(y.bas)
      КОН;
      ЗК.PutORM(038H,y.bas,x) (* CMP Eb,Gb *)
    КОН
  АЕСЛИ
       y.тип = пПост
  ТО                                 (* character-array 'rel' constant-string *)
    len:=y.disp;
    СК.AdrToRegIDisp0(x,ESI);
    СК.AdrToRegIDisp0(y,EDI);
    h.тип:=Reg;
    h.bas:=МР.ЗанятьОпредРег({ECX});
    ЗК.PutOMD(4,0C7H,0H,h,len); (* MOV Ed,Id *)
    ЗК.Put2;                    (* d -> w *)
    ЗК.PutO(0F3A7H);            (* REPE CMPSD *)
    ЗК.Release(h);
  ИНАЧЕ                              (* character-array 'rel' character-array *)
    СК.AdrToRegIDisp0(x,ESI);
    СК.AdrToRegIDisp0(y,EDI);
    L1:=ЗК.pc; 
    L2:=0; 
    L3:=0;
    ЗК.PutOMD(2,081H,7H,y,0); (* CMP Ew,Iw *)
    ЗК.PutJmpCF(EQL,L2);
    ЗК.Put2;       (* d -> w *)
    ЗК.PutO(0A7H); (* CMPSD *)
    ЗК.PutJmpCB(EQL,L1);
    ЗК.PutJmpF(L3);
    ЗК.FixLink(L2);
    ЗК.Put2;       (* d -> w *)
    ЗК.PutO(0A7H); (* CMPSD *)
    ЗК.FixLink(L3)
  КОН;
  ЗК.Release(x);
  СК.SetCoc(x,coc)
КОН Cmp;


(*===================================== statements ===========================*)


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Copy-(x+,y+:ЗК.нItem);
(*
 *  Цель: код для служебного слова СПИСАТЬ
 *    До:    
 * После: x:=y
 *)
ПЕР
  L1,L2:ЗК.Label; 
  rx,ry:ЗК.нItem;
УКАЗ
  СК.LoadSize(x,rx);
  СК.LoadSize(y,ry);
  СК.ValToReg(rx);
  СК.ValToReg(ry);
  ЗК.PutOMD(1,0C1H,7H,rx,1); (* SAR Ed,Ib *)
  ЗК.PutOMD(1,0C1H,7H,ry,1); (* SAR Ed,Ib *)
  СК.IgnoreDynArrDesc(x);
  СК.IgnoreDynArrDesc(y);
  СК.AdrToRegIDisp0(y,ESI);
  СК.AdrToRegIDisp0(x,EDI);
  МР.РегВОпредМРег(rx.bas,EAX);

  L1:=ЗК.pc; 
  L2:=0;
  ЗК.PutOM(0FFH,1H,rx);      (* DEC Ed *)
  ЗК.PutJmpCF(LEQ,L2);
  ЗК.PutOMD(2,081H,7H,y,0);  (* CMP Ew,Iw *)
  ЗК.PutJmpCF(EQL,L2);
  ЗК.Put2;                   (* d -> w *)
  ЗК.PutO(0A5H);             (* MOVSD *)
  ЗК.PutOM(0FFH,1H,ry);      (* DEC Ed *)
  ЗК.PutJmpCB(GTR,L1);

  ЗК.FixLink(L2);
  ЗК.Release(ry);
  ЗК.PutORM(031H,rx.bas,rx); (* XOR Ed,Gd *)
  ЗК.Put2;                   (* d -> w *)
  ЗК.PutO(0ABH);             (* STOSD *)
  ЗК.Release(rx)
КОН Copy;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА
       Assign-(x+,y+:ЗК.нItem);
(*
 * Цель:  код для присваивания
 * После: x:=y
 *)
ПЕР
  fx,fy:ЦЕЛ;
  h:ЗК.нItem;
  мреги:МНОЖ;
УКАЗ
  fx:=x.вид.родв;
  fy:=y.вид.родв;
  ВЫБРАТЬ fx ИЗ
    вЯчейка,вКлюч,вЦел8:
      ЕСЛИ y.тип = пПост ТО
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutOD(1,06AH,y.адр) (* PUSH Ib *)
        ИНАЧЕ
          СК.LoadAdr(x);
          ЗК.PutOMD(1,0C6H,0H,x,y.адр) (* MOV Eb,Ib *)
        КОН
      ИНАЧЕ
        СК.ValToReg(y);
        ЕСЛИ (fx = вЦел8) И НП.клПровПределов ТО
          СК.CheckRange(y,вЦел8)
        КОН;
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutPushReg(y.bas)
        ИНАЧЕ
          МР.РегВоЯчМРег(y.bas);
          СК.LoadAdr(x);
          ЗК.PutORM(088H,y.bas,x) (* MOV Eb,Gb *)
        КОН
      КОН
  | вЗнак,вЦел16:
      ЕСЛИ y.тип = пПост ТО
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutOD(4,068H,y.адр) (* PUSH Id *)
        ИНАЧЕ
          СК.LoadAdr(x);
          ЗК.PutOMD(2,0C7H,0H,x,y.адр) (* MOV Ew,Iw *)
        КОН
      ИНАЧЕ
        СК.ValToReg(y);
        ЕСЛИ (fx = вЦел16) И НП.клПровПределов ТО
          СК.CheckRange(y,вЦел16)
        КОН;
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutPushReg(y.bas)
        ИНАЧЕ
          СК.LoadAdr(x);
          ЗК.Put2;                (* d -> w *)
          ЗК.PutORM(089H,y.bas,x) (* MOV Ed,Gd *)
        КОН
      КОН
  | вЦел32,вМнож:
      ЕСЛИ y.тип = пПост ТО
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutOD(4,068H,y.адр) (* PUSH Id *)
        ИНАЧЕ
          СК.LoadAdr(x);
          ЗК.PutOMD(4,0C7H,0H,x,y.адр) (* MOV Ed,Id *)
        КОН
      ИНАЧЕ
        СК.ValToReg(y);
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutPushReg(y.bas)
        ИНАЧЕ
          СК.LoadAdr(x);
          ЗК.PutORM(089H,y.bas,x) (* MOV Ed,Gd *)
        КОН
      КОН
  | вЦел64:
      ЕСЛИ y.тип = пПост ТО
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutOD(4,068H,y.disp); (* PUSH Id *) (* ст. *)
          ЗК.PutOD(4,068H,y.адр)   (* PUSH Id *) (* мл. *)
        ИНАЧЕ
          СК.LoadAdr(x);
          h:=x;
          СК.IncAdr(h,4);
          ЗК.PutOMD(4,0C7H,0H,x,y.адр);  (* MOV Ed,Id *) (* мл. *)
          ЗК.PutOMD(4,0C7H,0H,h,y.disp)  (* MOV Ed,Id *) (* ст. *)
        КОН
      ИНАЧЕ
        СК.ValToReg(y);
        ЕСЛИ fy # вЦел64 ТО
          y.inx:=МР.ЗанятьОпредРег({EDX});
          мреги:=МР.СейчасДопМРеги(y.bas);
          МР.РегВОпредМРег(y.bas,EAX);
          ЗК.PutO(099H); (* CDQ *)
          МР.УстДопМРеги(y.bas,мреги);
          МР.УстДопМРеги(y.inx,МР.МРеги)
        КОН;
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutPushReg(y.inx);    (* ст. *)
          ЗК.PutPushReg(y.bas);    (* мл. *)
        ИНАЧЕ
          СК.LoadAdr(x);
          h:=x;
          СК.IncAdr(h,4);
          ЗК.PutORM(089H,y.bas,x); (* MOV Ed,Gd *) (* мл. *)
          ЗК.PutORM(089H,y.inx,h)  (* MOV Ed,Gd *) (* ст. *)
        КОН;
        ЕСЛИ fy # вЦел64 ТО
          МР.ОсвободитьРег(y.inx)
        КОН
      КОН
  | вВещ32:
      ЕСЛИ (y.тип = пПост) И (fy = вВещ32) ТО
        ЕСЛИ x.тип = Stk ТО
          СК.LoadAdr(y);
          ЗК.PutOM(0FFH,6H,y) (* PUSH Ed *)
        ИНАЧЕ
          СК.LoadAdr(x);
          СК.MoveBlockS(x,y,4)
        КОН
      ИНАЧЕ
        ЕСЛИ x.тип = Stk ТО
          ЕСЛИ fy # вВещ32 ТО
            СК.ValToFStk(y)
          КОН;
          ЕСЛИ y.тип = FStk ТО
            СК.AllocStkBlockS(4,x);
            МР.УмМатМРегов;
            ЗК.PutOM(0D9H,3H,x); (* FSTP Es *)
            ЗК.Release(x);
            x.тип:=Stk
          ИНАЧЕ
            СК.LoadAdr(y);
            ЗК.PutOM(0FFH,6H,y) (* PUSH Ed *)
          КОН
        ИНАЧЕ
          СК.ValToFStk(y);
          СК.LoadAdr(x);
          МР.УмМатМРегов;
          ЗК.PutOM(0D9H,3H,x) (* FSTP Es *)
        КОН
      КОН
  | вВещ64:
      ЕСЛИ (y.тип = пПост) И (fy = вВещ64) ТО
        ЕСЛИ x.тип = Stk ТО
          СК.LoadAdr(y);
          СК.IncAdr(y,4);
          ЗК.PutOM(0FFH,6H,y); (* PUSH Ed *)
          СК.IncAdr(y,-4);
          ЗК.PutOM(0FFH,6H,y)  (* PUSH Ed *)
        ИНАЧЕ
          СК.LoadAdr(x);
          СК.MoveBlockS(x,y,8)
        КОН
      ИНАЧЕ
        ЕСЛИ x.тип = Stk ТО
          ЕСЛИ fy # вВещ64 ТО
            СК.ValToFStk(y)
          КОН;
          ЕСЛИ y.тип = FStk ТО
            СК.AllocStkBlockS(8,x);
            МР.УмМатМРегов;
            ЗК.PutOM(0DDH,3H,x); (* FSTP El *)
            ЗК.Release(x);
            x.тип:=Stk
          ИНАЧЕ
            СК.LoadAdr(y);
            СК.IncAdr(y,4);
            ЗК.PutOM(0FFH,6H,y); (* PUSH Ed *)
            СК.IncAdr(y,-4);
            ЗК.PutOM(0FFH,6H,y)  (* PUSH Ed *)
          КОН;
        ИНАЧЕ
          СК.ValToFStk(y);
          СК.LoadAdr(x);
          МР.УмМатМРегов;
          ЗК.PutOM(0DDH,3H,x)  (* FSTP El *)
        КОН
      КОН
  | вДоступ:
      ЕСЛИ fy = вПусто ТО
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutOD(4,068H,0) (* PUSH Id *)
        ИНАЧЕ
          СК.LoadAdr(x);
          ЗК.PutOMD(4,0C7H,0H,x,0) (* MOV Ed,Id *)
        КОН
      ИНАЧЕ
        ЕСЛИ x.тип = Stk ТО
          СК.LoadAdr(y);
          ЗК.PutOM(0FFH,6H,y) (* PUSH Ed *)
        ИНАЧЕ
          СК.ValToReg(y);
          СК.LoadAdr(x);
          ЗК.PutORM(089H,y.bas,x) (* MOV Ed,Gd *)
        КОН
      КОН
  | вЗадача:
      ЕСЛИ fy = вПусто ТО
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutOD(4,068H,0) (* PUSH Id *)
        ИНАЧЕ
          СК.LoadAdr(x);
          ЗК.PutOMD(4,0C7H,0H,x,0) (* MOV Ed,Id *)
        КОН
      АЕСЛИ x.вид = y.вид ТО
        ЕСЛИ x.тип = Stk ТО
          СК.LoadAdr(y);
          ЗК.PutOM(0FFH,6H,y) (* PUSH Ed *)
        ИНАЧЕ
          СК.ValToReg(y);
          СК.LoadAdr(x);
          ЗК.PutORM(089H,y.bas,x) (* MOV Ed,Gd *)
        КОН
      ИНАЧЕ (* y.тип = пЗадача *)
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutOD(4,068H,0) (* PUSH Id *)
        ИНАЧЕ
          СК.LoadAdr(x);
          ЗК.PutOMD(4,0C7H,0H,x,0) (* MOV Ed,Id *)
        КОН;
        ЕСЛИ y.пон.адр <= 0 ТО
          ЗК.PutLink(ЗК.pc-4,y.пон.адр)
        ИНАЧЕ
          Coff.СоздатьСкр(Coff.Код,Coff.СКР_ТОЧНО,y.пон.адр,ЗК.pc-4)
        КОН;
      КОН
  | вБегунок:
      ЕСЛИ fy = вПусто ТО
        ЕСЛИ x.тип = Stk ТО
          ЗК.PutOD(4,068H,0) (* PUSH Id *)
        ИНАЧЕ
          СК.LoadAdr(x);
          ЗК.PutOMD(4,0C7H,0H,x,0) (* MOV Ed,Id *)
        КОН
      ИНАЧЕ
        ЕСЛИ НП.клПровБегунка ТО
          ЕСЛИ x.тип = Stk ТО
            СК.AllocStkBlockS(НП.рБегунок,x)
          ИНАЧЕ
            СК.LoadAdr(x)
          КОН;
          СК.MoveBlockS(x,y,НП.рБегунок)
        ИНАЧЕ
          (* как вДоступ *)
          ЕСЛИ x.тип = Stk ТО
            СК.LoadAdr(y);
            ЗК.PutOM(0FFH,6H,y) (* PUSH Ed *)
          ИНАЧЕ
            СК.ValToReg(y);
            СК.LoadAdr(x);
            ЗК.PutORM(089H,y.bas,x) (* MOV Ed,Gd *)
          КОН
        КОН  
      КОН
  | вОРяд:
      ПРОВЕРИТЬ(x.тип # Stk);
      СК.LoadAdr(x);
      СК.PushDynArrDesc(x,y)
  | вРяд:
      ПРОВЕРИТЬ(x.тип # Stk);
      СК.LoadAdr(x);
      ЕСЛИ x.вид = y.вид ТО
        СК.MoveBlockS(x,y,x.вид.размер)
      ИНАЧЕ
        СК.MoveBlockS(x,y,y.disp*НП.рЗнак) (* вПЦепь *)
      КОН
  | вНабор:
      ПРОВЕРИТЬ(x.тип # Stk);
      СК.LoadAdr(x);
      СК.MoveBlockS(x,y,x.вид.размер)
  КОН
КОН Assign;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       УмножДлРазм-(z+,y+:ЗК.нItem;
                    dimtyp,dim0typ:ВД.ДкВиду);
(*
 *  Цель:  z:=z*y
 *    До: <z> - накопитель,
 *        <y> - РАЗМЕР у текущей размерности <dimtyp>
 *        <dim0typ> - 0-я размерность
 *)
ПЕР
  s:ЗК.нItem;
УКАЗ
  (* сохраняем РАЗМЕР размерности для УстДлРазм *)
  ЕСЛИ y.тип = пПост ТО
    ЗК.PutOD(4,068H,y.адр)  (* PUSH Id *)
  ИНАЧЕ
    СК.ValToReg(y);
    ЗК.PutOM(0FFH,6H,y)     (* PUSH Ed *)
  КОН;
  ЕСЛИ dimtyp = dim0typ ТО
    (* для 0-й размерности устанавливаем начальное значение <z>=<y> *)
    z.тип:=Reg;
    z.bas:=МР.ЗанятьРег();
    z.вид:=ВД.цел32вид;
    ЕСЛИ y.тип = пПост ТО
      ЗК.PutOMD(4,0C7H,0H,z,y.адр) (* MOV Ed,Id *)
    ИНАЧЕ
      ЗК.PutORM(089H,y.bas,z)      (* MOV Ed,Gd *)
    КОН
  ИНАЧЕ
    Mul(z,y,ОТКЛ)
  КОН;
  ЗК.Release(y);
  ЕСЛИ dimtyp.адрОВ = 4 ТО (* последняя размерность *)
    (* умножаем на размер слагаемого ряда *)
    s.тип:=пПост;
    s.вид:=ВД.цел32вид;
    s.адр:=dimtyp.овид.размер;
    Mul(z,s,ОТКЛ);
    (* и прибавляем размер служебных данных ряда *)
    s.тип:=пПост;
    s.вид:=ВД.цел32вид;
    s.адр:=dim0typ.размер;
    Add(z,s,ОТКЛ)
  КОН
КОН УмножДлРазм;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       УстДлРазм-(     x+:ЗК.нItem;
                  dimtyp :ВД.ДкВиду);
(*
 *  Цель: установить у измерения <dimtyp.n> ряда <x> соответствующую РАЗМЕРn
 *    До: x.тип = RegI, ссылается на память ряда; в стеке сохранены все РАЗМЕРы
 * После: РАЗМЕР(x,dimtyp.n)=РАЗМЕРn
 *)
ПЕР
  h:ЗК.нItem;
УКАЗ
  x.disp:=dimtyp.адрОВ;
  h.тип:=Reg;
  h.bas:=МР.ЗанятьРег();
  ЗК.PutOM(08FH,0H,h);      (* POP Ed *) (* восстанавливаем РАЗМЕРn *)
  ЗК.PutORM(089H,h.bas,x);  (* MOV Ed,Gd *)
  ЗК.Release(h);
  x.disp:=0 (* восстанавливаем адрес ряда *)
КОН УстДлРазм;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       СоздатьОРяд-(x+,z+:ЗК.нItem);
(*
 *  Цель: распределить память для вОРяд
 *    До: <x> = ДОСТУП К вОРяд
 *        <z> = размер участка памяти для рабочих и служебных данных
 * После: <x> = вОРяд
 *)
УКАЗ
                 (* сохраняем адрес x *)
  СК.LoadAdr(x);
  СК.PushItem(x);
                 (* 1-й приёмник у Создать - описатель вида (=0 для вОРяд) *)
  ЗК.PutOD(4,068H,0);       (* PUSH Id *)
                 (* 2-й приёмник у Создать - размер участка памяти *)
  ЕСЛИ z.тип = пПост ТО
    ЗК.PutOD(4,068H,z.адр)  (* PUSH Id *)
  ИНАЧЕ
    ЗК.PutOM(0FFH,6H,z)     (* PUSH Ed *)
  КОН;
  ЗК.Release(z);
                 (* 3-й приёмник у Создать - адрес <x> *)
  СК.PushItem(x);
  ЗК.Release(x);
                 (* вызов СРЕДА.Создать(...) *)
  ЗК.PutCall(Coff.rtsNewInx);
                 (* восстанавливаем адрес <x> *)
  x.тип:=Reg;
  x.bas:=МР.ЗанятьРег();
  ЗК.PutOM(08FH,0H,x);      (* POP Ed *)
                 (* преобразуем <x> из 'ДОСТУП К вОРяд' в 'вОРяд' *)
  x.тип:=RegI;
  x.disp:=0;
  ЗК.PutORM(08BH,x.bas,x);  (* MOV Gd,Ed *)
  x.вид:=x.вид.овид;
                 (* записываем в 0-е служебное слово ряда его размерность *)
  ЗК.PutOMD(4,0C7H,0H,x,x.вид.n+1) (* MOV Ed,Id *)
КОН СоздатьОРяд;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Создать-(x+:ЗК.нItem);
(*
 *  Цель: распределить память для вРяд или для вНабор
 *    До: x = адрес переменной, в которой будет сохранен адрес участка
 *        x.вид.овид.родв В {вНабор,вРяд}
 *)
ПЕР
  xtag:ЗК.нItem;
  вид:ВД.ДкВиду;
УКАЗ
  вид:=x.вид.овид;
  ПРОВЕРИТЬ(вид.родв В {вРяд,вНабор});
  ЕСЛИ вид.родв = вРяд ТО
    ЗК.PutOD(4,068H,0);         (* PUSH Id *) (* у ряда нет ОВ *)
    ЗК.PutOD(4,068H,вид.размер) (* PUSH Id *)
  ИНАЧЕ
    LoadTypDescAdr(вид,xtag);
    СК.PushAdr(xtag);
    ЗК.Release(xtag);
    ЗК.PutOD(4,068H,вид.размер) (* PUSH Id *)
  КОН;
  СК.PushAdr(x);
  ЗК.PutCall(Coff.rtsNewInx)
КОН Создать;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА 
       Обнулить-(x+:ЗК.нItem);
(*
 *  Цель: обнулить память для вРяд, вОРяд или вНабор
 *    До: x = переменная которую необходимо обнулить
 *        x.вид.родв В {вНабор,вРяд,вОРяд}
 *)
ПЕР
  rx,z:ЗК.нItem;
  eax:ЦЕЛ;
УКАЗ
  СК.LoadSize(x,rx);
  СК.ValToReg(rx);
  СК.IgnoreDynArrDesc(x);
  СК.AdrToRegIDisp0(x,EDI);
  МР.РегВОпредМРег(rx.bas,ECX);    (* ECX:=размер *)
  eax:=МР.ЗанятьОпредРег({EAX});
  СК.ClearReg(eax);                (* EAX:=0 *)
  ЗК.PutO(0F3AAH);                 (* REP STOSB *)
  ЗК.Release(x);
  ЗК.Release(rx);
  МР.ОсвободитьРег(eax)
КОН Обнулить;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ЦелЧасть-(x+:ЗК.нItem);
(*  Цель: целая часть вещественного числа (задача ЦЕЛЧАСТЬ) *)
УКАЗ
  СК.ValToFStk(x);
  ЗК.PutCall(Coff.rtsCelChast)
КОН ЦелЧасть;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       FJ-(loc+:ЗК.Label);
(*  Цель: unconditional forward jump *)
УКАЗ
  ЗК.PutJmpF(loc)
КОН FJ;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       CFJ-(  x+:ЗК.нItem;
            loc+:ЗК.Label);
(*  Цель: conditional forward jump on false *)
УКАЗ
  ЕСЛИ x.тип # Coc ТО СК.BoolToCoc(x) КОН;
  ЗК.PutJmpCF(СК.InvertedCoc(x.reloc),x.disp);
  loc:=x.disp;(* Fjmp *)
  ЗК.FixLink(x.адр)  (* Tjmp here *)
КОН CFJ;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       BJ-(loc:ЗК.Label);
(*  Цель: unconditional backward jump *)
УКАЗ
  ЗК.PutJmpB(loc)
КОН BJ;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       CBJ-( x+:ЗК.нItem;
           loc :ЗК.Label);
(* Цель: conditional backward jump on false *)
ПЕР
  L1:ЗК.Label;
УКАЗ
  ЕСЛИ x.тип # Coc ТО СК.BoolToCoc(x) КОН;
  ЕСЛИ x.disp = 0 ТО
    ЗК.PutJmpCB(СК.InvertedCoc(x.reloc),loc) (* Fjmp *)
  ИНАЧЕ
    L1:=0;
    ЗК.PutJmpCF(x.reloc,L1);
    ЗК.FixLink(x.disp);  (* Fjmp here *)
    ЗК.PutJmpB(loc);
    ЗК.FixLink(L1)
  КОН;
  ЗК.FixLink(x.адр)      (* Tjmp here *)
КОН CBJ;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Case-(       x+:ЗК.нItem;
             low,high :ЦЕЛ;
                  tab+:ЦЕЛ);
(* 
 *  Цель: code for the case statement
 *    До: x = value of case selector
 *        low, high = minimal an maximal value of 'x'
 * После: tab = address of case table
 *        code for trap СС.или ELSE clause must follow immediately
 *        after the code emitted by this function
 *)
ПЕР
  LElse:ЗК.Label;
УКАЗ
  СК.ValToReg(x);
  ЕСЛИ low # 0 ТО
    ЗК.PutOMD(4,081H,5H,x,low);    (* SUB Ed,Id *)
  ИНАЧЕ
    ЗК.PutORM(85H,x.bas,x);       (* TEST Ed,Gd *)
  КОН;
  LElse:=0;
  ЗК.PutJmpCF(LSS,LElse);
  ЗК.PutOMD(4,081H,7H,x,high-low); (* CMP Ed,Id *)
  ЗК.PutJmpCF(GTR,LElse);
  ЗК.PutCaseJmp(x);
  ЗК.AllocCaseTab(low,high,tab);
  ЗК.FixLink(LElse)
КОН Case;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Param-(ис+, пр+  :ЗК.нItem;
              заграница,
              deref,сюда:КЛЮЧ);
(*
 *  Цель: укладывание источников в стог
 *    До: <ис>          - источники
 *        <пр>          - приёмники
 *        заграница=ВКЛ - источники передаются наружу или принимаются извне
 *        deref=ВКЛ     - <ис> является доступом 
 *        сюда=ВКЛ      - источники принимаются извне
 *)
ПЕР
  x:ЗК.нItem;
УКАЗ
  ЕСЛИ пр.вид.родв = вОРяд ТО
    ЕСЛИ заграница ТО
      ПРОВЕРИТЬ(сюда = ОТКЛ);
      СК.IgnoreDynArrDesc(ис);
      СК.PushAdr(ис)
    ИНАЧЕ
      СК.PushDynArrDesc(пр,ис)
    КОН
  АЕСЛИ пр.тип = пПрСсылки ТО
    ЕСЛИ пр.вид.родв = вНабор ТО
      ЕСЛИ deref ТО
        ПРОВЕРИТЬ(заграница = ОТКЛ);
        СК.LoadAdr(ис);
        СК.PushAdr(ис);
        СК.IncAdr(ис,-4);         (* указатель на ОВ *)
        ЗК.PutOM(0FFH,6H,ис)      (* PUSH Ed *)
      АЕСЛИ ис.тип = пПрСсылки ТО
        СК.LoadBaseAdr(ис);       (* указатель на адрес *)
        ЕСЛИ заграница ТО
          ЕСЛИ сюда ТО
            ЗК.PutOM(0FFH,6H,ис); (* PUSH Ed *)
            LoadTypDescAdr(ис.вид,x);
            СК.PushAdr(x);
            ЗК.Release(x)
          ИНАЧЕ
            СК.IncAdr(ис,4);      (* указатель на адрес *)
            ЗК.PutOM(0FFH,6H,ис); (* PUSH Ed *)
          КОН
        ИНАЧЕ
          СК.IncAdr(ис,4);        (* указатель на адрес *)
          ЗК.PutOM(0FFH,6H,ис);   (* PUSH Ed *)
          СК.IncAdr(ис,-4);       (* указатель на ОВ *)
          ЗК.PutOM(0FFH,6H,ис)    (* PUSH Ed *) 
        КОН
      ИНАЧЕ
        ПРОВЕРИТЬ(заграница = ОТКЛ);
        СК.PushAdr(ис);
        LoadTypDescAdr(ис.вид,x);
        СК.PushAdr(x);
        ЗК.Release(x);
      КОН
    ИНАЧЕ
      СК.PushAdr(ис)
    КОН
  ИНАЧЕ
    x.тип:=Stk;
    x.вид:=пр.вид;
    Assign(x,ис);
    ЗК.Release(x)
  КОН
КОН Param;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       СохранитьРеги-;
(*  Цель: save used CPU registers в stack before function call *)
ПЕР
  нов:ДкСохрРеги;
УКАЗ
     СОЗДАТЬ(нов);
             нов.пред:=сохрРегиД;
  сохрРегиД:=нов;
  МР.ВходВЗадачу(сохрРегиД.греги)
КОН СохранитьРеги;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ВосстановитьРеги-(x+:ЗК.нItem);
(*
 *  Цель: load CPU registers from stack after function call
 *        prepare result в 'x'
 *    До: x.вид = type of result (# ВД.нетвид)
 * После: x.тип В {FStk,Reg}, result СС.в FS(0) СС.или EAX
 *)
ПЕР
  вещОтв:КЛЮЧ;
УКАЗ
  ПРОВЕРИТЬ(сохрРегиД # ПУСТО);
  вещОтв:=x.вид.родв В множВещ;
  МР.ВыходИзЗадачи(сохрРегиД.греги,вещОтв);
  сохрРегиД:=сохрРегиД.пред;
  ЕСЛИ вещОтв ТО
    x.тип:=FStk
  ИНАЧЕ
    x.тип:=Reg;
    x.bas:=МР.ЗанятьОпредРег({EAX});
    МР.УстДопМРеги(x.bas,МР.ЯчМРеги);
    ЕСЛИ x.вид.родв = вЦел64 ТО
      x.inx:=МР.ЗанятьОпредРег({EDX});
      МР.УстДопМРеги(x.bas,МР.МРеги)
    КОН
  КОН
КОН ВосстановитьРеги;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       CallVar-(x+:ЗК.нItem);
(*
 *  Цель: код для вызова переменных
 *    До: x.тип В {пПер,пПрСсылки}
 *)
УКАЗ
  ЕСЛИ НЕ (x.тип В {Abs,AbsRel}) ТО
    СК.LoadAdr(x);
    СК.AdrToRegI(x)
  КОН;
  ЗК.PutIndCall(x)
КОН CallVar;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       CallProc-(задача:ВД.ДкПонятию);(* Цель: generate code for задача calls *)
УКАЗ
  ЕСЛИ задача.адр <= 0 ТО
    ЗК.PutCallF(задача.адр)
  ИНАЧЕ
    ЗК.PutCall(задача.адр)
  КОН
КОН CallProc;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       CallDllProc-(задача:ВД.ДкПонятию);
ПЕР
  нс:ЦЕЛ;
  имя:ЦЕПЬ[НП.длинаНазвания+10];
УКАЗ
  ЕСЛИ НП.клКодДляМСборки ТО
    имя:="__imp__"
  ИНАЧЕ
    имя:=""
  КОН;
 оЦепи.ДобавитьВКонец(имя,задача.имя);
  Coff.AddSymbolName(имя,нс,ВКЛ);
  ЗК.PutDllCall(нс)
КОН CallDllProc;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Result-(задача :ВД.ДкПонятию;
                    x+:ЗК.нItem);
(*
 *  Цель: code to return 'x' from a function
 *    До: задача:задача which finishes
 *             x:value to be returned
 *)
УКАЗ
  ЕСЛИ задача.вид.родв В множВещ ТО
    СК.ValToFStk(x);
  ИНАЧЕ
    СК.ValToReg(x);
    МР.РегВОпредМРег(x.bas,EAX);
    ЕСЛИ задача.вид.родв = вЦел64 ТО
      ЕСЛИ x.вид.родв # вЦел64 ТО
        x.inx:=МР.ЗанятьОпредРег({EDX});
        ЗК.PutO(099H);   (* CDQ *)
        x.вид:=задача.вид
      ИНАЧЕ
        МР.РегВОпредМРег(x.inx,EDX)
      КОН
    КОН
  КОН
КОН Result;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ОпустошитьДоступы(задача:ВД.ДкПонятию;
                        адреса+:РЯД ИЗ ЦЕЛ;
                        адресов:ЦЕЛ);
(*
 *  Цель: устанавливает переменные доступа задачи <задача> в ПУСТО
 *    До: <адреса>     - адреса переменных доступа задачи
 *        <адресов>    - наполнение ряда <адреса>
 *)
ПЕР
  x:ЗК.нItem; (* EDI=ESP,EBP *)
  y:ЗК.нItem; (* ECX=размер области данных / 4 *)
  z:ЗК.нItem; (* EAX=ПУСТО *)
УКАЗ
  ЕСЛИ адресов = 0 ТО ВОЗВРАТ КОН;
  z.bas:=МР.ЗанятьОпредРег({EAX});
  СК.ClearReg(z.bas);          (* EAX:=ПУСТО *)
  ЕСЛИ
      адресов = РАЗМЕР(адреса)
  ТО                                                 (* слишком много адресов *)
    (* обнуляем всю область данных задачи *)
    y.тип:=Reg;                          (* ECX:=размер DIV 4 *)
    y.bas:=МР.ЗанятьОпредРег({ECX});
    (* в задача.пост.цел2 размер области данных задачи *)
    ЗК.PutOMD(4,0C7H,0H,y,задача.пост.цел2 ДЕЛИТЬ 4); (* MOV Ed,Id *)
    x.тип:=Reg;                          (* EDI:=ESP *)
    x.bas:=МР.ЗанятьОпредРег({ESP});
    x.inx:=МР.ЗанятьОпредРег({EDI});
    ЗК.PutORM(08BH,x.inx,x);             (* MOV r32,r/m32 *)
    ЗК.PutO(0F3ABH);                     (* REP STOSW/D *)
    МР.ОсвободитьРег(x.bas);
    МР.ОсвободитьРег(x.inx);
    МР.ОсвободитьРег(y.bas);
  ИНАЧЕ
    x.тип:=RegI;
    x.bas:=МР.ЗанятьОпредРег({EBP});
    ПОКА адресов > 0 ВЫП
      УМЕНЬШИТЬ(адресов);
      x.disp:=адреса[адресов];
      ПРОВЕРИТЬ(x.disp < 0);
      ЗК.PutORM(089H,z.bas,x)            (* MOV Ed,Gd *)
    КОН;
    МР.ОсвободитьРег(x.bas)
  КОН;
  МР.ОсвободитьРег(z.bas)
КОН ОпустошитьДоступы;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ЗапускОтдела;
(*  Цель: code at entry-point of modules *)
ПЕР
  имя:ЦЕПЬ[НП.длинаНазвания*2+1];
  нс,но:ЦЕЛ;
УКАЗ
  ЕСЛИ
       НП.отдВид=НП.приложение
  ТО
    но:=1;
    ПОКА
         но < ВД.чВхОтд
    ВЫП
      Coff.MakeGlobalName(ВД.рПонВхОтд[но].имя,"_Zapusk",имя);
      Coff.AddSymbolName(имя,нс,ВКЛ);
      ЗК.PutCall(нс);
      УВЕЛИЧИТЬ(но)
    КОН
  КОН;
  Coff.AddSymbolName("SRJEDA_Prisojedinite",нс,ВКЛ);
  ЗК.PutOD(4,068H,0); (* PUSH Id *)
  ЗК.PutLink(ЗК.pc-4,ЗК.modDescLabel);
  ЗК.PutCall(нс)
КОН ЗапускОтдела;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ВходВПринимаемую-;
(*
 *  Цель: сохраняем EBP ([EBP]) и EIP ([EBP]+4) задачи,
 *        вызвавшей принимаемую задачу, в глобальных переменных GlBP и GlIP
 *)
ПЕР
  x,y,z:ЗК.нItem;
УКАЗ
  x.тип:=RegI;
  x.bas:=МР.ЗанятьОпредРег({EBP});
  x.disp:=0;
  y.тип:=Reg;
  y.bas:=МР.ЗанятьРег();
  ЗК.PutORM(08BH,y.bas,x); (* MOV Gd,Ed *)
  z.тип:=AbsRel;
  z.адр:=0;
  z.reloc:=Coff.СКР_ТОЧНО;
  z.relocInx:=Coff.rtsGlBP;
  ЗК.PutORM(089H,y.bas,z); (* MOV Ed,Gd *)
  x.disp:=4;
  ЗК.PutORM(08BH,y.bas,x); (* MOV Gd,Ed *)
  z.relocInx:=Coff.rtsGlIP;
  ЗК.PutORM(089H,y.bas,z); (* MOV Ed,Gd *)
  ЗК.Release(x);
  ЗК.Release(y)
КОН ВходВПринимаемую;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ВходВПередаваемую-;
(*
 *  Цель: связать стек вызовов с предыдущей вызванной из Глагола
 *        принимаемой задачей
 *)
ПЕР
  x:ЗК.нItem;
УКАЗ
  ЗК.PutO(050H+3);         (* PUSH EBX *)
  ЗК.PutO(050H+6);         (* PUSH ESI *)
  ЗК.PutO(050H+7);         (* PUSH EDI *)
  x.тип:=AbsRel;
  x.адр:=0;
  x.reloc:=Coff.СКР_ТОЧНО;
  x.relocInx:=Coff.rtsGlIP;
  ЗК.PutOM(0FFH,6H,x);     (* PUSH Ed *)
  x.relocInx:=Coff.rtsGlBP;
  ЗК.PutOM(0FFH,6H,x);     (* PUSH Ed *)
  x.тип:=Reg;
  x.bas:=МР.ЗанятьОпредРег({EBP});
  ЗК.PutOMD(4,081H,5H,x,12); (* SUB Ed,Id *)
  ЗК.Release(x)
КОН ВходВПередаваемую;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ВыходИзПередаваемой-;
(*
 *  Цель: отвязать стек вызовов от предыдущей вызванной из Глагола
 *        принимаемой задачей
 *)
ПЕР
  x:ЗК.нItem;
УКАЗ
  x.тип:=Reg;
  x.bas:=МР.ЗанятьОпредРег({EBP});
  ЗК.PutOMD(4,081H,0H,x,12); (* ADD Ed,Id *)
  ЗК.Release(x);
  x.тип:=AbsRel;
  x.адр:=0;
  x.reloc:=Coff.СКР_ТОЧНО;
  x.relocInx:=Coff.rtsGlBP;
  ЗК.PutOM(08FH,0H,x);      (* POP Ed *)
  x.relocInx:=Coff.rtsGlIP;
  ЗК.PutOM(08FH,0H,x);      (* POP Ed *)
  ЗК.Release(x);
  ЗК.PutO(058H+7);          (* POP EDI *)
  ЗК.PutO(058H+6);          (* POP ESI *)
  ЗК.PutO(058H+3);          (* POP EBX *)
КОН ВыходИзПередаваемой;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Enter-(   задача:ВД.ДкПонятию;
              startLine:ЦЕЛ;
 startOffs+,lineNumInx+:ЦЕЛ;
                адреса+:РЯД ИЗ ЦЕЛ;
                адресов:ЦЕЛ
             );
(*
 *  Цель: код в точке входа задачи
 *    До: <startLine>  - номер первой строки задачи в тексте отдела
 *        <адреса>     - адреса переменных доступа задачи
 *        <адресов>    - наполнение ряда <адреса>
 * После: <startOffs>  - адрес точки входа
          <lineNumInx> - номер в таблице COFF первой строки задачи
 *)
УКАЗ
  startOffs:=ЗК.pc;
  ЗК.ВСписокОЗ(задача,startOffs);

  Coff.AddLineNum(startOffs,startLine,ВКЛ);

  lineNumInx:=Coff.GetLineInx();
  ЗК.BegProc(задача.пост.цел2,задача.уровень+1);
  ЕСЛИ НП.клДостВПусто ТО ОпустошитьДоступы(задача,адреса,адресов) КОН;

  ЕСЛИ прГоловная В задача.признаки ТО
    ЗапускОтдела
  КОН;

  ЕСЛИ НП.клОтлДанные ТО
    СОЗДАТЬ(задача.debugInfo);
    задача.debugInfo.codeDebugStart:=ЗК.pc-startOffs
  КОН
КОН Enter;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Exit-(задача:ВД.ДкПонятию);
(*
 *  Цель: code at exit-point of procedures СС.и modules
 *    До: задача:задача which finishes
 *)
УКАЗ
  ПРОВЕРИТЬ((задача.родп = пЗадача) ИЛИ (задача.родп = пОтдел));
  ЗК.EndProc(задача.пост.цел1)
КОН Exit;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Leave-(
                  задача :ВД.ДкПонятию;
               startLine,
               startOffs,
              lineNumInx,
               конСтрока :ЦЕЛ
             );
ПЕР
  ссылки:ЦЕЛ;                     (* список ссылок на задачу *)
УКАЗ
  ЕСЛИ НП.клОтлДанные ТО
    задача.debugInfo.codeDebugEnd:=ЗК.pc-startOffs
  КОН;
  Coff.AddLineNum(ЗК.pc,конСтрока,ОТКЛ);
  Exit(задача);
  ЕСЛИ НП.клОтлДанные ТО
    задача.debugInfo.procLen:=ЗК.pc-startOffs-1
  КОН;
  ЕСЛИ ЗК.уровень <= 1 ТО
    ЕСЛИ НЕ НП.клОтлДанные ТО lineNumInx:=0 КОН
  КОН;
  ссылки:=задача.адр;
  Coff.AddSymbolProc(задача,startOffs,ЗК.pc-startOffs,startLine,lineNumInx);
  ЗК.FixLinkInd(-ссылки,задача.адр)
КОН Leave;


(*============== задачи отдела ОБХОД ===========================*)


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       SYSadr-(x+:ЗК.нItem);                           (* ОБХОД.ПолучитьАдрес *)
ПЕР
  h:ЗК.нItem;
УКАЗ
  СК.IgnoreDynArrDesc(x);
  СК.LoadAdr(x);
  h.bas:=МР.ЗанятьРег();
  ЗК.PutORM(08DH,h.bas,x); (* LEA r32,m *)
  ЗК.Release(x);
  x.bas:=h.bas;
  x.тип:=Reg;
  x.вид:=ВД.цел32вид
КОН SYSadr;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       SYSval-(x+:ЗК.нItem; вид:ВД.ДкВиду);                 (* ОБХОД.Значение *)
ПЕР
  xродв,родв:ЦЕЛ;
УКАЗ
  xродв:=x.вид.родв; 
   родв:=вид.родв;
  ЕСЛИ
        ( родв В множВещ)
       И
        (x.тип = Reg )
       И
        (xродв В {вЯчейка,вЗнак,вЦел8,вЦел16,вЦел32,вЦел64,вМнож,вДоступ,вЗадача})
  ТО
    СК.RegToFStk(x)
  АЕСЛИ
        (xродв В множВещ)
       И
        (x.тип = FStk)
       И
        (родв  В {вЯчейка,вЗнак,вЦел8,вЦел16,вЦел32,вЦел64,вМнож,вДоступ,вЗадача})
  ТО
    СК.FStkToReg(x)
  КОН;
  x.вид:=вид
КОН SYSval;
          
(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ValToAdr(x+:ЗК.нItem);
(*
 *  Цель: переводит значение из 'x' в register indirect memory reference
 *    До: x.тип В {пПер,пПрСсылки,пПост,FStk,Reg,Abs,RegI,RegX,Inx,Coc}
 *        x.вид.родв В {вЯчейка,вКлюч,вЗнак,вЦел8,вЦел16,вЦел32,вЦел64,
 *                                                 вМнож,вВещ32,вВещ64}
 * После: x.тип=RegI
 *)
ПЕР
  h:ЗК.нItem;
УКАЗ
  СК.ValToReg(x);
  x.disp:=0;
  x.тип:=RegI
КОН ValToAdr;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       SYSgetput-(x+,y+:ЗК.нItem; get:КЛЮЧ);
УКАЗ
  ЕСЛИ get ТО
    ValToAdr(y);
    СК.LoadAdr(x);
    y.вид:=x.вид
  ИНАЧЕ
    ValToAdr(x);
    x.вид:=y.вид
  КОН;
  Assign(x,y)
КОН SYSgetput;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       SYSmove-(x+,y+,z+:ЗК.нItem);                 (*  Цель: x:=z bytes of y *)
УКАЗ
  ValToAdr(x);
  ValToAdr(y);
  СК.MoveBlock(x,y,z)
КОН SYSmove;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Подготовить-;
УКАЗ
  сохрРегиД:=ПУСТО
КОН Подготовить;

КОН КУ.
 