(*~\Глагол\Приложения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;



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

ЗАДАЧА ^DeRef-(x+:ЗК.нItem);
ЗАДАЧА ^Index-(x+,y+:ЗК.нItem);
ЗАДАЧА ^ValToReg-(x+:ЗК.нItem);


(*=рррррррррррррррррррррррр= реализация задач =рррррррррррррррррррррррррррррр=*)


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ClearReg-(reg:ЦЕЛ);
(*
 *  Цель: erase register
 *    До: reg: a correct register
 * После: VALUE(reg)=0
 *)
ПЕР
  h:ЗК.нItem;
УКАЗ
  h.тип:=Reg;
  h.bas:=reg;
  ЗК.PutORM(031H,h.bas,h) (* XOR Ed,Gd *)
КОН ClearReg;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА CocToReg-(x+:ЗК.нItem);
(*
 *  Цель: item-transfer
 *    До: x.reloc = Coc
 * После: x.тип = Reg
 *)
ПЕР
  L1:ЗК.Label;
УКАЗ
  L1:=0;
  x.тип:=Reg;
  x.bas:=МР.ЗанятьЯчРег();
  ЗК.PutJmpCF(x.reloc,x.адр);   (* Tjmp *)
  ЗК.FixLink(x.disp);           (* Fjmp here *)
  ЗК.PutOMD(4,0C7H,0H,x,0);     (* MOV Ed,Id *)
  ЗК.PutJmpF(L1);
  ЗК.FixLink(x.адр);            (* Tjmp here *)
  ЗК.PutOMD(4,0C7H,0H,x,1);     (* MOV Ed,Id *)
  ЗК.FixLink(L1)
КОН CocToReg;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА IncAdr-(x+:ЗК.нItem; смещение:ЦЕЛ);
(*
 *  Цель: increment address of item
 *    До: x.тип В {Abs,RegI,RegX,Inx}
 *        смещение: number of bytes to increment
 * После: x.тип В {Abs,RegI,RegX,Inx}
 *)
УКАЗ
  ЕСЛИ x.тип В {Abs,AbsRel} ТО
    УВЕЛИЧИТЬ(x.адр,смещение)
  ИНАЧЕ
    УВЕЛИЧИТЬ(x.disp,смещение)
  КОН
КОН IncAdr;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА LoadBaseAdr-(x+:ЗК.нItem);
(*
 *  Цель: load опора-address on stack
 *    До: x.тип В {пПер,пПрСсылки,DArr}, 0 < x.уровень <= ЗК.уровень
 * После: x.тип = RegI, x is опора-address on stack
 *)
ПЕР
  y:ЗК.нItem;
УКАЗ
  ЕСЛИ x.уровень = ЗК.уровень ТО  (* local variable is in own SS *)
    x.bas:=МР.ЗанятьОпредРег({EBP})
  ИНАЧЕ                         (* access over static след *)
    y.тип:=RegI;
    y.bas:=МР.ЗанятьОпредРег({EBP});
    y.disp:=-4*x.уровень;
    x.bas:=МР.ЗанятьРег();
    ЗК.PutORM(08BH,x.bas,y); (* MOV r32,r/m32 *)
    МР.ОсвободитьРег(y.bas)
  КОН;
  x.тип:=RegI;
  x.disp:=x.адр
КОН LoadBaseAdr;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА VarParToRegI(x+:ЗК.нItem);
(*
 *  Цель: item-transfer
 *    До: x.тип = пПрСсылки
 * После: x.тип = RegI
 *)
УКАЗ
  LoadBaseAdr(x);
  ЕСЛИ x.вид.родв = вНабор ТО IncAdr(x,4) КОН; (* jump over typtag *)
  DeRef(x)
КОН VarParToRegI;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА VarToAdr(x+:ЗК.нItem);
(*
 *  Цель: item-transfer
 *    До: x.тип = пПер
 * После: x.тип В {RegI,Abs,AbsRel}
 *)
УКАЗ
  ЕСЛИ x.уровень <= 0 ТО (* <0 imported variable from another module *)
    x.тип:=AbsRel;      (* =0 global variable in own data section *)
    x.disp:=0;
    x.reloc:=Coff.СКР_ПЕР;
    x.relocInx:=-x.уровень
  ИНАЧЕ                   (* local variable on stack *)
    LoadBaseAdr(x);
    ЕСЛИ x.вид.родв = вОРяд ТО DeRef(x) КОН
  КОН
КОН VarToAdr;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА VarToRegI(x+:ЗК.нItem);
(*
 *  Цель: item-transfer
 *    До: x.тип = пПер
 * После: x.тип = RegI
 *)
УКАЗ
  VarToAdr(x);
  ЕСЛИ x.тип В {Abs,AbsRel} ТО
    x.тип:=Reg;
    x.bas:=МР.ЗанятьРег();
    ЗК.PutOMD(4,0C7H,0H,x,x.адр); (* MOV Ed,Id *)
    x.тип:=RegI;
    x.disp:=0;
    ЕСЛИ x.тип = AbsRel ТО
      Coff.СоздатьСкр(Coff.Код,x.reloc,x.relocInx,ЗК.pc-4)
    КОН
  КОН;
  ПРОВЕРИТЬ(x.тип = RegI)
КОН VarToRegI;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА DArrToAdr(x+:ЗК.нItem);
(*
 *  Цель: item-transfer
 *    До: x.тип = DArr
 * После: x.тип В {RegI,RegX}
 *)
ПЕР
  h:ЗК.нItem;
УКАЗ
  h.тип:=пПост;
  h.адр:=0;
  h.уровень:=0;
  ПОКА x.тип = DArr ВЫП Index(x,h) КОН
КОН DArrToAdr;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА IgnoreDynArrDesc-(x+:ЗК.нItem);
(*
 *  Цель: gets the start address for data of a dynamic array
 *)
УКАЗ
  ЕСЛИ (x.вид.родв = вОРяд) И (x.тип = RegI) И (x.disp = 0) ТО
    x.disp:=x.вид.размер
  КОН
КОН IgnoreDynArrDesc;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА LoadAdr-(x+:ЗК.нItem);
(*
 *  Цель: item-transfer
 *    До: x.тип В {пПер,пПрСсылки,StrCon,DArr,Abs,Reg,RegI,RegX,Inx,FStk}
 * После: x.тип В {Abs,Reg,RegI,RegX,Inx,пПост(but no strings),FStk}  
 *)
УКАЗ
  ВЫБРАТЬ x.тип ИЗ
    пПрСсылки:
      VarParToRegI(x)
  | пПер:
      VarToAdr(x)
  | DArr:
      DArrToAdr(x)
  | пПост:
      ПРОВЕРИТЬ(x.вид.родв В ({вПЦепь}+множВещ)); 
      x.тип:=AbsRel;
      x.disp:=0;
      x.reloc:=Coff.СКР_ПОСТ;
      x.relocInx:=-x.уровень;
      ПРОВЕРИТЬ((x.relocInx >= 0) И (x.relocInx < ВД.ВсегоОтделов))
  ИНАЧЕ
    ПРОВЕРИТЬ(x.тип В {FStk,Reg,Abs,RegI,RegX,Inx,AbsRel,RegIRel,RegXRel,InxRel})
  КОН
КОН LoadAdr;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА AdrToRegI-(x+:ЗК.нItem);
(*
 *  Цель: item-transfer
 *    До: x.тип В {пПер,пПрСсылки,StrCon,Abs,RegI,RegX,Inx,DArr}
 * После: x.тип = RegI,RegIRel
 *)
ПЕР
  y:ЗК.нItem;
  тип:ЦЕЛ;
УКАЗ
  LoadAdr(x);
  тип:=x.тип;
  ЕСЛИ тип В {RegIRel,RegI} ТО ВОЗВРАТ КОН;
  ВЫБРАТЬ тип ИЗ
  | Abs,AbsRel:
      x.тип:=Reg;
      x.bas:=МР.ЗанятьРег();
      ЗК.PutOMD(4,0C7H,0H,x,x.адр); (* MOV Ed,Id *)
      ЕСЛИ тип = AbsRel ТО
        Coff.СоздатьСкр(Coff.Код,x.reloc,x.relocInx,ЗК.pc-4)
      КОН
  | RegX,RegXRel:
      ЕСЛИ МР.СтекРег(x.bas) ТО
        y.bas:=МР.ЗанятьРег();
        ЗК.PutORM(08DH,y.bas,x); (* LEA Gd,M *)
        МР.ОсвободитьРег(x.bas)
      ИНАЧЕ
        y.bas:=x.bas;
        ЗК.PutORM(08DH,y.bas,x); (* LEA Gd,M *)
      КОН;
      МР.ОсвободитьРег(x.inx);
      x.bas:=y.bas
  | Inx,InxRel:
      ЗК.PutORM(08DH,x.inx,x); (* LEA Gd,M *)
      x.bas:=x.inx
  КОН;
  x.disp:=0;
  x.тип:=RegI
КОН AdrToRegI;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА AdrToRegIDisp0-(x+:ЗК.нItem;
                 baseReg :ЦЕЛ);
(*
 *    До: x.тип В {пПер,пПрСсылки,StrCon,Abs,RegI,RegX,Inx,DArr}
 * После: x.тип = RegI, x.disp = 0
 *        IF baseReg >= 0 THEN x.bas.м = 'baseReg'
 *        ELSE x.bas.м = a general register
 *)
ПЕР
  y:ЗК.нItem;
УКАЗ
  AdrToRegI(x);
  (* x.тип В {RegI,RegIRel} *)
  ЕСЛИ x.disp # 0 ТО
    y.тип:=Reg;
    ЕСЛИ МР.СтекРег(x.bas) ТО
      ЕСЛИ baseReg < 0 ТО
        y.bas:=МР.ЗанятьРег()
      ИНАЧЕ
        y.bas:=МР.ЗанятьОпредРег({baseReg})
      КОН;
      ЗК.PutORM(08DH,y.bas,x); (* LEA r32,M *)
      МР.ОсвободитьРег(x.bas)
    ИНАЧЕ
      y.bas:=x.bas;
      ЗК.PutOMD(4,081H,0H,y,x.disp); (* ADD r/m32,imm32 *)
      ЕСЛИ x.тип=RegIRel ТО
        Coff.СоздатьСкр(Coff.Код,x.reloc,x.relocInx,ЗК.pc-4)
      КОН
    КОН;
    x.bas:=y.bas
  АЕСЛИ x.тип = RegIRel ТО
    y.тип:=Reg;
    y.bas:=x.bas;
    ЗК.PutOMD(4,081H,0H,y,0); (* ADD r/m32,imm32 *)
    Coff.СоздатьСкр(Coff.Код,x.reloc,x.relocInx,ЗК.pc-4)
  КОН;
  ЕСЛИ baseReg >= 0 ТО МР.РегВОпредМРег(x.bas,baseReg) КОН;
  x.тип:=RegI;
  x.disp:=0
КОН AdrToRegIDisp0;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА RegToFStk-(x+:ЗК.нItem);
(*
 *  Цель: перенести содержимое регистра в стек мат. регистров (для ОБХОД.Значение)
 *    До: x.тип = Reg
 * После: x.тип = FStk
 *)
ПЕР
  родв:ЦЕЛ;
  врег:ЦЕЛ;
  y:ЗК.нItem;
УКАЗ
       родв:=x.вид.родв; 
  ЕСЛИ
       родв = вЦел64
  ТО                         (*64*)
    врег:=МР.ЗанятьВРег64()
  ИНАЧЕ
    врег:=МР.ЗанятьВРег()
  КОН;
  y.тип:=RegI;
  y.bas:=МР.ЗанятьОпредРег({EBP});
  y.disp:=-ЗК.virtRegOffs-4*врег;
  ЗК.PutORM(089H,x.bas,y); (* MOV r/m32,r32 *)
  МР.ОсвободитьРег(x.bas);
  ЕСЛИ
       родв = вЦел64
  ТО                         (*64*)
    IncAdr(y,4);
    ЗК.PutORM(089H,x.inx,y); (* MOV r/m32,r32 *)
    МР.ОсвободитьРег(x.inx);
    IncAdr(y,-4)
  КОН;
  x:=y;
  МР.УвМатМРегов;
  ЕСЛИ
       родв = вЦел64
  ТО
    ЗК.PutOM(0DDH,0H,x); (* FLD El *)
    МР.ОсвободитьВРег64(врег)
  ИНАЧЕ
    ЗК.PutOM(0D9H,0H,x); (* FLD Es *)
    МР.ОсвободитьВРег(врег)
  КОН;
  ЗК.Release(x);
  x.тип:=FStk
КОН RegToFStk;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА FStkToReg-(x+:ЗК.нItem);
(*
 *  Цель: перенести содержимое мат. регистра в регистр (для ОБХОД.Значение)
 *    До: x.тип = FStk
 * После: x.тип = Reg
 *)
ПЕР
  родв:ЦЕЛ;
  врег:ЦЕЛ;
  y:ЗК.нItem;
УКАЗ
  родв:=x.вид.родв; 
  ЕСЛИ родв = вВещ64 ТО
    врег:=МР.ЗанятьВРег64()
  ИНАЧЕ
    врег:=МР.ЗанятьВРег()
  КОН;
  y.тип:=RegI;
  y.bas:=МР.ЗанятьОпредРег({EBP});
  y.disp:=-ЗК.virtRegOffs-4*врег;
  МР.УмМатМРегов;
  ЕСЛИ родв = вВещ64 ТО
    ЗК.PutOM(0DDH,3H,y); (* FSTP El *)
    y.вид:=ВД.цел64вид
  ИНАЧЕ
    ЗК.PutOM(0D9H,3H,y); (* FSTP Es *)
    y.вид:=ВД.цел32вид
  КОН;
  ЗК.Release(x);
  x:=y;
  ValToReg(x);
  ЕСЛИ родв = вВещ64 ТО
    МР.ОсвободитьВРег64(врег)
  ИНАЧЕ
    МР.ОсвободитьВРег(врег)
  КОН
КОН FStkToReg;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ValToFStk-(x+:ЗК.нItem);
(*
 *  Цель: загрузить значение 'x' в стек мат. регистров
 *    До: x.тип В {пПер,пПрСсылки,пПост,Reg,Abs,RegI,RegX,Inx,FStk}
 *     (* x.вид.родв В {вЯчейка,вКлюч,вЦел8,вЗнак,вЦел16,вЦел32,вЦел64,вМнож,вВещ32,вВещ64} *)
 *        x.вид.родв В {вЦел32,вЦел64,вВещ32,вВещ64}
 * После: x.тип = FStk
 *)
ПЕР
  родв:ЦЕЛ;
  испврег:КЛЮЧ;
  врег:ЦЕЛ;
  y:ЗК.нItem;
УКАЗ
  ЕСЛИ x.тип = FStk ТО ВОЗВРАТ КОН;
  родв:=x.вид.родв;
  ЕСЛИ родв В множВещ ТО
    ЕСЛИ x.тип = пПост ТО
      x.тип:=AbsRel;
      x.reloc:=Coff.СКР_ПОСТ;
      x.relocInx:=0
    ИНАЧЕ
      LoadAdr(x)
    КОН
  ИНАЧЕ
    ValToReg(x)
  КОН;
  (* x.тип В {Abs,Reg,RegI,RegX,Inx} *)
  испврег:=x.тип = Reg;
  ЕСЛИ испврег ТО
    ЕСЛИ родв = вЦел64 ТО (*64*)
      врег:=МР.ЗанятьВРег64()
    ИНАЧЕ
      врег:=МР.ЗанятьВРег();
      родв:=вЦел32
    КОН;
    y.тип:=RegI;
    y.bas:=МР.ЗанятьОпредРег({EBP});
    y.disp:=-ЗК.virtRegOffs-4*врег;
    ЗК.PutORM(089H,x.bas,y); (* MOV r/m32,r32 *)
    МР.ОсвободитьРег(x.bas);
    ЕСЛИ родв = вЦел64 ТО (*64*)
      IncAdr(y,4);
      ЗК.PutORM(089H,x.inx,y); (* MOV r/m32,r32 *)
      МР.ОсвободитьРег(x.inx);
      IncAdr(y,-4)
    КОН;
    x:=y
  КОН;
  (* x.тип В {Abs,RegI,RegX,Inx} *)
  ВЫБРАТЬ родв ИЗ
  | вЦел32: ЗК.PutOM(0DBH,0H,x) (* FILD Ed *)
  | вЦел64: ЗК.PutOM(0DFH,5H,x) (* FILD Eq *) (*64*)
  |  вВещ32: ЗК.PutOM(0D9H,0H,x) (* FLD Es *)
  | вВещ64: ЗК.PutOM(0DDH,0H,x) (* FLD El *)
  КОН;
  ЗК.Release(x);
  ЕСЛИ испврег ТО
    ЕСЛИ родв = вЦел64 ТО (*64*)
      МР.ОсвободитьВРег64(врег)
    ИНАЧЕ
      МР.ОсвободитьВРег(врег)
    КОН
  КОН;
  МР.УвМатМРегов;
  x.тип:=FStk
КОН ValToFStk;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
(*64*)
(*16*)
ЗАДАЧА ValToReg-(x+:ЗК.нItem);
(*
 *  Цель: load value of 'x' in cpu-register
 *    До: x.тип      В {пПер,пПрСсылки,пПост,Reg,Abs,RegI,RegX,Inx,Coc}
 *        x.вид.родв В {вЯчейка,вКлюч,вЦел8,вЗнак,вЦел16,вЦел32,вЦел64,вМнож}
 * После: x.тип = Reg
 *)
ПЕР
  y:ЗК.нItem;
  freexbas:КЛЮЧ;
  родв:ЦЕЛ;
УКАЗ
  ЕСЛИ x.тип = Reg ТО ВОЗВРАТ КОН;
  ЕСЛИ x.тип = Coc ТО CocToReg(x); ВОЗВРАТ КОН;
  родв:=x.вид.родв;
  ПРОВЕРИТЬ(НЕ (родв В ({вПЦепь}+множВещ)));
  ЕСЛИ x.тип = пПост ТО
    x.тип:=Reg;
    ЕСЛИ родв = вЦел64 ТО (*64*)
      x.bas:=МР.ЗанятьРег();
      ЗК.PutOMD(4,0C7H,0H,x,x.disp); (* MOV Ed,Id *)
      x.inx:=x.bas
    КОН;
    x.bas:=МР.ЗанятьРег();
    ЗК.PutOMD(4,0C7H,0H,x,x.адр); (* MOV Ed,Id *)
  ИНАЧЕ
    freexbas:=ОТКЛ;
    LoadAdr(x);
    (* x.тип В {Abs,RegI,RegX,Inx} *)
    ЕСЛИ родв = вЦел64 ТО (*64*)
      ЕСЛИ x.тип В {Inx,InxRel,RegX,RegXRel} ТО
        y.inx:=x.inx
      АЕСЛИ (x.тип В {Abs,AbsRel}) ТО
        y.inx:=МР.ЗанятьРег()
      ИНАЧЕ (* RegI *)
        ЕСЛИ МР.СтекРег(x.bas) ТО
          freexbas:=ВКЛ;
          y.inx:=МР.ЗанятьРег()
        ИНАЧЕ
          y.inx:=x.bas
        КОН;
      КОН;
      y.bas:=МР.ЗанятьРег();
      ЗК.PutORM(08BH,y.bas,x);   (* MOV Gd,Ed *)
      IncAdr(x,4);
      ЗК.PutORM(08BH,y.inx,x);   (* MOV Gd,Ed *)
      x.inx:=y.inx
    ИНАЧЕ
      ЕСЛИ x.тип В {Inx,InxRel,RegX,RegXRel} ТО
        y.bas:=x.inx
      АЕСЛИ (x.тип В {Abs,AbsRel}) ТО
        y.bas:=МР.ЗанятьРег()
      ИНАЧЕ (* RegI *)
        ЕСЛИ МР.СтекРег(x.bas) ТО
          freexbas:=ВКЛ;
          y.bas:=МР.ЗанятьРег()
        ИНАЧЕ
          y.bas:=x.bas
        КОН;
      КОН;
      ЕСЛИ x.вид.размер = 1 ТО
        ЕСЛИ родв = вЦел8 ТО
          ЗК.PutORM(0FBEH,y.bas,x) (* MOVSX Gd,Eb *)
        ИНАЧЕ
          ЗК.PutORM(0FB6H,y.bas,x) (* MOVZX Gd,Eb *)
        КОН
      АЕСЛИ x.вид.размер = 2 ТО
        ЕСЛИ родв = вЦел16 ТО
          ЗК.PutORM(0FBFH,y.bas,x) (* MOVSX Gd,Ew *)
        ИНАЧЕ
          ЗК.PutORM(0FB7H,y.bas,x) (* MOVZX Gd,Ew *)
        КОН
      ИНАЧЕ
        ЗК.PutORM(08BH,y.bas,x)  (* MOV Gd,Ed *)
      КОН
    КОН;
    ЕСЛИ freexbas ИЛИ (x.тип В {RegX,RegXRel}) ТО
      МР.ОсвободитьРег(x.bas)
    КОН;
    x.bas:=y.bas;
  КОН;
  x.тип:=Reg;
КОН ValToReg;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
(*64*)
ЗАДАЧА RealToInt-(x+:ЗК.нItem; шир:КЛЮЧ);
(*
 *  Цель: преобразование видов
 *    До: x.вид.родв В {вВещ32,вВещ64}
 * После: x.тип = Reg
 *        x.вид.родв = вЦел64, если <шир>=ВКЛ
 *        x.вид.родв = вЦел32,  если <шир>=ОТКЛ
 *)
ПЕР
  y:ЗК.нItem;
  L1:ЗК.Label;
  врег:ЦЕЛ;
УКАЗ
  ValToFStk(x);
  ЕСЛИ шир ТО
    врег:=МР.ЗанятьВРег64()
  ИНАЧЕ
    врег:=МР.ЗанятьВРег()
  КОН;
  y.тип:=RegI;
  y.bas:=МР.ЗанятьОпредРег({EBP});
  y.disp:=-ЗК.virtRegOffs-4*врег;
  МР.УмМатМРегов;
  ЕСЛИ шир ТО
    ЗК.PutOM(0DFH,7H,y)       (* FISTP Eq *)
  ИНАЧЕ
    ЗК.PutOM(0DBH,3H,y)       (* FISTP Ed *)
  КОН;
  ЕСЛИ НП.клПровПределов ТО
    x.тип:=Reg;
    x.bas:=МР.ЗанятьОпредРег({EAX});
    ЗК.PutB(09BH);            (* WAIT *)
    ЗК.PutO(0DFE0H);          (* FSTSW AX *)
    ЗК.PutO(0A801H);          (* TEST AL,1  *)
    МР.ОсвободитьРег(x.bas);
    L1:=0;
    ЗК.PutJmpCF(LEQ,L1);
    ЗК.Ловушка(пределыАвОст);
    ЗК.FixLink(L1)
  КОН;
  x.тип:=Reg;
  x.bas:=МР.ЗанятьРег();
  ЗК.PutORM(08BH,x.bas,y); (* MOV Gd,Ed *)
  ЕСЛИ шир ТО
    IncAdr(y,4);
    x.inx:=МР.ЗанятьРег();
    ЗК.PutORM(08BH,x.inx,y) (* MOV Gd,Ed *)
  КОН;
  МР.ОсвободитьРег(y.bas);
  ЕСЛИ шир ТО
    МР.ОсвободитьВРег64(врег)
  ИНАЧЕ
    МР.ОсвободитьВРег(врег)
  КОН
КОН RealToInt;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА LoadSize-(x+,s+:ЗК.нItem);
(*
 *  Цель: загрузить размер (ячеек) 'x' в 's'
 *    До: x.тип В {пПер,пПрСсылки,StrCon,DArr,RegI}
 * После: s.тип В {пПост,Reg}, x не изменяется
 *)
ПЕР
  опора,h:ЗК.нItem;
  basedisp:ЦЕЛ;

 (*.............................................подЗАДАЧА...*)
  ЗАДАЧА DynArrSize(вид:ВД.ДкВиду);
  ПЕР
    овид:ВД.ДкВиду;
  УКАЗ
    ЕСЛИ вид.родв = вОРяд ТО
      овид:=вид.овид;
      DynArrSize(овид);
      опора.disp:=basedisp+вид.адрОВ;
      ЕСЛИ (овид.родв = вОРяд) ИЛИ (овид.размер # 1) ТО
        ЗК.PutORM(08BH,h.bas,опора);    (* MOV Gd,Ed *)
        ЗК.PutORM(0FAFH,s.bas,h)        (* IMUL Gd,Ed *)
      ИНАЧЕ
        ЗК.PutORM(08BH,s.bas,опора)     (* MOV Gd,Ed *)
      КОН
    АЕСЛИ вид.размер # 1 ТО
      ЗК.PutOMD(4,0C7H,0H,s,вид.размер) (* MOV Ed,Id *)
    КОН
  КОН DynArrSize;

УКАЗ
  s.вид:=ВД.цел32вид;
  ЕСЛИ x.вид.родв = вПЦепь ТО
    s.тип:=пПост;
    s.адр:=x.disp*НП.рЗнак;
    s.уровень:=0
  АЕСЛИ x.вид.родв # вОРяд ТО
    s.тип:=пПост;
    s.адр:=x.вид.размер;
    s.уровень:=0
  ИНАЧЕ (* x.вид.родв=вОРяд, see also PushDynArrDesc *)
    s.тип:=Reg;
    s.bas:=МР.ЗанятьРег();
    h.тип:=Reg;
    h.bas:=МР.ЗанятьРег();
    ЕСЛИ (x.тип = DArr) И (x.disp = RegI) ТО
      опора.тип:=RegI;
      опора.bas:=x.inx;
      basedisp:=0;
      DynArrSize(x.вид)
    АЕСЛИ x.тип В {RegI,RegIRel} ТО
      опора.тип:=x.тип;
      опора.bas:=x.bas;
      basedisp:=0;
      опора.reloc:=x.reloc;
      опора.relocInx:=x.relocInx;
      DynArrSize(x.вид)
    ИНАЧЕ
      опора.уровень:=x.уровень;
      LoadBaseAdr(опора);
      basedisp:=x.адр;
      DynArrSize(x.вид);
      ЗК.Release(опора)
    КОН;
    МР.ОсвободитьРег(h.bas)
  КОН
КОН LoadSize;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ПроверкаГраницШ(н+:ЗК.нItem;
                     отн,
                     дон,
                  номЛов :ЦЕЛ);
(*
 *  Цель: код для проверки значения <н> по границе [отн,дон]
 *    До: н.вид.родв = вЦел64
 *)
ПЕР
  L1,L2,L3:ЗК.Label;
  отв,дов:ЦЕЛ;  (* верхние разряды границы *)
  в:ЗК.нItem;   (* верхние разряды <н> *)
УКАЗ
  ЕСЛИ отн < 0 ТО отв:=-1 ИНАЧЕ отв:=0 КОН;
  ЕСЛИ дон < 0 ТО дов:=-1 ИНАЧЕ дов:=0 КОН;
  ЕСЛИ н.тип = Reg ТО
    в.тип:=Reg;
    в.bas:=н.inx
  ИНАЧЕ
    в:=н;
    IncAdr(в,4)
  КОН;
  L1:=0; L2:=0; L3:=0;
  ЗК.PutOMD(4,081H,7H,в,отв); (* CMP Ed,Id *)
  ЗК.PutJmpCF(LSS,L1);
  ЗК.PutJmpCF(GTR,L3);
  ЗК.PutOMD(4,081H,7H,н,отн); (* CMP Ed,Id *)
  ЗК.PutJmpCF(LSS,L1);
  ЗК.FixLink(L3);
  ЗК.PutOMD(4,081H,7H,в,дов); (* CMP Ed,Id *)
  ЗК.PutJmpCF(LSS,L2);
  ЗК.PutJmpCF(GTR,L1);
  ЗК.PutOMD(4,081H,7H,н,дон); (* CMP Ed,Id *)
  ЗК.PutJmpCF(LEQ,L2);
  ЗК.FixLink(L1);
  ЗК.Ловушка(номЛов);
  ЗК.FixLink(L2)
КОН ПроверкаГраницШ;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ПроверкаГраниц(x+:ЗК.нItem;
                     от,
                     до,
                 номЛов :ЦЕЛ);
(*
 *  Цель: код для проверки значения <x> по границе [от,до]
 *    до: x.вид.родв # вЦел64
 *)
ПЕР
  L1,L2:ЗК.Label;
УКАЗ
  L1:=0; 
  L2:=0;
  ЗК.PutOMD(4,081H,7H,x,от); (* CMP Ed,Id *)
  ЗК.PutJmpCF(LSS,L1);
  ЗК.PutOMD(4,081H,7H,x,до); (* CMP Ed,Id *)
  ЗК.PutJmpCF(LEQ,L2);
  ЗК.FixLink(L1);
  ЗК.Ловушка(номЛов);
  ЗК.FixLink(L2)
КОН ПроверкаГраниц;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА CheckRange-(x+:ЗК.нItem;
                родв :ЦЕЛ);
(*  Цель: код для проверки значения <x> по границе [от,до] *)
УКАЗ
  ЕСЛИ x.вид.родв = вЦел64 ТО
    ВЫБРАТЬ родв ИЗ
      вМнож: ПроверкаГраницШ(x,0,НП.МаксМнож,пределыАвОст)
    | вЗнак: ПроверкаГраницШ(x,НП.МинЗнак,НП.МаксЗнак,пределыАвОст)
    | вЦел8: ПроверкаГраницШ(x,НП.МинЦел8,НП.МаксЦел8,пределыАвОст)
    | вЦел16:ПроверкаГраницШ(x,НП.МинЦел16,НП.МаксЦел16,пределыАвОст)
    | вЦел32:ПроверкаГраницШ(x,НП.МинЦел32,НП.МаксЦел32,пределыАвОст)
    ИНАЧЕ
    КОН
  ИНАЧЕ
    ВЫБРАТЬ родв ИЗ
      вМнож: ПроверкаГраниц(x,0,НП.МаксМнож,пределыАвОст)
    | вЗнак: ПроверкаГраниц(x,НП.МинЗнак,НП.МаксЗнак,пределыАвОст)
    | вЦел8: ПроверкаГраниц(x,НП.МинЦел8,НП.МаксЦел8,пределыАвОст)
    | вЦел16:ПроверкаГраниц(x,НП.МинЦел16,НП.МаксЦел16,пределыАвОст)
    ИНАЧЕ
    КОН
  КОН
КОН CheckRange;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ПроверкаУРяда(x+,y+:ЗК.нItem);
(*
 *  Цель: код для проверки номера слагаемого ряда
 *    До: x.вид = родв ряда
 *        y = проверяемый номер
 *)
УКАЗ
  ПроверкаГраниц(y,0,x.вид.n-1,номерАвОст)
КОН ПроверкаУРяда;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ПроверкаУОРяда(x+,y+:ЗК.нItem);
(*
 *  Цель: код для проверки номера слагаемого открытого ряда
 *    До: <x> = адрес длины ряда
 *        <y> = проверяемый номер, y.тип = Reg
 *)
ПЕР
  L1,L2:ЗК.Label;
УКАЗ
  L1:=0; L2:=0;
  ЗК.PutOMD(4,081H,7H,y,0); (* CMP Ed,Id *)   (* i ? 0 *)
  ЗК.PutJmpCF(LSS,L1);
  ЗК.PutORM(039H,y.bas,x);  (* CMP r/m32,r32 *)  (* LEN ? i *)
  ЗК.PutJmpCF(GTR,L2);
  ЗК.FixLink(L1);
  ЗК.Ловушка(номерАвОст);
  ЗК.FixLink(L2)
КОН ПроверкаУОРяда;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА CheckOvfl-;
(*  Цель: code for overflow-check *)
ПЕР
  L1:ЗК.Label;
УКАЗ
  ЕСЛИ НП.клПровПереполн ТО
    L1:=0;
    ЗК.PutJmpCF(NOV,L1); (* jump if no ovfl *)
    ЗК.Ловушка(арифмАвОст);
    ЗК.FixLink(L1)
  КОН
КОН CheckOvfl;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА SetCoc-(x+:ЗК.нItem; cc:ЦЕЛ);
(*
 *  Цель: initialize item with condition
 *    До: cc = condition 
 * После: x = initialized item                                  
 *)
УКАЗ
  x.тип:=Coc;
  x.вид:=ВД.ключвид;
  x.reloc:=cc;
  x.адр:=0;
  x.disp:=0
КОН SetCoc;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА InvertedCoc-(cc:ЦЕЛ):ЦЕЛ;
(*
 *  Цель: invert the meaning of condition
 *    До: cc:condition
 * После: RETURN:inverted condition. (x cc y) = ~ (x RETURN y)
 *)
УКАЗ
  ЕСЛИ НЕ ЧЕТ(cc) ТО ВОЗВРАТ cc-1 ИНАЧЕ ВОЗВРАТ cc+1 КОН
КОН InvertedCoc;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ExchangedCoc-(cc:ЦЕЛ):ЦЕЛ;
(*
 *  Цель: return condition after change of лево and право hand side
 *    До: cc:condition
 * После: RETURN:condition after exchange. (x cc y) = (y RETURN x)
 *)
УКАЗ
  ВЫБРАТЬ cc ИЗ
    LSS:ВОЗВРАТ GTR
  | GEQ:ВОЗВРАТ LEQ
  | LEQ:ВОЗВРАТ GEQ
  | GTR:ВОЗВРАТ LSS
  ИНАЧЕ ВОЗВРАТ cc
  КОН
КОН ExchangedCoc;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА UnsignedCoc-(cc:ЦЕЛ):ЦЕЛ;
(*
 *  Цель: return condition for unsigned (or float) compare
 *    До: cc:condition
 * После: RETURN condition for unsigned compare
 *)
УКАЗ
  ВЫБРАТЬ cc ИЗ
    LSS:ВОЗВРАТ ULSS
  | GEQ:ВОЗВРАТ UGEQ
  | LEQ:ВОЗВРАТ ULEQ
  | GTR:ВОЗВРАТ UGTR
  ИНАЧЕ ВОЗВРАТ cc
  КОН
КОН UnsignedCoc;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА BoolToCoc-(x+:ЗК.нItem);
(*
 *  Цель: item-transfer
 *    До: x.тип В {пПер,пПрСсылки,пПост,Reg,Abs,RegI,RegX,Inx}
 * После: x.тип = Coc
 *)
УКАЗ
  ЕСЛИ x.тип = пПост ТО
    ЕСЛИ x.адр = 1 ТО SetCoc(x,ALWAYS) ИНАЧЕ SetCoc(x,NEVER) КОН
  ИНАЧЕ
    LoadAdr(x);
    ЕСЛИ x.тип = Reg ТО
      ЗК.PutOMD(1,083H,7H,x,1) (* CMP Ed,Ib *)
    ИНАЧЕ
      ЗК.PutOMD(1,080H,7H,x,1) (* CMP Eb,Ib *)
    КОН;
    ЗК.Release(x);
    SetCoc(x,EQL)
  КОН
КОН BoolToCoc;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА MoveBlockS-(x+,y+:ЗК.нItem; размер:ЦЕЛ);
(*
 *  Цель: move 'размер' bytes from 'y' to 'x'
 *    До: x, y: addresses
 *        размер: number of bytes to move
 * После: x[i]:=y[i] for i = 0 .. размер - 1
 *)
ПЕР
  z:ЗК.нItem;
  n:ЦЕЛ;
УКАЗ
  LoadAdr(x);
  LoadAdr(y);
  z.тип:=Reg;
  ЕСЛИ размер = 1 ТО
    z.bas:=МР.ЗанятьЯчРег();
    ЗК.PutORM(08AH,z.bas,y); (* MOV Gb,Eb *)
    ЗК.PutORM(088H,z.bas,x)  (* MOV Eb,Gb *)
  АЕСЛИ размер = 4 ТО
    z.bas:=МР.ЗанятьРег();
    ЗК.PutORM(08BH,z.bas,y); (* MOV Gd,Ed *)
    ЗК.PutORM(089H,z.bas,x)  (* MOV Ed,Gd *)
  ИНАЧЕ
    AdrToRegIDisp0(y,ESI);
    AdrToRegIDisp0(x,EDI);
    z.bas:=МР.ЗанятьОпредРег({ECX});
    ЗК.PutOMD(4,0C7H,0H,z,размер ДЕЛИТЬ 4); (* MOV Ed,Id *)
    ЗК.PutO(0F3A5H);                        (* REPE MOVSW/D *)
    ПОКА (размер ОСТАТОК 4) # 0 ВЫП
      ЗК.PutO(0A4H);                        (* MOVSB *)
      УМЕНЬШИТЬ(размер)
    КОН
  КОН;
  МР.ОсвободитьРег(z.bas)
КОН MoveBlockS;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА MoveBlock-(x+,y+,z+:ЗК.нItem);
(*
 *  Цель: move 'z' bytes from 'y' to 'x'
 *    До: x,y:addresses
 *        z:number of bytes to move
 * После: x[i]:=y[i] for i = 0 .. z - 1
 *)
УКАЗ
  ЕСЛИ z.тип = пПост ТО
    MoveBlockS(x,y,z.адр)
  ИНАЧЕ
    ValToReg(z);
    МР.РегВОпредМРег(z.bas,ECX);
    AdrToRegIDisp0(y,ESI);
    AdrToRegIDisp0(x,EDI);
    ЗК.PutO(0F3A4H) (* REPE MOVSB *)
  КОН
КОН MoveBlock;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА AllocStkBlockS-(размер:ЦЕЛ; адр+:ЗК.нItem);
(*
 *  Цель: allocates a block of <размер> bytes on stack and returns
 *        in <адр> the starting address of this block.
 *    До: <размер> размер in bytes
 * После: <адр> points to start address, ESP is decremented by <размер>
 *)
ПЕР
  h:ЗК.нItem;
УКАЗ
  h.тип:=Reg;
  h.bas:=МР.ЗанятьОпредРег({ESP});
  (* stack alignment to 4 bytes *)
  ЗК.PutOMD(4,081H,05H,h,размер+(-размер) ОСТАТОК 4); (* SUB r/m32,imm32 *)
  адр.bas:=МР.ЗанятьРег();
  ЗК.PutORM(08BH,адр.bas,h);  (* MOV r32,r/m32 *)
  МР.ОсвободитьРег(h.bas);
  адр.тип:=RegI;
  адр.disp:=0
КОН AllocStkBlockS;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА PushItem-(ap+:ЗК.нItem);
(*
 *  Цель: push addres of actual parameter
 *    До: ap:actual parameter
 *)
УКАЗ
  ЕСЛИ ap.тип = Abs ТО
    ЗК.PutOD(4,068H,ap.адр); (* PUSH Id *)
  АЕСЛИ ap.тип = AbsRel ТО
    ЗК.PutOD(4,068H,ap.адр); (* PUSH Id *)
    Coff.СоздатьСкр(Coff.Код,ap.reloc,ap.relocInx,ЗК.pc-4)
  ИНАЧЕ
    AdrToRegIDisp0(ap,-1);
    ЗК.PutPushReg(ap.bas)
  КОН
КОН PushItem;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА PushAdr-(ap+:ЗК.нItem);
(*
 *  Цель: push address of an actual parameter
 *    До: ap:actual parameter
 *)
УКАЗ
  LoadAdr(ap);
  PushItem(ap)
КОН PushAdr;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА CmpAdr-(memLoc+,
              typeTag+ :ЗК.нItem);
(*
 *  Цель: compare memLoc,адр(typeTag)
 *    До: typeTag.тип in {AbsRel,RegI}
 * После: след instruction emitted was CMP,
 *        if typeTag.тип was RegI:
 *          typeTag.bas:=typeTag.bas+typeTag.disp;
 *          typeTag.disp:=0;
 *)
УКАЗ
  ВЫБРАТЬ typeTag.тип ИЗ
    RegI:
      ЕСЛИ typeTag.disp # 0 ТО
        typeTag.тип:=Reg;
        ЗК.PutOMD(4,081H,0H,typeTag,typeTag.disp); (* ADD r/m32,imm32 *)
        typeTag.disp:=0;
        typeTag.тип:=RegI
      КОН;
      ЗК.PutORM(039H,typeTag.bas,memLoc) (* CMP r/m32,r32 *)
  | AbsRel:
      ЗК.PutOMD(4,081H,7H,memLoc,typeTag.адр); (* CMP r/m32,imm32 *)
      Coff.СоздатьСкр(Coff.Код,typeTag.reloc,typeTag.relocInx,ЗК.pc-4)
  КОН
КОН CmpAdr;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА PushDynArrDesc-(fp+,
                       ap+ :ЗК.нItem);
(*
 *  Цель: занести границы открытого ряда в стек
 *    До: <fp> - formal parameter, <ap> - actual parameter
 *        fp.вид.родв = вОРяд
 *        ap.тип В {пПер,пПрСсылки,StrCon,Abs,RegI,RegX,Inx,DArr}
 *)
ПЕР
  размер,опора:ЗК.нItem;
  basedisp:ЦЕЛ;

 (*.....................................подЗАДАЧА...*)
  ЗАДАЧА PushBnd(ftyp,atyp:ВД.ДкВиду);
  УКАЗ
    ЕСЛИ atyp.родв = вРяд ТО
      ЗК.PutOD(4,068H,atyp.n)   (* PUSH Id *) (* LEN *)
    ИНАЧЕ (* atyp.родв = вОРяд *)
      опора.disp:=basedisp+atyp.адрОВ;
      ЗК.PutOM(0FFH,6H,опора)    (* PUSH Ed *) (* LEN *)
    КОН;
    ЕСЛИ ftyp.овид.родв = вОРяд ТО
      PushBnd(ftyp.овид,atyp.овид)
    КОН
  КОН PushBnd;

УКАЗ
  ЕСЛИ ap.вид.родв = вПЦепь ТО
    ЕСЛИ fp.вид.овид = ВД.оячвид ТО
      ЗК.PutOD(4,068H,ap.disp*2)   (* PUSH Id *) (* LEN*2 *)
    ИНАЧЕ
      ЗК.PutOD(4,068H,ap.disp)     (* PUSH Id *) (* LEN *)
    КОН;
    ЗК.PutOD(4,068H,ap.адр);       (* PUSH Id *) (* смещение *)
    Coff.СоздатьСкр(Coff.Код,Coff.СКР_ПОСТ,0,ЗК.pc-4)
  ИНАЧЕ
    ЕСЛИ fp.вид.овид = ВД.оячвид ТО
      ЕСЛИ ap.вид.родв = вРяд ТО
        ЗК.PutOD(4,068H,ap.вид.размер)    (* PUSH Id *) (* LEN *)
      ИНАЧЕ  (* ap.вид.родв = вОРяд, ap.тип В {пПер,пПрСсылки,DArr} *)
        LoadSize(ap,размер);
        ЕСЛИ размер.тип = пПост ТО
          ЗК.PutOD(4,068H,размер.адр)  (* PUSH Id *) (* LEN *)
        ИНАЧЕ
          ЗК.PutOM(0FFH,6H,размер)     (* PUSH Ed *) (* LEN *)
        КОН;
        ЗК.Release(размер)
      КОН
    ИНАЧЕ    (* ap.вид.родв В {вОРяд,вРяд} ap.тип В {пПер,пПрСсылки,DArr} *)
      ЕСЛИ ap.вид.родв = вОРяд ТО   (* see also LoadSize *)
        ЕСЛИ (ap.тип = RegI) ИЛИ (ap.тип = DArr) И (ap.disp = RegI) ТО
          опора.тип:=RegI;
          ЕСЛИ ap.тип = DArr ТО опора.bas:=ap.inx ИНАЧЕ опора.bas:=ap.bas КОН;
          basedisp:=0;
          PushBnd(fp.вид,ap.вид)
        ИНАЧЕ
          опора.уровень:=ap.уровень;
          LoadBaseAdr(опора);
          basedisp:=ap.адр;
          PushBnd(fp.вид,ap.вид);
          ЗК.Release(опора)
        КОН
      ИНАЧЕ (* ap.вид.родв=вРяд *)
        basedisp:=0;
        PushBnd(fp.вид,ap.вид)
      КОН;
    КОН;
    IgnoreDynArrDesc(ap);
    PushAdr(ap)
  КОН
КОН PushDynArrDesc;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА ПроверкаБегунка-(б+:ЗК.нItem);
(* 
 *  Цель: ПРОВЕРИТЬ(тб # 0)
 *    До: б.тип В {пПрСсылки,пПер,Abs,RegI,RegX,Inx}
 * После: б.тип без изменений
 *)
ПЕР
  тб:ЗК.нItem;
  L1:ЗК.Label;
УКАЗ
  L1:=0;
  LoadAdr(б);
  тб.bas:=МР.ЗанятьРег();
  ЗК.PutORM(08BH,тб.bas,б); (* MOV r32,r/m32 *)
  тб.тип:=Reg;
  ЗК.PutOM(09H,МР.РегМВ(тб.bas),тб); (* OR r/m32,r32 *)
  ЗК.PutJmpCF(NEQ,L1); 
  ЗК.Ловушка(пустоАвОст);
ЗК.FixLink(L1);
  МР.ОсвободитьРег(тб.bas)
КОН ПроверкаБегунка;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА DeRef-(x+:ЗК.нItem);
(*
 *  Цель: разыменовывание бегунка и доступа к переменной
 *    До: x.тип В {пПрСсылки,пПер,Abs,RegI,RegX,Inx}
 * После: x.тип = RegI
 *)
ПЕР
  y:ЗК.нItem;
  L1,L2:ЗК.Label;
  родв:ЦЕЛ;
УКАЗ
  родв:=x.вид.родв;
  LoadAdr(x);
  y.bas:=МР.ЗанятьРег();
  ЗК.PutORM(08BH,y.bas,x); (* MOV r32,r/m32 *)
  ЕСЛИ (родв = вБегунок) И НП.клПровБегунка ТО
    (* y = тб *)
    L1:=0;
    L2:=0;
    y.тип:=Reg;
    (* тб = 0 ? *)
    ЗК.PutOM(09H,МР.РегМВ(y.bas),y); (* OR r/m32,r32 *)
    ЗК.PutJmpCF(EQL,L1); 
    (* нб > тб ? *)
    СК.IncAdr(x,4);
    ЗК.PutORM(039H,y.bas,x); (* CMP Ed,Gd *)
    ЗК.PutJmpCF(GTR,L1); 
    (* кб <= тб ? *)
    СК.IncAdr(x,4);
    ЗК.PutORM(039H,y.bas,x); (* CMP Ed,Gd *)
    ЗК.PutJmpCF(LEQ,L1); 
    (* восстанавливаем 'б' и переход на продолжение *)
    СК.IncAdr(x,-8);
    ЗК.PutJmpF(L2); 
ЗК.FixLink(L1);
    ЗК.Ловушка(бегунокАвОст);
ЗК.FixLink(L2)
  КОН;
  ЕСЛИ родв = вБегунок ТО
    ЗК.PutOMD(4,081H,0H,x,x.вид.n*x.вид.овид.размер)  (* ADD Ed,Id *)
  КОН;
  ЗК.Release(x);
  ЕСЛИ (родв # вБегунок) И НП.клПровПусто ТО
    y.тип:=Reg;
    ЗК.PutOM(09H,МР.РегМВ(y.bas),y); (* OR r/m32,r32 *)
    L1:=0;
    ЗК.PutJmpCF(NEQ,L1); (* check if pointer is ПУСТО *)
    ЗК.Ловушка(пустоАвОст);
    ЗК.FixLink(L1)
  КОН;
  x.тип:=RegI;
  x.disp:=0;
  x.bas:=y.bas
КОН DeRef;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Index-(x+,y+:ЗК.нItem);
(*
 *  Цель: index in an array (x <- x[y])
 *    До: x.вид.родв В {вРяд,вОРяд}
 *        x.тип В {пПер,пПрСсылки,DArr,RegI (disp = 0)}
 * После: x.тип В {DArr,RegI,RegIRel,RegX}
 *)
ПЕР
  r,h:ЗК.нItem;
  s:ЦЕЛ;
  releaseH:КЛЮЧ;
УКАЗ
  releaseH:=ОТКЛ;
  (* Adr:=((.. (i1 * n2 + i2) * n3 + .. ) * nk + ik) * basSiz + basAdr *)
  ЕСЛИ x.вид.родв = вРяд ТО
    (* x.тип В {пПер,пПрСсылки,RegI,RegX,Inx}*)
    s:=x.вид.овид.размер;
    ЕСЛИ y.тип = пПост ТО
      LoadAdr(x);
      IncAdr(x,y.адр*s)
    АЕСЛИ (x.вид.овид.родв = вРяд) ИЛИ (s # 1) И (s # 2) И (s # 4) И (s # 8) ТО
      ValToReg(y);
      ЕСЛИ НП.клПровНомера ТО ПроверкаУРяда(x,y) КОН;
      ЕСЛИ s # 1 ТО
        ЗК.PutIMUL3(y.bas,y,s) (* IMUL Gd,Ed,Id *)
      КОН;
      LoadAdr(x);
      ЕСЛИ x.тип В {Abs,AbsRel} ТО
        ЕСЛИ x.тип = Abs ТО x.тип:=RegI ИНАЧЕ x.тип:=RegIRel КОН;
        x.disp:=x.адр;
        x.bas:=y.bas;
        y.тип:=0
      ИНАЧЕ
        AdrToRegI(x);
        МР.РегВоМРег(x.bas);
        ЗК.PutORM(03H,x.bas,y);  (* ADD r32,r/m32 *)
        ЗК.Release(y)
      КОН
    ИНАЧЕ (* s = 1|2|3|4 *)
      ValToReg(y);
      ЕСЛИ НП.клПровНомера ТО ПроверкаУРяда(x,y) КОН;
      LoadAdr(x);
      ЕСЛИ x.тип = Abs ТО
        x.тип:=Inx;
        x.disp:=x.адр
      АЕСЛИ x.тип = AbsRel ТО
        x.тип:=InxRel;
        x.disp:=x.адр
      ИНАЧЕ
        AdrToRegI(x);
        ЕСЛИ x.тип=RegI ТО
          x.тип:=RegX
        АЕСЛИ x.тип=RegIRel ТО
          x.тип:=RegXRel
        КОН
      КОН;
      x.inx:=y.bas;
      ЕСЛИ  s=1 ТО x.адр:=0
      АЕСЛИ s=2 ТО x.адр:=1
      АЕСЛИ s=4 ТО x.адр:=2
      ИНАЧЕ (*8*)  x.адр:=3
      КОН;
      y.тип:=0 
    КОН
  ИНАЧЕ (* x.вид.родв = вОРяд, x.тип В {пПер,пПрСсылки,DArr,RegI (disp = 0) *)
    ПРОВЕРИТЬ(x.тип # RegIRel);
    ЕСЛИ (x.тип = RegI) ИЛИ (x.тип = DArr) И (x.disp = RegI) ТО
      h.тип:=RegI;
      ЕСЛИ x.тип = DArr ТО h.bas:=x.inx ИНАЧЕ h.bas:=x.bas КОН;
      h.disp:=x.вид.адрОВ
    ИНАЧЕ
      h.уровень:=x.уровень;
      LoadBaseAdr(h);
      releaseH:=ВКЛ;
      h.disp:=x.адр+x.вид.адрОВ
    КОН;
    (* h.тип=RegI, h указывает на bound *)
    ЕСЛИ x.тип = DArr ТО
      ЕСЛИ (y.тип = пПост) И (НЕ НП.клПровНомера ИЛИ (y.адр = 0)) ТО
        ЕСЛИ y.адр # 0 ТО
          x.тип:=Reg;
          ЗК.PutOMD(4,081H,0H,x,y.адр); (* ADD Ed,Id *)
          x.тип:=DArr
        КОН
      ИНАЧЕ
        ValToReg(y);
        ЕСЛИ НП.клПровНомера ТО ПроверкаУОРяда(h,y) КОН;
        ЗК.PutORM(03H,x.bas,y); (* ADD Gd,Ed *)
        ЗК.Release(y)
      КОН
    ИНАЧЕ (* x.тип В {пПер,пПрСсылки,RegI (disp = 0) *)
      ЕСЛИ x.тип = RegI ТО
        x.inx:=x.bas;
        x.адр:=x.вид.размер
      КОН;
      x.disp:=x.тип;
      ЕСЛИ (y.тип = пПост) И (НЕ НП.клПровНомера ИЛИ (y.адр = 0)) ТО
        x.тип:=Reg;
        x.bas:=МР.ЗанятьРег();
        ЗК.PutOMD(4,0C7H,0H,x,y.адр) (* MOV Ed,Id *)
      ИНАЧЕ
        ValToReg(y);
        ЕСЛИ НП.клПровНомера ТО ПроверкаУОРяда(h,y) КОН;
        x.bas:=y.bas;
        y.тип:=0
      КОН;
      x.тип:=DArr
    КОН;
    (* x.тип = DArr *)
    ЕСЛИ x.вид.овид.родв = вОРяд ТО
      ЕСЛИ x.disp В {пПер,пПрСсылки} ТО
        h.disp:=x.адр+x.вид.овид.адрОВ
      ИНАЧЕ (* x.disp = RegI *)
        h.disp:=x.вид.овид.адрОВ
      КОН;
      r.тип:=Reg;
      r.bas:=МР.ЗанятьРег();
      ЗК.PutORM(08BH,r.bas,h);  (* MOV r32,r/m32 *)  (* r:=LEN *)
      ЗК.PutORM(0FAFH,x.bas,r); (* IMUL Gd,Ed *)     (* x:=x*LEN *)
      МР.ОсвободитьРег(r.bas)
    ИНАЧЕ
      s:=x.вид.овид.размер;
      ЕСЛИ (s # 1) И (s # 2) И (s # 4) И (s # 8) ТО
        x.тип:=Reg;
        ЗК.PutIMUL3(x.bas,x,s);   (* IMUL Gd,Ed,Id *)
        ЕСЛИ x.disp В {пПер,пПрСсылки} ТО
          h.disp:=x.адр;
          ЗК.PutORM(03H,x.bas,h); (* ADD Gd,Ed *)
          x.disp:=0
        ИНАЧЕ (* x.disp = RegI *)
          x.тип:=Reg;
          ЗК.PutORM(01H,x.inx,x); (* ADD Ed,Gd *)
          МР.ОсвободитьРег(x.inx);
          x.disp:=x.адр
        КОН;
        x.тип:=RegI
      ИНАЧЕ
        r.bas:=x.inx; (* x.bas <-> x.inx *)
        x.inx:=x.bas;
        x.bas:=r.bas;
        ЕСЛИ x.disp В {пПер,пПрСсылки}  ТО
          x.bas:=МР.ЗанятьРег();
          h.disp:=x.адр;
          ЗК.PutORM(08BH,x.bas,h); (* MOV r32,r/m32 *)
          x.disp:=0
        ИНАЧЕ
          x.disp:=x.адр
        КОН;
        ЕСЛИ  s=1 ТО x.адр:=0
        АЕСЛИ s=2 ТО x.адр:=1
        АЕСЛИ s=4 ТО x.адр:=2
        ИНАЧЕ (*8*)  x.адр:=3
        КОН;
        x.тип:=RegX
      КОН
    КОН;
    ЕСЛИ releaseH ТО МР.ОсвободитьРег(h.bas) КОН;
  КОН;
  x.вид:=x.вид.овид
КОН Index;

КОН СК.
