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

                   (* Род узлов (Узел.роду). Из ПД. *)
  Nvar     =0;
  Nvarpar  =1;
  Nfield   =2;
  Nderef   =3;
  Nindex   =4;
  Nguard   =5;
  Neguard  =6;
  Nconst   =7;
  Ntype    =8;
  Nproc    =9;
  Nupto    =10;
  Nmop     =11;
  Ndop     =12;
  NcallTuda=13;
  NcallSuda=14;
  Ncall    =15;
  Nif      =16;
  Ncaselse =17;
  Ncasedo  =18;
  Nenter   =19;
  Nassign  =20;
  Nifelse  =21;
  Ncase    =22;
  Nwhile   =23;
  Nrepeat  =24;
  Nloop    =25;
  Nexit    =26;
  Nreturn  =27;
  Nwith    =28;
  Ntrap    =29;

                   (* Номера задач (нУзел.подроду). Из ПД. *)
  assign    =0;
  зВЦел     =1;
  зВШирЦел  =2;
  зЧет      =3;
  зВЗнак    =4;
  зМодуль   =5;
  зМин      =6;
  зМакс     =7;
  зУзк      =8;
  зУвеличить=9;
  зУменьшить=10;
  зСтоп     =11;
  зРазмер   =12;
  зДлина    =13;
  зСоздать  =14;
  зСписать  =15;
  зЗадано   =16;
  зПроверить=17;
  зПоставить=18;
  зСместить =19;
  зОбнулить =20; 
  зЦелЧасть =21;

                   (* Номера задач ОБХОД отдела (нУзел.подроду). Из ПД. *)
  зПолучитьАдрес=23;
  зИзПамяти     =24;
  зВПамять      =25;
  зЗначение     =26;
  зОбраз        =27;
  зОУзк         =28;

  (*
   * Способы адресации 80386 (нItem.тип). Не должны пересекаться с
   * номерами ВД.Понятие.родп. Из ЗК.
   *)
  Coc=17;

  PARSIZE_VAR=4;    (* размер источника переменных в стеке *)
  PARSIZE_RECVAR=8; (* размер источника набора переменных в стеке *)

              (* смещение всех источников от EBP (место для старых EBP и EIP) *)
  ProcParOff=8;

                          (* Программные ловушки (аварийные остановы). Из СК. *)
  пределыАвОст=1;
    номерАвОст=2;
    арифмАвОст=3;
   охранаАвОст=4;
    пустоАвОст=5;
      дляАвОст=6;
  выбратьАвОст=7;
    ответАвОст=8;
проверитьАвОст=9;
     нольАвОст=10;
  бегунокАвОст=11;

ПЕР
  ExitChain:ЗК.Label;


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


ЗАДАЧА ^ParamAdr(первПр:ВД.ДкПонятию; psize+:ЦЕЛ; невызываемая:КЛЮЧ);
ЗАДАЧА ^Traverse(пон:ВД.ДкПонятию; общедоступные:КЛЮЧ);
ЗАДАЧА ^expr(n:ПД.ДкУзлу; x+:ЗК.нItem);


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


(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ДоступыЗадачи( задача:ВД.ДкПонятию;
                     адреса+:РЯД ИЗ ЦЕЛ):ЦЕЛ;
(*
 * Цель:  находит в задаче адреса переменных вида ДОСТУП
 *        (нужны для начальной установки их в ПУСТО)
 * До:    <задача> - задача
 * После: возвращает число найденых адресов, помещённых в ряду <адреса>
 *)
ПЕР
  адресов:ЦЕЛ; (* число найденых адресов *)
  пон:ВД.ДкПонятию;   (* переменная задачи *)

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

УКАЗ
  адресов:=0;
  пон:=задача.область.область;
  ПОКА (пон # ПУСТО) И (адресов < РАЗМЕР(адреса)) ВЫП
    ДоступыПер(пон.вид,пон.адр);
    пон:=пон.след
  КОН;
  ВОЗВРАТ адресов
КОН ДоступыЗадачи;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА TypSize(вид:ВД.ДкВиду; нуженОВ:КЛЮЧ);
(*
 * Цель:  вычисление размера переменных вида <вид>
 * До:    <нуженОВ> = ВКЛ, если требуется разместить ОВ в области постоянных
 * После: <вид.размер> с правильным значением
 *)
ПЕР
  смещение,размер:ЦЕЛ;
  свво:ВД.ДкПонятию;
  овид:ВД.ДкВиду;
  размерНеопределён,размещаемОВ,неСжатый:КЛЮЧ;
УКАЗ
  ЕСЛИ вид = ВД.неопрвид ТО
    ОО.Ошибка(ОО.ПЕРЕКРЕСТНЫЙ_ВИД)
  КОН;
  размерНеопределён:=вид.размер = -1;
  размещаемОВ:=нуженОВ И (вид.адрОВ = НП.АдрНеопр);
  ЕСЛИ размерНеопределён ИЛИ размещаемОВ ТО
    ЕСЛИ размещаемОВ ТО вид.адрОВ:=-2 КОН; (* для избежания зацикливания *)
    овид:=вид.овид;
    ВЫБРАТЬ вид.родв ИЗ
      вНабор:
        ЕСЛИ овид = ВД.неопрвид ТО
          смещение:=0
        ИНАЧЕ
          TypSize(овид,нуженОВ);
          смещение:=овид.размер
        КОН;
        ЕСЛИ размещаемОВ ТО
          ЕСЛИ (овид # ВД.неопрвид) И ((овид.адрОВ = -2) ИЛИ (овид.адрОВ = НП.АдрНеопр)) ТО
            размещаемОВ:=ОТКЛ; (* ещё не готовы к распределению *)
            вид.адрОВ:=НП.АдрНеопр
          КОН
        КОН;
        неСжатый:=вид.n # 1;
        свво:=вид.след;
        ПОКА свво # ПУСТО ВЫП
          овид:=свво.вид;
          TypSize(овид,нуженОВ);
          ЕСЛИ размерНеопределён ТО
            размер:=овид.размер;
            ПОКА овид.родв = вРяд ВЫП овид:=овид.овид КОН;
            ЕСЛИ неСжатый ТО
              ЕСЛИ овид.размер >= 4 ТО
                УВЕЛИЧИТЬ(смещение,(-смещение) ОСТАТОК 4)
              АЕСЛИ овид.размер = 2 ТО
                УВЕЛИЧИТЬ(смещение,смещение ОСТАТОК 2)
              КОН
            КОН;
            свво.адр:=смещение;
            УВЕЛИЧИТЬ(смещение,размер)
          КОН;
          свво:=свво.след
        КОН;
        ЕСЛИ размерНеопределён ТО
          ЕСЛИ неСжатый ТО
            УВЕЛИЧИТЬ(смещение,(-смещение) ОСТАТОК 4)
          КОН;
          вид.размер:=смещение
        КОН;
        ЕСЛИ размещаемОВ ТО
          ЗК.AllocTypDesc(вид);
          Traverse(вид.след,ВКЛ)
        КОН
    | вДоступ:
        вид.размер:=НП.рДоступ;
        ЕСЛИ размещаемОВ ТО
          TypSize(овид,нуженОВ)
        КОН
    | вБегунок:
        вид.размер:=НП.рБегунок;
        ЕСЛИ размещаемОВ ТО
          TypSize(овид,нуженОВ)
        КОН
    | вЗадача:
        вид.размер:=НП.рЗадача;
        ЕСЛИ размещаемОВ ТО
          TypSize(овид,ВКЛ);
          ParamAdr(вид.след,размер,вид.n = 1)
        КОН
    | вРяд:
        TypSize(овид,нуженОВ);
        ЕСЛИ размерНеопределён ТО вид.размер:=вид.n*овид.размер КОН
    | вОРяд:
        TypSize(овид,нуженОВ);
        ЕСЛИ овид.родв = вОРяд ТО
          вид.размер:=овид.размер+4;
          вид.адрОВ:=овид.адрОВ+4   
        ИНАЧЕ
          вид.размер:=8;            
          вид.адрОВ:=4
        КОН
    КОН
  КОН
КОН TypSize;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ParamAdr(первПр:ВД.ДкПонятию;
                psize+:ЦЕЛ;
          невызываемая:КЛЮЧ);
(*
 * Цель:  вычисляет адреса приёмников и их размер,
 *        записывая при необходимости ОВ в области постоянных
 * После: <psize> - размер приёмников
 *)
ПЕР
  пр:ВД.ДкПонятию;
  вид:ВД.ДкВиду;
  адр,размер:ЦЕЛ;
УКАЗ
  адр:=0;
  пр:=первПр;
  ПОКА пр # ПУСТО ВЫП
    вид:=пр.вид;
    TypSize(вид,ВКЛ);
    ЕСЛИ пр.родп = пПрСсылки ТО
      ЕСЛИ невызываемая ТО
        размер:=PARSIZE_VAR
      ИНАЧЕ
        ЕСЛИ вид.родв = вНабор ТО
          размер:=PARSIZE_RECVAR
        АЕСЛИ вид.родв = вОРяд ТО
          размер:=вид.размер
        ИНАЧЕ
          размер:=PARSIZE_VAR
        КОН
      КОН
    ИНАЧЕ
      размер:=вид.размер
    КОН;
    УВЕЛИЧИТЬ(адр,размер+((-размер) ОСТАТОК 4));
    пр.адр:=адр;
    пр:=пр.след
  КОН;
  psize:=адр;
  УВЕЛИЧИТЬ(адр,ProcParOff);
  ЕСЛИ невызываемая ТО
    УВЕЛИЧИТЬ(адр,12) (* подставные IP,BP и свой BP для связывания стека вызовов *)
  КОН;
  ПОКА первПр # ПУСТО ВЫП
    первПр.адр:=адр-первПр.адр;
    первПр:=первПр.след
  КОН
КОН ParamAdr;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ParamSize(первПр:ВД.ДкПонятию;
                 psize+:ЦЕЛ);
(*
 * Цель:  вычисляет размер приёмников,
 *        без записи ОВ в области постоянных
 * После: <psize> - размер приёмников
 *)
ПЕР
  пр:ВД.ДкПонятию;
  вид:ВД.ДкВиду;
  адр,размер:ЦЕЛ;
УКАЗ
  адр:=0;
  пр:=первПр;
  ПОКА пр # ПУСТО ВЫП
    вид:=пр.вид;
    TypSize(вид,ОТКЛ);
    ЕСЛИ пр.родп = пПрСсылки ТО
      ЕСЛИ вид.родв = вНабор ТО
        размер:=PARSIZE_RECVAR;
      АЕСЛИ вид.родв = вОРяд ТО
        размер:=вид.размер
      ИНАЧЕ
        размер:=PARSIZE_VAR;
      КОН
    ИНАЧЕ
      размер:=вид.размер
    КОН;
    УВЕЛИЧИТЬ(адр,размер+((-размер) ОСТАТОК 4));
    пр:=пр.след
  КОН;
  psize:=адр
КОН ParamSize;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА LVarAdr(   var:ВД.ДкПонятию;
               locOff:ЦЕЛ;
               lsize+:ЦЕЛ);
(*
 * Цель:  initializes addresses of local задача variables      
 * До:    locOff = смещение, relativ to EBP, where parameters begin 
 * После: lsize = размер of local variable field
 *)
ПЕР
  адр,размер:ЦЕЛ;
УКАЗ
  адр:=locOff;  (* адр <= 0 *)
  ПОКА var # ПУСТО ВЫП
    TypSize(var.вид,ВКЛ);
    размер:=var.вид.размер;
    УМЕНЬШИТЬ(адр,размер+((-размер) ОСТАТОК 4));
    var.адр:=адр;
    var:=var.след
  КОН;
  lsize:=locOff-адр
КОН LVarAdr;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА GVarAdr(var:ВД.ДкПонятию);
(*
 * Цель:  initializes addresses of global variables               
 * До:    var = перв global variable
 *)
ПЕР
  адр,размер:ЦЕЛ;
УКАЗ
  адр:=ЗК.dsize;
  ПОКА var # ПУСТО ВЫП
    TypSize(var.вид,ВКЛ);
    размер:=var.вид.размер;
    ЕСЛИ размер >= 4 ТО
      УВЕЛИЧИТЬ(адр,(-адр) ОСТАТОК 4)
    АЕСЛИ размер = 2 ТО
      УВЕЛИЧИТЬ(адр,адр ОСТАТОК 2)
    КОН;
    var.адр:=адр;
    УВЕЛИЧИТЬ(адр,размер);
    var:=var.след
  КОН;
  УВЕЛИЧИТЬ(адр,(-адр) ОСТАТОК 4);
  ЗК.dsize:=адр
КОН GVarAdr;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА АдресаЗадачи(       задача:ВД.ДкПонятию;
                    общедоступные:КЛЮЧ);
(*
 * Цель:  вычисление адресов приёмников и переменных данной 'задача'
 * До:    общедоступные = ВКЛ:  рассматриваются только общедоступные задачи
 *        общедоступные = ОТКЛ: рассматриваются остальные задачи
 *)
ПЕР
  смещениеПер:ЦЕЛ;
  былаПоз:ОО.нТекстПоз;
УКАЗ
  былаПоз:=ОО.текПоз;
  ОО.текПоз.строка:=задача.область.адр;
  ОО.текПоз.колонка:=0;
  ЕСЛИ (прОбщедоступная В задача.признаки) = общедоступные ТО
    TypSize(задача.вид,ВКЛ);
    ParamAdr(задача.след,задача.пост.цел1,прПередаваемая В задача.признаки)
  КОН;
  ЕСЛИ НЕ общедоступные ТО
    ЕСЛИ НЕ (прОбъявлена В задача.признаки) ТО
      ОО.Отметить(ОО.НЕВЕРНАЯ_ЗАГОТОВКА,задача.имя)
    КОН;
    ПРОВЕРИТЬ(задача.уровень >= 0);
    смещениеПер:=-4*(задача.уровень+1);
    (* адреса переменных задачи *)
    LVarAdr(задача.область.область,смещениеПер,задача.пост.цел2); 
    (* обход подобласти *)
    Traverse(задача.область.право,ОТКЛ)
  КОН;
  ОО.текПоз:=былаПоз
КОН АдресаЗадачи;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА Traverse(          пон:ВД.ДкПонятию;
                общедоступные:КЛЮЧ);
(*
 * Цель:  рекурсивный обход дерева понятий
 * До:    общедоступные = ВКЛ:  рассматриваются только общедоступные понятия
 *        общедоступные = ОТКЛ: рассматриваются остальные понятия
 *)
УКАЗ
  ЕСЛИ пон # ПУСТО ТО
    Traverse(пон.лево,общедоступные);
    ЕСЛИ (пон.родп = пВид) И ((прОбщедоступная В пон.признаки) = общедоступные) ТО
      TypSize(пон.вид,ВКЛ)
    АЕСЛИ пон.родп = пЗадача ТО
      АдресаЗадачи(пон,общедоступные)
    КОН;
    Traverse(пон.право,общедоступные)
  КОН
КОН Traverse;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА AdrAndSize-;
(*
 * Цель:  вычисление адресов всех переменных и приёмников задач, а также
 *        размеров, соответствующих видов данных
 * До:    <текОбласть> - голова дерева понятий
 *)
УКАЗ
  ОО.текПоз.строка:=ВД.текОбласть.адр;
  ОО.текПоз.колонка:=0;
  Traverse(ВД.текОбласть.право,ВКЛ); (* сначало вычисляем у общедоступных переменных и задач *)
  GVarAdr(ВД.текОбласть.область);    (* переменные отдела *)
  Traverse(ВД.текОбласть.право,ОТКЛ) (* остальные понятия *)
КОН AdrAndSize;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА DeSign(узел:ПД.ДкУзлу; x+:ЗК.нItem);
(*
 * Цель:  разбор цели назначения узла <узел> и возврат ответа в <x>
 * До:    узел = узел
 * После: x = address of object
 *)
ПЕР
  пон:ВД.ДкПонятию;
  y:ЗК.нItem;
  лево:ПД.ДкУзлу;
УКАЗ
  лево:=узел.лево;
  ВЫБРАТЬ узел.роду ИЗ
    Nvar,Nvarpar:
      пон:=узел.пон;
      x.тип:=пон.родп;
      x.уровень:=пон.уровень;
      x.адр:=пон.адр;
  | Nfield:
      DeSign(лево,x);
      КУ.Field(x,узел.пон.адр);
  | Nderef:
      DeSign(лево,x);
      СК.DeRef(x);
  | Nindex:
      DeSign(лево,x);
      expr(узел.право,y);
      СК.Index(x,y);
      ЗК.Release(y);
  | Nguard:
      DeSign(лево,x);
      КУ.TypTest(x,узел.вид,ВКЛ,ОТКЛ)
  | Neguard:
      DeSign(лево,x);
      КУ.TypTest(x,узел.вид,ВКЛ,ВКЛ)
  | Nproc:
      пон:=узел.пон;
      ЕСЛИ пон.пост.цел1=-1 ТО
        ParamSize(пон.след,пон.пост.цел1)
      КОН;
      x.тип:=пон.родп;
      x.уровень:=пон.уровень;
      ЕСЛИ (x.уровень < 0) И (пон.адр = 0) ТО (* неподготовленная внешняя задача *)
        Coff.AddImportedProc(пон)
      КОН;
      x.пон:=пон
  КОН;
  x.вид:=узел.вид
КОН DeSign;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ActualPar(у:ПД.ДкУзлу; пон:ВД.ДкПонятию);
(*
 * Цель:  вычисляет все источники задачи                  
 * До:    у   - выражение первого источника
 *        пон - понятие первого приёмника
 *)
ПЕР
  ис,пр:ЗК.нItem;
УКАЗ
  ПОКА у # ПУСТО ВЫП
    expr(у,ис);
    пр.тип:=пон.родп;
    пр.вид:=пон.вид;
    КУ.Param(ис,пр,ОТКЛ,у.роду = Nderef,ОТКЛ);
    ЗК.Release(ис);
    у:=у.след;
    пон:=пон.след
  КОН
КОН ActualPar;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ActualParDLL(источник:ПД.ДкУзлу;
                        сюда:КЛЮЧ);
(*
 *  Цель: если <сюда> = ВКЛ, то
 *        передаёт источники передаваемой задачи в приёмники нашей задачи
 *        иначе
 *        передаёт источники (приёмники нашей задачи) в принимаемую задачу
 *)
ПЕР
  ис,пр:ЗК.нItem;
  пон:ВД.ДкПонятию;
УКАЗ
  ПОКА источник # ПУСТО ВЫП
    пон:=источник.пон;
    ис.тип:=пон.родп;
    ис.уровень:=пон.уровень;
    ис.адр:=пон.адр;
    ис.вид:=источник.вид;
    пр.тип:=ис.тип;
    пр.вид:=ис.вид;
    КУ.Param(ис,пр,ВКЛ,ОТКЛ,сюда);
    ЗК.Release(ис);
    источник:=источник.след
  КОН
КОН ActualParDLL;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА expr(n:ПД.ДкУзлу; x+:ЗК.нItem);
(*
 *  Цель: раскрывает выражение узла 'n' и возвращает ответ в 'x'
 *    До: n - ведущий узел выражения
 * После: x - значение выражения
 *)
ПЕР
  y,z:ЗК.нItem;
  f,g:ЦЕЛ;
  задача:ВД.ДкПонятию;
УКАЗ
  ВЫБРАТЬ n.роду ИЗ
    Nconst:
      x.тип:=пПост;
      x.вид:=n.вид;
      x.уровень:=0;
      ВЫБРАТЬ n.вид.родв ИЗ
        вКлюч,вЯчейка,вЗнак..вЦел64,вПусто,вДоступ:
          x.адр:=УЗК(n.пост.цел ОСТАТОК 100000000H); (*64*)
          x.disp:=УЗК(n.пост.цел ДЕЛИТЬ 100000000H); (*64*)
      | вВещ32,вВещ64:
          ЕСЛИ n.пон = ПУСТО ТО
            ЗК.AllocReal(n.пост.вещ,n.пост.цел1,n.вид.родв = вВещ64);
            x.адр:=n.пост.цел1;
          ИНАЧЕ
            ЕСЛИ n.пон.пост.цел1 = НП.АдрНеопр ТО
              ЗК.AllocReal(n.пон.пост.вещ,n.пон.пост.цел1,n.вид.родв = вВещ64)
            КОН;
            x.адр:=n.пон.пост.цел1
          КОН;
          x.disp:=0
      | вМнож:
          x.адр:=ОБХОД.Значение(ЦЕЛ,n.пост.множ)
      | вПЦепь:
          ЕСЛИ n.пон = ПУСТО ТО
            ЗК.AllocString(n.пост.цепьД^,n.пост.цел1)
          ИНАЧЕ
            ЕСЛИ n.пон.пост.цел1 = НП.АдрНеопр ТО
              ЗК.AllocString(n.пост.цепьД^,n.пон.пост.цел1)
            КОН;
            n.пост.цел1:=n.пон.пост.цел1
          КОН;
          x.адр:=n.пост.цел1;
          x.disp:=РАЗМЕР(n.пост.цепьД^)
      КОН
  | Nupto: (* n.вид = ВД.множвид *)
      expr(n.лево,y);
      expr(n.право,z);
      КУ.SetRange(x,y,z);
      ЗК.Release(y);
      ЗК.Release(z)
  | Nmop:
      expr(n.лево,x);
      ВЫБРАТЬ n.подроду ИЗ
        СС.не:
          КУ.Not(x)
      | СС.минус:
          КУ.Neg(x)
      | СС.является:
          КУ.TypTest(x,n.пон.вид,ОТКЛ,ОТКЛ)
      | СС.преобр:
          КУ.Convert(x,n.вид.родв)
      | СС.элем:
          КУ.Элемент(x)
      | СС.длина:
          КУ.Длина(x)
      | СС.модуль:
          КУ.AbsVal(x)
      | СС.целчасть:
          КУ.ЦелЧасть(x)
      | СС.чет:
          КУ.Odd(x)
      | СС.адрес:
          КУ.SYSadr(x)
      | СС.значение:
          ЕСЛИ (x.вид.размер # n.вид.размер) И НЕ ((x.тип = пПост) И (n.вид.размер <= 4)) ТО
            ОО.Ошибка(ОО.НЕСОВПАДЕНИЕ_РАЗМЕРОВ)
          КОН;
          КУ.SYSval(x,n.вид)
      КОН
  | Ndop:
      expr(n.лево,x);
      f:=x.вид.родв;
      ЕСЛИ n.подроду = СС.и ТО 
        КУ.CondAnd(x)
      АЕСЛИ n.подроду = СС.или ТО 
        КУ.CondOr(x)
      АЕСЛИ (n.подроду >= СС.равно) И (n.подроду <= СС.бравно) ТО 
        КУ.Relation(x)
      КОН;
      expr(n.право,y);
      ВЫБРАТЬ n.подроду ИЗ
        СС.умножить:
          ЕСЛИ f = вМнож ТО
            КУ.SetInter(x,y)
          ИНАЧЕ
            КУ.Mul(x,y,f В множВещ)
          КОН
      | СС.косая:
          ЕСЛИ f = вМнож ТО
            КУ.SetSymmDiff(x,y)
          ИНАЧЕ
            КУ.FloatDiv(x,y)
          КОН
      | СС.делить:
          КУ.DivMod(x,y,ВКЛ)
      | СС.остаток:
          КУ.DivMod(x,y,ОТКЛ)
      | СС.и:
          КУ.And(x,y)
      | СС.плюс:
          ЕСЛИ f = вМнож ТО
            КУ.SetUnion(x,y)
          ИНАЧЕ
            КУ.Add(x,y,f В множВещ)
          КОН
      | СС.минус:
          ЕСЛИ f = вМнож ТО
            КУ.SetDiff(x,y)
          ИНАЧЕ
            КУ.Sub(x,y,f В множВещ)
          КОН
      | СС.или:
          КУ.Or(x,y)
      | СС.равно..СС.бравно:
          КУ.Cmp(x,y,n.подроду)
      | СС.в:
          КУ.In(x,y)
      | СС.сдвиг:
          КУ.Ash(x,y)
      | СС.сбрбиты:
          КУ.Msk(x,y)
      | СС.размер:
          КУ.Len(x,y)
      КОН;
      ЗК.Release(y)
  | Ncall:
      ЕСЛИ n.вид = ВД.нетвид ТО
        ОО.Ошибка(ОО.НЕТ_ОТВЕТА)
      КОН;
      ЕСЛИ n.лево.роду = Nproc ТО (* просто ЗАДАЧА ? *)
        задача:=n.лево.пон;
        ЕСЛИ задача.пост.цел1=-1 ТО
          ParamSize(задача.след,задача.пост.цел1)
        КОН
      ИНАЧЕ  (* переменная вида ЗАДАЧА ? *)
        ПРОВЕРИТЬ(n.лево.вид.родв = вЗадача);
        задача:=ПУСТО;
        ЕСЛИ n.лево.пост = ПУСТО ТО
          n.лево.пост:=ВД.СоздатьПост();
          n.лево.пост.цел1:=-1
        КОН;
        ЕСЛИ n.лево.пост.цел1 = -1 ТО
          ParamSize(n.лево.вид.след,n.лево.пост.цел1)
        КОН
      КОН;
      DeSign(n.лево,x);
      КУ.СохранитьРеги;
      ActualPar(n.право,n.пон);
      ЕСЛИ задача # ПУСТО ТО
        КУ.CallProc(задача)
      ИНАЧЕ
        КУ.CallVar(x);
        x.вид:=n.вид
      КОН;
      КУ.ВосстановитьРеги(x)
  ИНАЧЕ
    DeSign(n,x)
  КОН;
  x.вид:=n.вид
КОН expr;


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

(*-----------------------------рекурсивная локальная ЗАДАЧА-------------------*)
ЗАДАЧА ^stat(n:ПД.ДкУзлу);

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ProcEnter(n:ПД.ДкУзлу);
ПОСТ
  АДРЕСОВ=10;
ПЕР
  задача:ВД.ДкПонятию;
  startLine,конСтрока:ЦЕЛ;
  lineNumInx:ЦЕЛ;
  startOffs:ЦЕЛ;
  адреса:РЯД АДРЕСОВ ИЗ ЦЕЛ; (* адреса переменных доступа в задаче *)
  адресов:ЦЕЛ;               (* наполнение адресов *)
УКАЗ
  задача:=n.пон;
  ПРОВЕРИТЬ((задача.родп = пЗадача) ИЛИ (задача.родп = пОтдел));
  УВЕЛИЧИТЬ(ЗК.уровень);
  stat(n.лево);  (* вложенные задачи *)
  УМЕНЬШИТЬ(ЗК.уровень);
  startLine:=n.текстп.строка;
  конСтрока:=n.конСтрока;
  адресов:=ДоступыЗадачи(задача,адреса);
  КУ.Enter(задача,startLine,startOffs,lineNumInx,адреса,адресов);
  stat(n.право); (* указания *)
  КУ.Leave(задача,startLine,startOffs,lineNumInx,конСтрока);
КОН ProcEnter;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА IfStat(n:ПД.ДкУзлу; withtrap:КЛЮЧ);
ПЕР
  x:ЗК.нItem;
  Lcfj,Lfix:ЗК.Label;
  if:ПД.ДкУзлу;
УКАЗ
  Lfix:=0;
  if:=n.лево;
  КОЛЬЦО
    ОО.текПоз:=if.текстп;
    Coff.AddLineNum(ЗК.pc,if.текстп.строка,ОТКЛ);
    expr(if.лево,x);
    КУ.CFJ(x,Lcfj);
    ЗК.Release(x);
    stat(if.право);
    if:=if.след;
    ЕСЛИ if = ПУСТО ТО ВЫХОД КОН;
    КУ.FJ(Lfix);
    ЗК.FixLink(Lcfj)
  КОН;
  ЕСЛИ (n.право # ПУСТО) ИЛИ withtrap ТО
    КУ.FJ(Lfix);
    ЗК.FixLink(Lcfj);
    ЕСЛИ withtrap ТО
      ОО.текПоз:=n.текстп;
      ЗК.Ловушка(дляАвОст)
    ИНАЧЕ
      stat(n.право)
    КОН
  ИНАЧЕ
    ЗК.FixLink(Lcfj)
  КОН;
  ЗК.FixLink(Lfix);
  Coff.AddLineNum(ЗК.pc,n.лево.конСтрока,ОТКЛ)
КОН IfStat;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА CaseStat(n:ПД.ДкУзлу);
ПЕР
  x:ЗК.нItem;
  Lfix:ЗК.Label;
  case,lab:ПД.ДкУзлу;
  tab,low,high:ЦЕЛ;
УКАЗ
  expr(n.лево,x);
  low:=n.право.пост.цел1;
  high:=n.право.пост.цел2;
  КУ.Case(x,low,high,tab);
  ЗК.Release(x);
  Lfix:=0;
  ЕСЛИ n.право.пост.множ # {} ТО (* ELSE clause *)
    stat(n.право.право);
    КУ.FJ(Lfix);
  ИНАЧЕ
    ЗК.Ловушка(выбратьАвОст)
  КОН;
  case:=n.право.лево;
  ПОКА case # ПУСТО ВЫП    (* case.роду = Ncasedo *)
    lab:=case.лево;
    ПОКА lab # ПУСТО ВЫП
      ЗК.CaseJump(tab,lab.пост.цел1-low,lab.пост.цел2-low);
      lab:=lab.след
    КОН;
    stat(case.право);
    КУ.FJ(Lfix);
    case:=case.след
  КОН;
  ЗК.FixLink(Lfix)
КОН CaseStat;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА СоздатьОРяд(x+,z+:ЗК.нItem;
                       n:ПД.ДкУзлу;
          dimtyp,dim0typ:ВД.ДкВиду);
ПЕР
  y:ЗК.нItem;
УКАЗ
  expr(n,y);
  КУ.УмножДлРазм(z,y,dimtyp,dim0typ);
  ЕСЛИ (n.след # ПУСТО) И (dim0typ.овид.родв # вЗнак) ТО
    СоздатьОРяд(x,z,n.след,dimtyp.овид,dim0typ)
  ИНАЧЕ
    КУ.СоздатьОРяд(x,z)
  КОН;
  КУ.УстДлРазм(x,dimtyp);
  ЕСЛИ (n.след # ПУСТО) И (dim0typ.овид.родв = вЗнак) ТО
    expr(n.след,y);
    КУ.Copy(x,y);
    ЗК.Release(y)
  КОН
КОН СоздатьОРяд;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА stat(n:ПД.ДкУзлу);
(*
 *  Цель: evaluates the statement of узел 'n'
 *    До: n = ancore узел of statement
 *)
ПЕР
  x,y,z:ЗК.нItem;
  задача:ВД.ДкПонятию;
  L,Lcfj,prevExitChain:ЗК.Label;
  овид:ВД.ДкВиду;
УКАЗ
  ПОКА n # ПУСТО ВЫП
    ОО.текПоз:=n.текстп;
    ЗК.BegStat;
    ЕСЛИ n.роду # Nenter ТО
      Coff.AddLineNum(ЗК.pc,n.текстп.строка,ОТКЛ)
    КОН;
    ВЫБРАТЬ n.роду ИЗ
    | Nenter:
        ProcEnter(n)
    | Nassign:
        ВЫБРАТЬ n.подроду ИЗ
        | assign:
            expr(n.право,y);
            ЕСЛИ y.тип = Coc ТО СК.CocToReg(y) КОН;
            expr(n.лево,x);
            КУ.Assign(x,y);
            ЗК.Release(y)
        | зСоздать:
            expr(n.лево,x);
            овид:=x.вид.овид;
            ЕСЛИ n.право # ПУСТО ТО
              СоздатьОРяд(x,z,n.право,овид,овид)
            ИНАЧЕ
              КУ.Создать(x)
            КОН
        | зОбнулить:
            expr(n.лево,x);
            КУ.Обнулить(x)
        | зСтоп:
            expr(n.лево,x);
            КУ.Стоп(x)
        | зОбраз:   (* x^:=перв z байт из y *)
            expr(n.право.след,z);
            expr(n.право,y);
            expr(n.лево,x);
            КУ.SYSmove(x,y,z);
            ЗК.Release(y);
            ЗК.Release(z)
        | зПоставить:   
            (* поставить бегунок 'x' на переменную ряда 'y' с номером 'z' *)
            expr(n.право.след,z);
            expr(n.право,x);
            expr(n.лево,y);
            КУ.Поставить(x,y,z);
            ЗК.Release(y);
            ЗК.Release(z)
        ИНАЧЕ
          expr(n.лево,x);
          expr(n.право,y);
          ВЫБРАТЬ n.подроду ИЗ
          | зУвеличить:
              КУ.Increment(x,y,ОТКЛ)
          | зУменьшить:
              КУ.Increment(x,y,ВКЛ)
          | зСместить:
              КУ.Пропустить(x,y)
          | зСписать:
              КУ.Copy(x,y)
          | зИзПамяти:
              КУ.SYSgetput(x,y,ВКЛ)
          | зВПамять:
              КУ.SYSgetput(x,y,ОТКЛ)
          КОН;
          ЗК.Release(y)
        КОН;
        ЗК.Release(x)
    | Ncall:
        ЕСЛИ n.вид # ВД.нетвид ТО
          ОО.Ошибка(ОО.ЛИШНИЙ_ОТВЕТ)
        КОН;
        ЕСЛИ n.лево.роду = Nproc ТО (* просто ЗАДАЧА ? *)
          задача:=n.лево.пон;
          ЕСЛИ задача.пост.цел1 = -1 ТО
            ParamSize(задача.след,задача.пост.цел1)
          КОН
        ИНАЧЕ (* переменная вида ЗАДАЧА *)
          ПРОВЕРИТЬ(n.лево.вид.родв = вЗадача);
          задача:=ПУСТО;
          ЕСЛИ n.лево.пост = ПУСТО ТО
            n.лево.пост:=ВД.СоздатьПост();
            n.лево.пост.цел1:=-1
          КОН;
          ЕСЛИ n.лево.пост.цел1 = -1 ТО
            ParamSize(n.лево.вид.след,n.лево.пост.цел1)
          КОН
        КОН;
        DeSign(n.лево,x);
        x.вид:=ВД.нетвид; (* get result type *)
        ActualPar(n.право,n.пон);
        ЕСЛИ задача # ПУСТО ТО
          КУ.CallProc(задача)
        ИНАЧЕ
          КУ.CallVar(x)
        КОН;
        ЗК.Release(x)
    | NcallTuda:
        КУ.ВходВПринимаемую;
        задача:=n.лево.пон;
        ParamAdr(задача.след,задача.пост.цел1,ОТКЛ);
        ActualParDLL(n.право,ОТКЛ); (* список <источники> *)
        КУ.CallDllProc(задача)
    | NcallSuda:
        КУ.ВходВПередаваемую;
        ActualParDLL(n.право,ВКЛ);  (* список <источники> *)
        КУ.CallProc(n.лево.пон);
        КУ.ВыходИзПередаваемой
    | Nifelse:
        IfStat(n,ОТКЛ)
    | Ncase:
        CaseStat(n)
    | Nwhile:
        L:=ЗК.pc;
        expr(n.лево,x);
        КУ.CFJ(x,Lcfj);
        ЗК.Release(x);
        stat(n.право);
        Coff.AddLineNum(ЗК.pc,n.конСтрока,ОТКЛ);
        КУ.BJ(L);
        ЗК.FixLink(Lcfj)
    | Nrepeat:
        L:=ЗК.pc;
        stat(n.лево);
        Coff.AddLineNum(ЗК.pc,n.конСтрока,ОТКЛ);
        expr(n.право,x);
        КУ.CBJ(x,L);
        ЗК.Release(x)
    | Nloop:
        prevExitChain:=ExitChain;
        ExitChain:=0;
        L:=ЗК.pc;
        stat(n.лево);
        Coff.AddLineNum(ЗК.pc,n.конСтрока,ОТКЛ);
        КУ.BJ(L);
        ЗК.FixLink(ExitChain);
        ExitChain:=prevExitChain
    | Nexit:
        КУ.FJ(ExitChain)
    | Nreturn:
        ЕСЛИ n.лево # ПУСТО ТО
          expr(n.лево,x);
          КУ.Result(n.пон,x);
          ЗК.Release(x)
        КОН;
        КУ.Exit(n.пон)
    | Nwith:
        IfStat(n,НЕ n.толькочт)
    | Ntrap:
        ЗК.Ловушка(УЗК(n.право.пост.цел))
    КОН;
    ЗК.EndStat;
    n:=n.след
  КОН
КОН stat;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Module-(задачи:ПД.ДкУзлу);
(*
 *  Цель: выработка кода для всего отдела
 *    До: задачи - головная задача отдела
 *)
УКАЗ
  stat(задачи)
КОН Module;

КОН ОД.
