define @emNOTAVAIL   "Не pеализовано"
define @emINTERNAL   "Внутpенняя ошибка"
define @emNOMEMORY   "Недостаточно памяти"
define @emEOF        "Конец файла"
define @emWRITEERR   "Ошибка записи"
define @emTHENEXP    "Пpопущено then"
define @emCASEEXP    "Пpопущено case"
define @emDOEXPECTED "Пpопущено do"
define @emLOOP       "loop/exit вне цикла"
define @emVOID       "Тип void недопустим"
define @emTYPE       "Несоответствие типов"
define @emBOOLEAN    "Тpебуется условие"
define @emPOINTER    "Ссылка недопустима"
define @emNOPTR      "Тpебуется ссылка"
define @emLVALUE     "Пpисваивание недопустимо"
define @emEXPECTED   "Пpопущен идентификатоp"
define @emDOUBLE     "Повтоpное описание"
define @emEMPTY      "Pаздел пуст"
define @emSIZE       "Слишком длинный идентификатоp"
define @emASSIGN     "Пpопущено ="
define @emSTRING     "Пpопущена двойная кавычка"
define @emLONG       "Слишком длинная стpока"
define @emCHAR       "Пpопущена кавычка"
define @emNUMBER     "Ошибка в константе"
define @emOVERFLOW   "Константа слишком велика"
define @emARRAY      "Пустой массив"
define @emFORWARD    "Не опpеделено"
define @emSTRUCTURE  "Стpуктуpа слишком велика"
define @emNOBRACKET  "Скобка недопустима"
define @emSBRACKET   "Пpопущена скобка"
define @emCBRACKET   "Пpопущена скобка"
define @emOPERATOR   "Два опеpатоpа подpяд"
define @emADDR       "Невозможно вычислить адpес"
define @emNULL       "Пpопущено NULL"
define @emUNDEFOPR   "Опеpация не опpеделена"
define @emCOMMA      "Пpопущена запятая"
define @emEQUAL      "Тpебуется одинаковый поpядок ссылок"
define @emCOLON      "Пpопущено двоеточие"
define @emSEMICOLON  "Пpопущена точка с запятой"
define @emNOTMATCH   "Несоответствие объявлению"
define @emFIELD      "Пpопущено поле"
define @emFUNCTION   "Описание функции недопустимо"
define @emINIT       "Инициализация массива невозможна"
define @emNOTYPE     "Тип не найден"
define @emCLASSEXP   "Тpебуется имя класса"
define @emNOSECTION  "Секция недопустима"
define @emMETHOD     "Недопустимо внутpи функции"
define @emNOBASE     "Нет базового класса"
define @emNOINDEX    "Индексация недопустима"
define @emDEFINE     "Объявление недопустимо"

define  Smax   65520

define  idSIZE    16
define  ttSIZE   128
define  ftSIZE   512
define  stSIZE   128
define  rtSIZE   128
define  ptSIZE   512
define  dtSIZE   128
define  vtSIZE   128
define  ctSIZE   128
define  cbSIZE  8192
define  rbSIZE   512
define  itSIZE   512
define  jtSIZE    64
define  ssSIZE   128

define  srNO       0
define  srAX       1
define  srCS       2
define  srDS       3
define  srBP       4
define  srBN       5
define  srSP       6
define  srES       7
define  sr87       8

define  rgAX       0
define  rgDX       1
define  rgSI       2
define  rgDI       3
define  rgES       4

define  ttVOID     0
define  ttBOOL     1
define  ttCHAR     2
define  ttBYTE     3
define  ttWORD     4
define  ttINT      5
define  ttREAL     6

define  obDATA     0
define  obSTAT     1
define  obVIRT     2

struct long
  word Low;
  word High;
end

struct OpInfo
  word pType;
  word Seg;
  word Ofs;
  word High;
  word nPtr;
  word Index;
  word Value;
end

struct TT
  char Name [idSIZE];
  word pBase;
  word pField;
  word nField;
  word Size;
  word Ofs;
  word Lock;
end

struct FT
  char Name [idSIZE];
  word pType;
  word pMethod;
  word fMethod;
  word pIndex;
  word nIndex;
  word nPtr;
  word Ofs;
end

struct ST
  char Name [idSIZE];
  word pType;
  word pParm;
  word nParm;
  word nPtr;
  word Ofs;
end

struct RT
  long Pos;
  word Ref;
end

struct PT
  char Name [idSIZE];
  word pType;
  word nPtr;
  word Ofs;
end

struct VT
  char Name [idSIZE];
  word pType;
  word pIndex;
  word nIndex;
  word nPtr;
  word Ofs;
end

struct DT
  char Name [idSIZE];
  word pType;
  word pIndex;
  word nIndex;
  word nPtr;
  word Ofs;
end

struct CT
  char Name [idSIZE];
  word pType;
  word nPtr;
  word Low;
end

TT   TTabl [ttSIZE];
word nType;

FT   FTabl [ftSIZE];
word nField;

ST   STabl [stSIZE];
word nSub;

RT   RTabl [rtSIZE];
word nRef;

PT   PTabl [ptSIZE];
word nParm;

VT   VTabl [vtSIZE];
word nVar;

DT   DTabl [dtSIZE];
word DSize;
word nData;

CT   CTabl [ctSIZE];
word nConst;

char CBuff [cbSIZE];
word nByte;

char RBuff [rbSIZE];
word nReal;

word ITabl [itSIZE];
word nIndex;

long JTabl [jtSIZE];
word nJump;

word Regs  [5];

word Stack [ssSIZE];
word SP;

word RSize;
word PSize;
word VSize;
word SSize;

word pStr;
word pSub;

word Loop;

char Buff  [4096];
word pChar;
word nChar;
//word Ready;

char Dest  [4096];
word pDest;
word mDest;
word fDest;

word Class;
word Label;
word Line;

char Name  [13];
word F1;
word F2;

word CharToByte(char Ch)
  void  @P=@Ch;
  word  @W=@P;
  return W&255;
end

void @Ptr(word Seg, Ofs)
  void   @P1=@Ofs;
  void  @@P2=@P1;
  return @P2;
end

word isalpha(char Ch)
  if ('a'<=Ch & Ch<='z') then
    return 0;
  end

  if ('A'<=Ch & Ch<='Z') then
    return 0;
  end

  if (Ch='_') then
    return 0;
  end

  return   1;
end

word isdigit(char Ch)
  if ('0'<=Ch & Ch<='9') then
    return 0;
  end

  return   1;
end

word ishexdec(char Ch)
  if ('0'<=Ch & Ch<='9') then
    return 0;
  end

  if ('A'<=Ch & Ch<='F') then
    return 0;
  end

  if (Ch='$') then
    return 0;
  end

  return   1;
end

word strlen(char @Buff)
  word P=0;
  while Buff[P]!=#0 do
    inc P;
  end
  return P;
end

word strcmp(char @St1, @St2)
  word P=0;
  while TRUE do
    if St1[P]!=St2[P] then
      return 1;
    end
    if St1[P]=#0 then
      return 0;
    end
    inc P;
  end
end

word strchr(char @Buff; char Ch)
  if Buff[0]!=Ch then
    return 1;
  end
  if Buff[1]!=#0 then
    return 1;
  end
  return 0;
end

char @strcpy(char @Dst, @Src)
  word P=0;
  while Src[P]!=#0 do
    Dst[P]=Src[P];
    inc P;
  end
  Dst[P]=#0;
  return @Dst;
end

char @strcat(char @Dst, @Src)
  word P=strlen(@Dst);
  word Q=0;
  while Src[Q]!=#0 do
    Dst[P]=Src[Q];
    inc P;
    inc Q;
  end
  Dst[P]=#0;
  return @Dst;
end

word GetPSP()
  asm mov     AH,62H
  asm int     21H
  asm mov     AX,BX
end

word create(char @Name)
  asm push    DS
  asm mov     AH,3CH
  asm mov     CX,00H
  asm mov     DX,SS:[BP+6]
  asm mov     DS,DX
  asm mov     DX,SS:[BP+4]
  asm int     21H
  asm pop     DS
end

word open(char @Name)
  asm push    DS
  asm mov     AH,3DH
  asm mov     AL,00H
  asm mov     DX,SS:[BP+6]
  asm mov     DS,DX
  asm mov     DX,SS:[BP+4]
  asm int     21H
  asm db      73H, 03H
  asm mov     AX,0FFFFH
  asm pop     DS
end

word read(word F; void @Buff; word N)
  asm push    DS
  asm mov     AH,3FH
  asm mov     BX,SS:[BP+10]
  asm mov     CX,SS:[BP+4]
  asm mov     DX,SS:[BP+8]
  asm mov     DS,DX
  asm mov     DX,SS:[BP+6]
  asm int     21H
  asm pop     DS
end

word write(word F; void @Buff; word N)
  asm push    DS
  asm mov     AH,40H
  asm mov     BX,SS:[BP+10]
  asm mov     CX,SS:[BP+4]
  asm mov     DX,SS:[BP+8]
  asm mov     DS,DX
  asm mov     DX,SS:[BP+6]
  asm int     21H
  asm pop     DS
end

void close(word F)
  asm mov     AH,3EH
  asm mov     BX,SS:[BP+4]
  asm int     21H
end

void putc(char Ch)
  asm mov     AH,2
  asm mov     DL,SS:[BP+4]
  asm int     21H
end

void puts(char @St)
  word P=0;
  while St[P]!=#0 do
    putc(St[P]);
    inc P;
  end
end

void outs(char @St)
  puts(@St);
  putc(#13);
  putc(#10);
end

word str(word N; word S; char @Buff)
  if S>0 then
    dec S;
  end

  word P=0;
  if N>=10 | S>0 then
    P=str(N/10,S,@Buff);
  end

  char @D = "0123456789";
  Buff [P]=D[N%10];

  return P+1;
end

char @Str(word N; word S)
  char   @P="00000";
  P[str(N,S,@P)]=#0;
  return @P;
end

void Stop(char @EM)
  putc(#13);
  puts(@Name);
  puts("(");
  puts(@Str(Line,0));
  puts(")");
  puts(": ");
  puts(@EM);

  close (F2);
  close (F1);

  asm mov     AX,4C00H
  asm int     21H
end

word Add(word A, B)
  word C1=A/256+B/256;
  word C0=A%256+B%256;

  C1=C1+C0/256;
  C0=C0%256;

  if (C1>255) then
    C1=255;
    C0=255;
  end

  return 256*C1+C0;
end

word Mul(word A, B)
  word A1=A/256;
  word A0=A%256;
  word B1=B/256;
  word B0=B%256;

  if ((A1*B1>0) | (Add(A1*B0,A0*B1)>255)) then
    return 65535;
  end

  return Add(256*(A1*B0+A0*B1),A0*B0);
end

long StoD(char @Buff)
  char @D = "0123456789ABCDEF";
  word  B[4];
  word  K;
  word  P;
  word  E;
  long  R;

  K=0;
  while (K<4) do
    B[K]=0;
    inc K;
  end

  E=10;
  P= 0;
  if Buff[0]='$' then
    E=16;
    P= 1;
  end

  while (Buff[P]!=#0) do
    word S=0;
    while D[S]!=#0 do
      if D[S]=Buff[P] then
        exit
      end

      inc S;
    end

    if S>=E then
      Stop(@emNUMBER);
    end

    K=0;
    while (K<4) do
      S   =E*B[K]+S;
      B[K]=S%256;
      S   =S/256;
      inc  K;
    end

    if (S>0) then
      Stop(@emOVERFLOW);
    end

    inc P;
  end

  R.High=256*B[3]+B[2];
  R.Low =256*B[1]+B[0];

  return R;
end

word StoR(word @Temp; word S1, P1)
  asm  fldz

  word I=0;
  while Temp[I]<10 do
    word N=Temp[I];
    word D=10;

    asm  fild    SS:[BP-6]
    asm  fmulp
    asm  fild    SS:[BP-4]
    asm  faddp

    inc  I;
  end

  if S1=0 then
    while P1>0 do
      word D=10;
      asm fild    SS:[BP-4]
      asm fmulp
      dec P1;
    end
  else
    while P1>0 do
      word D=10;
      asm fild    SS:[BP-4]
      asm fdivp
      dec P1;
    end
  end

  char Data [8];

  asm fstp    SS:[BP-10]

  word P=nReal;

  I=0;
  while I<8 do
    if (nReal>=rbSIZE) then
      Stop(@emNOMEMORY);
    end

    RBuff[nReal]=Data[I];
    inc   nReal;

    inc   I;
  end

  return P;
end

word StoN(char @Buff)
  char @D = "0123456789";

  word  Temp [128];

  word  P1=0;
  word  P2=0;
  word  S1=0;

  word  F =0;
  word  I =0;
  word  K =0;

  if Buff[0]='$' then
    return nReal;
  end

  while Buff[I]='0' do
    inc I;
  end

  while Buff[I]!=#0 do
    if Buff[I]='E' then
      select
        case Buff[I+1]='+':
          S1=0;
        case Buff[I+1]='-':
          S1=1;
        default:
          Stop(@emNUMBER);
      end

      if Buff[I+2]=#0 then
        Stop(@emNUMBER);
      end

      P2=StoD(@Buff[I+2]).Low;
      F =1;

      exit
    end

    if Buff[I]='.' then
      F = 1;
      inc I;
      loop
    end

    word S=0;
    while D[S]!=#0 do
      if D[S]=Buff[I] then
        exit
      end

      inc S;
    end

    if S>=10 then
      Stop(@emNUMBER);
    end

    if F!=0 then
      inc P1;
    end

    Temp[K]=S;
    inc  K;

    inc  I;
  end

  Temp[K]=10;

  if F=0 then
    return nReal;
  end

  if S1=0 then
    if P1>P2 then
      P1=P1-P2;
      S1=1;
    else
      P1=P2-P1;
    end
  else
    P1=P1+P2;
  end

  if K>16 then
    Stop(@emNUMBER);
  end

  if P1>290 then
    Stop(@emNUMBER);
  end

  return StoR(@Temp,S1,P1);
end

void Seek(long P)
  word F=F2;
  word H;
  word L;

  asm push    DS
  asm mov     AX,4202H
  asm mov     BX,SS:[BP-2]
  asm mov     CX,0
  asm mov     DX,0
  asm int     21H
  asm pop     DS

  asm mov     CX,SS:[BP+6]
  asm mov     BX,SS:[BP+4]
  asm sub     BX,AX
  asm sbb     CX,DX
  asm mov     SS:[BP-4],CX
  asm mov     SS:[BP-6],BX

  if H!=0 then
    if pDest>0 then
      if (write(F2,@Dest,pDest)!=pDest) then
        Stop(@emWRITEERR);
      end
      pDest=0;
    end

    asm push    DS
    asm mov     AX,4200H
    asm mov     BX,SS:[BP-2]
    asm mov     CX,SS:[BP+6]
    asm mov     DX,SS:[BP+4]
    asm int     21H
    asm pop     DS

    fDest=2;
  else
    mDest=pDest;
    pDest=L;
    fDest=1;
  end
end

long Back()
  select
    case fDest=2:
      if pDest>0 then
        if (write(F2,@Dest,pDest)!=pDest) then
          Stop(@emWRITEERR);
        end
        pDest=0;
      end

    case fDest=1:
      pDest=mDest;
  end

  fDest=0;

  word F=F2;
  word P=pDest;

  asm push    DS
  asm mov     AX,4202H
  asm mov     BX,SS:[BP-2]
  asm mov     CX,0
  asm mov     DX,0
  asm int     21H
  asm pop     DS
  asm add     AX,SS:[BP-4]
  asm adc     DX,0
end

char code [64];

void Code(word L; char @S)
  char Buff [128];
  word N;

  strcpy(@code,@S); // for inc/dec

  if (L!=0) then
    strcpy(@Buff,"@");
    strcat(@Buff,@Str(L,5));
    strcat(@Buff,": ");
  else
    strcpy(@Buff,"        ");
  end

  N=strlen(@strcat(@Buff,@S));

  Buff[N]=#13;
  inc  N;
  Buff[N]=#10;
  inc  N;

  word I=0;
  while I<N do
    if (pDest>=4096) then
      if (write(F2,@Dest,pDest)!=pDest) then
        Stop(@emWRITEERR);
      end
      pDest=0;
    end

    Dest[pDest]=Buff[I];
    inc  pDest;
    inc  I;
  end
end

void Jump(word L)
  char Buff [128];
  strcpy(@Buff,"jmp     @");
  if (L!=0) then
    strcat(@Buff,@Str(L,5));
  else
    strcat(@Buff,"00000");
  end
  Code(0,@Buff);
  Back();
end

char Read()
  if (pChar>=nChar) then
    nChar=read(F1,@Buff,4096);
    if (nChar<1) then
      Stop(@emEOF);
    end
    pChar=0;
  end
  return Buff[pChar];
end

void Next()
  inc pChar;
end
/*
void Keep()
  Ready=1;
end
*/
char @Scan(char @Buff)
  word N;
  word P;

/*if (Ready!=0) then
    Ready=0;
    return @Buff;
  end*/

  N=0;
  while TRUE do
    while ((Read()=#09) | (Read()=#10) | (Read()=#13) | (Read()=#32)) do
      if (Read()=#10) then
        inc Line;
        if (Line%100=0) then
          putc(#13);
          puts(@strcat(@strcat(@strcat(@strcpy(@Buff,@Name),"("),@Str(Line,0)),")"));
        end
      end
      Next();
    end

    if (Read()='/') then
      Next();
      if (Read()='*') then
        Next();
        inc N;
      end

      if (N>0) then
        loop
      end

      if (Read()='/') then
        while (Read()!=#10) do
          Next();
        end
        loop
      end

      return @strcpy(@Buff,"/");
    end

    if (N=0) then
      exit
    end

    if (Read()='*') then
      Next();
      if (Read()='/') then
        Next();
        dec N;
      end
      loop
    end

    Next();
  end

  P=0;
  select
    case isalpha(Read())=0:
      while ((isalpha(Read())=0) | (isdigit(Read())=0)) do
        Buff[P]=Read();
        inc  P;
        if  (P>=idSIZE) then
          Stop(@emSIZE);
        end

        Next();
      end

      Buff[P]=#0;
      return  @Buff;

    case isdigit(Read())=0:
      while ((isdigit(Read())=0) | (Read()='.') | (Read()='E')) do
        if Read()='E' then
          Buff[P]=Read(); Next();
          inc  P;

          Buff[P]=Read(); Next();
          inc  P;

          loop
        end

        Buff[P]=Read();
        inc  P;
        if  (P>=64) then
          Stop(@emSIZE);
        end

        Next();
      end

      Buff[P]=#0;
      return  @Buff;

    case ishexdec(Read())=0:
      while (ishexdec(Read())=0) do
        Buff[P]=Read();
        inc  P;
        if  (P>=idSIZE) then
          Stop(@emSIZE);
        end

        Next();
      end

      Buff[P]=#0;
      return  @Buff;
  end

  if (Read()='!') then
    Next();
    if (Read()='=') then
      Next();
      return @strcpy(@Buff,"!=");
    end
    return @strcpy(@Buff,"!");
  end

  if (Read()='<') then
    Next();
    if (Read()='=') then
      Next();
      return @strcpy(@Buff,"<=");
    end
    return @strcpy(@Buff,"<");
  end

  if (Read()='>') then
    Next();
    if (Read()='=') then
      Next();
      return @strcpy(@Buff,">=");
    end
    return @strcpy(@Buff,">");
  end

  Buff[0]=Read(); Next();
  Buff[1]=#0;

  return @Buff;
end

word FindType(char @Name)
  word P=0;
  while ((P<nType) & (strcmp(@TTabl[P].Name,@Name)!=0)) do
    inc P;
  end
  return P;
end

word FindSub(char @Name)
  word P=0;
  while ((P<nSub) & (strcmp(@STabl[P].Name,@Name)!=0)) do
    inc P;
  end
  return P;
end

word FindData(char @Name)
  word P=0;
  while ((P<nData) & (strcmp(@DTabl[P].Name,@Name)!=0)) do
    inc P;
  end
  return P;
end

word FindVar(char @Name)
  word P=0;
  while ((P<nVar) & (strcmp(@VTabl[P].Name,@Name)!=0)) do
    inc P;
  end
  return P;
end

word FindConst(char @Name)
  word P=0;
  while ((P<nConst) & (strcmp(@CTabl[P].Name,@Name)!=0)) do
    inc P;
  end
  return P;
end

void Init()
  word K=0;
  while (K<=rgES) do
    Regs[K]=0;
    inc  K;
  end
  SP=0;
end

void Push(word R)
  if (Regs[R]!=0) then
    select
      case R=rgAX:
        Code(0,"push    AX");
      case R=rgDX:
        Code(0,"push    DX");
      case R=rgSI:
        Code(0,"push    SI");
      case R=rgDI:
        Code(0,"push    DI");
      case R=rgES:
        Code(0,"push    ES");
      default:
        Stop(@emINTERNAL);
    end

    if (SP>=ssSIZE) then
      Stop(@emNOMEMORY);
    end

    Stack[SP]=R;
    inc   SP;

    Regs[R]=0;
  end
end

void Pop (word R)
  while (Regs[R]=0) do
    if (SP=0) then
      Stop(@emINTERNAL);
    end

    dec SP;

    if (Regs[Stack[SP]]!=0) then
      Stop(@emINTERNAL);
    end

    select
      case Stack[SP]=rgAX:
        Code(0,"pop     AX");
      case Stack[SP]=rgDX:
        Code(0,"pop     DX");
      case Stack[SP]=rgSI:
        Code(0,"pop     SI");
      case Stack[SP]=rgDI:
        Code(0,"pop     DI");
      case Stack[SP]=rgES:
        Code(0,"pop     ES");
      default:
        Stop(@emINTERNAL);
    end

    Regs[Stack[SP]]=1;
  end
end

word call;
word push;

void LDAX(OpInfo @Op1)
  char Buff [128];

  push=0;

  if (Op1.Value=0) then
    select
      case Op1.Seg=srNO:
        Push(rgDX);
        Push(rgAX);
        Code(0,"xor     DX,DX");
        Code(0,"xor     AX,AX");

      case Op1.Seg=srAX:
        Pop (rgDX);
        Pop (rgAX);

      case Op1.Seg=srCS:
        if call!=0 then
          Code(0,@strcat(@strcpy(@Buff,"mov     BX,offset @16384 + "),@Str(Op1.Ofs,0)));
          Code(0,"push    CS");
          Code(0,"push    BX");
          push=1;
        else
          Push(rgDX);
          Push(rgAX);
          Code(0,@strcat(@strcpy(@Buff,"mov     AX,offset @16384 + "),@Str(Op1.Ofs,0)));
          Code(0,"mov     DX,CS");
        end

      case Op1.Seg=srDS:
        select
          case Op1.Index=1:
            Pop (rgDI);
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(Op1.Ofs,0)));
            Code(0,"add     AX,DI");
            Code(0,"mov     DX,DS");
            Regs[rgDI]=0;

          case Op1.Index=2:
            Pop (rgSI);
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(Op1.Ofs,0)));
            Code(0,"add     AX,SI");
            Code(0,"mov     DX,DS");
            Regs[rgSI]=0;

          default:
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(Op1.Ofs,0)));
            Code(0,"mov     DX,DS");
        end

      case Op1.Seg=srBP:
        select
          case Op1.Index=1:
            Pop (rgDI);
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(Op1.Ofs,0)));
            Code(0,"add     AX,BP");
            Code(0,"add     AX,DI");
            Code(0,"mov     DX,SS");
            Regs[rgDI]=0;

          case Op1.Index=2:
            Pop (rgSI);
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(Op1.Ofs,0)));
            Code(0,"add     AX,BP");
            Code(0,"add     AX,SI");
            Code(0,"mov     DX,SS");
            Regs[rgSI]=0;

          default:
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(Op1.Ofs,0)));
            Code(0,"add     AX,BP");
            Code(0,"mov     DX,SS");
        end

      case Op1.Seg=srBN:
        select
          case Op1.Index=1:
            Pop (rgDI);
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     DX,"),@Str(Op1.Ofs,0)));
            Code(0,"mov     AX,BP");
            Code(0,"add     AX,DI");
            Code(0,"sub     AX,DX");
            Code(0,"mov     DX,SS");
            Regs[rgDI]=0;

          case Op1.Index=2:
            Pop (rgSI);
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     DX,"),@Str(Op1.Ofs,0)));
            Code(0,"mov     AX,BP");
            Code(0,"add     AX,SI");
            Code(0,"sub     AX,DX");
            Code(0,"mov     DX,SS");
            Regs[rgSI]=0;

          default:
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     DX,"),@Str(Op1.Ofs,0)));
            Code(0,"mov     AX,BP");
            Code(0,"sub     AX,DX");
            Code(0,"mov     DX,SS");
        end

      case Op1.Seg=srES:
        select
          case Op1.Index=1:
            Pop (rgDI);
            Pop (rgES);
            Push(rgDX);
            Push(rgAX);

            if (Op1.Ofs>0) then
              Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(Op1.Ofs,0)));
              Code(0,"add     AX,DI");
            else
              Code(0,"mov     AX,DI");
            end

            Regs[rgDI]=0;

          case Op1.Index=2:
            Pop (rgSI);
            Pop (rgES);
            Push(rgDX);
            Push(rgAX);

            if (Op1.Ofs>0) then
              Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(Op1.Ofs,0)));
              Code(0,"add     AX,SI");
            else
              Code(0,"mov     AX,SI");
            end

            Regs[rgSI]=0;

          default:
            Stop(@emINTERNAL);
        end

        Code(0,"mov     DX,ES");
        Regs[rgES]=0;

      default:
        Stop(@emINTERNAL);
    end

    if push=0 then
      Regs[rgDX]=1;
      Regs[rgAX]=1;
    end

    return
  end

  word S=4;
  if (Op1.nPtr=0) then
    if (Op1.pType=ttVOID) then // if (strcmp(@TTabl[Op1.pType].Name,"void")=0) then
      Stop(@emVOID);
    end

    if (TTabl[Op1.pType].Lock=0) then
      Stop(@emFORWARD);
    end

    if (Op1.Seg=srCS) then
      Code(0,"mov     BX,offset @32768");
      Code(0,@strcat(@strcat(@strcpy(@Buff,"fld     CS:[BX+"),@Str(Op1.Ofs,0)),"]"));

      return
    end

    S=TTabl[Op1.pType].Size;
  end

  if Op1.Seg=srNO then
    select
      case S=1:
        Push(rgAX);
        Code(0,@strcat(@strcpy(@Buff,"mov     AL,"),@Str(Op1.Ofs&255,0)));

      case S=2:
        Push(rgAX);
        Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(Op1.Ofs,0)));

      default:
        Stop(@emINTERNAL);
    end

    Regs[rgAX]=1;

    return
  end

  if Op1.Seg=srAX then
    select
      case S=1:
        select
          case Op1.High=1:
            Pop (rgAX);
          case Op1.High=2:
            Pop (rgAX);
          case Op1.High=4:
            Pop (rgDX);
            Pop (rgAX);
            Regs[rgDX]=0;
          default:
            Stop(@emINTERNAL);
        end

        select
          case Op1.Ofs=0:
          case Op1.Ofs=1:
            Code(0,"mov     AL,AH");
          case Op1.Ofs=2:
            Code(0,"mov     AL,DL");
          case Op1.Ofs=3:
            Code(0,"mov     AL,DH");
          default:
            Stop(@emINTERNAL);
        end

      case S=2:
        select
          case Op1.High=2:
            Pop (rgAX);
          case Op1.High=4:
            Pop (rgDX);
            Pop (rgAX);
            Regs[rgDX]=0;
          default:
            Stop(@emINTERNAL);
        end

        select
          case Op1.Ofs=0:
          case Op1.Ofs=1:
            Code(0,"mov     AL,AH");
            Code(0,"mov     AH,DL");
          case Op1.Ofs=2:
            Code(0,"mov     AX,DX");
          default:
            Stop(@emINTERNAL);
        end

      case S=4:
        if (Op1.High!=4) then
          Stop(@emINTERNAL);
        end

        if (Op1.Ofs!=0) then
          Stop(@emINTERNAL);
        end

        Pop (rgDX);
        Pop (rgAX);

        Regs[rgDX]=1;

      default:
        Stop(@emINTERNAL);
    end

    Regs[rgAX]=1;

    return
  end

  if Op1.Seg=sr87 then
    return
  end

  select
    case S=1:
      strcpy(@Buff,"mov     AL,");

    case S=2:
      strcpy(@Buff,"mov     AX,");

    case S=4:
      strcpy(@Buff,"mov     AX,");

    case Op1.pType=ttREAL:
      strcpy(@Buff,"fld     ");

    default:
      Stop(@emINTERNAL);
  end

  select
    case Op1.Seg=srDS:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          strcat(@Buff,"DS:[DI+");
          Regs  [rgDI]=0;

        case Op1.Index=2:
          Pop   (rgSI);
          strcat(@Buff,"DS:[SI+");
          Regs  [rgSI]=0;

        default:
          strcat(@Buff,"DS:[");
      end

    case Op1.Seg=srBP:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          strcat(@Buff,"SS:[BP][DI+");
          Regs  [rgDI]=0;

        case Op1.Index=2:
          Pop   (rgSI);
          strcat(@Buff,"SS:[BP][SI+");
          Regs  [rgSI]=0;

        default:
          strcat(@Buff,"SS:[BP+");
      end

    case Op1.Seg=srBN:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          strcat(@Buff,"SS:[BP][DI-");
          Regs  [rgDI]=0;

        case Op1.Index=2:
          Pop   (rgSI);
          strcat(@Buff,"SS:[BP][SI-");
          Regs  [rgSI]=0;

        default:
          strcat(@Buff,"SS:[BP-");
      end

    case Op1.Seg=srES:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          Pop   (rgES);
          strcat(@Buff,"ES:[DI+");
          Regs  [rgDI]=0;
          Regs  [rgES]=0;

        case Op1.Index=2:
          Pop   (rgSI);
          Pop   (rgES);
          strcat(@Buff,"ES:[SI+");
          Regs  [rgSI]=0;
          Regs  [rgES]=0;

        default:
          Stop(@emINTERNAL);
      end
  end

  select
    case S=1:
      Push(rgAX);
      Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"]"));
      Regs[rgAX]=1;

    case S=2:
      Push(rgAX);
      Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"]"));
      Regs[rgAX]=1;

    case S=4:
      char     Temp [128];
      strcpy (@Temp,@Buff);

      Temp[8]='D'; // !!!

      word     Ofs=Op1.Ofs;

      Push(rgDX);
      Push(rgAX);

      Code(0,@strcat(@strcat(@Buff,@Str(Ofs,0)),"]"));

      if Op1.Seg!=srBN then
        Ofs=Ofs+2;
      else
        Ofs=Ofs-2;
      end

      Code(0,@strcat(@strcat(@Temp,@Str(Ofs,0)),"]"));

      Regs[rgDX]=1;
      Regs[rgAX]=1;

    case Op1.pType=ttREAL:
      Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"]"));

    default:
      Stop(@emINTERNAL);
  end
end

void LDBX(OpInfo @Op1; word pType)
  word S=4;
  if (Op1.nPtr=0) then
    if (Op1.pType=ttVOID) then // if (strcmp(@TTabl[Op1.pType].Name,"void")=0) then
      Stop(@emVOID);
    end
    if (TTabl[Op1.pType].Lock=0) then
      Stop(@emFORWARD);
    end
    if ((Op1.Seg=srNO) & (TTabl[Op1.pType].Size<TTabl[pType].Size)) then // byte const
      Op1.pType=pType;
    end
    S=TTabl[Op1.pType].Size;
  end

  char Buff [128];

  if Op1.Seg=srNO then
    select
      case S=1:
        Code(0,@strcat(@strcpy(@Buff,"mov     BL,"),@Str(Op1.Ofs&255,0)));

      case S=2:
        Code(0,@strcat(@strcpy(@Buff,"mov     BX,"),@Str(Op1.Ofs,0)));

      default:
        Stop(@emINTERNAL);
    end

    return
  end

  if Op1.Seg=srAX then
    select
      case S=1:
        Pop (rgAX);
        Code(0,"mov     BL,AL");
        Regs[rgAX]=0;

      case S=2:
        Pop (rgAX);
        Code(0,"mov     BX,AX");
        Regs[rgAX]=0;

      case S=4:
        Pop (rgDX);
        Pop (rgAX);
        Code(0,"mov     BX,AX");
        Code(0,"mov     CX,DX");
        Regs[rgAX]=0;
        Regs[rgDX]=0;

      default:
        Stop(@emINTERNAL);
    end

    return
  end

  if Op1.Seg=sr87 then
    return
  end

  select
    case S=1:
      strcpy(@Buff,"mov     BL,");

    case S=2:
      strcpy(@Buff,"mov     BX,");

    case S=4:
      strcpy(@Buff,"mov     BX,");

    case Op1.pType=ttREAL:
      strcpy(@Buff,"fld     ");

    default:
      Stop(@emINTERNAL);
  end

  select
    case Op1.Seg=srDS:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          strcat(@Buff,"DS:[DI+");
          Regs  [rgDI]=0;

        case Op1.Index=2:
          Pop   (rgSI);
          strcat(@Buff,"DS:[SI+");
          Regs  [rgSI]=0;

        default:
          strcat(@Buff,"DS:[");
      end

    case Op1.Seg=srBP:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          strcat(@Buff,"SS:[BP][DI+");
          Regs  [rgDI]=0;

        case Op1.Index=2:
          Pop   (rgSI);
          strcat(@Buff,"SS:[BP][SI+");
          Regs  [rgSI]=0;

        default:
          strcat(@Buff,"SS:[BP+");
      end

    case Op1.Seg=srBN:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          strcat(@Buff,"SS:[BP][DI-");
          Regs  [rgDI]=0;

        case Op1.Index=2:
          Pop   (rgSI);
          strcat(@Buff,"SS:[BP][SI-");
          Regs  [rgSI]=0;

        default:
          strcat(@Buff,"SS:[BP-");
      end

    case Op1.Seg=srES:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          Pop   (rgES);
          strcat(@Buff,"ES:[DI+");
          Regs  [rgDI]=0;
          Regs  [rgES]=0;

        case Op1.Index=2:
          Pop   (rgSI);
          Pop   (rgES);
          strcat(@Buff,"ES:[SI+");
          Regs  [rgSI]=0;
          Regs  [rgES]=0;

        default:
          Stop(@emINTERNAL);
      end
  end

  select
    case S=1:
      Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"]"));

    case S=2:
      Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"]"));

    case S=4:
      char     Temp [128];
      strcpy (@Temp,@Buff);

      Temp[8]='C'; // !!!

      word     Ofs=Op1.Ofs;

      Code(0,@strcat(@strcat(@Buff,@Str(Ofs,0)),"]"));

      if Op1.Seg!=srBN then
        Ofs=Ofs+2;
      else
        Ofs=Ofs-2;
      end

      Code(0,@strcat(@strcat(@Temp,@Str(Ofs,0)),"]"));

    case Op1.pType=ttREAL:
      Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"]"));

    default:
      Stop(@emINTERNAL);
  end
end

void LPTR(OpInfo @Op1)
  char Buff [128];

  select
    case Op1.Seg=srAX:
      Pop (rgAX);
      Pop (rgDX);
      Push(rgES);

      if Regs[rgDI]=0 then
        Code(0,"mov     ES,DX");
        Code(0,"mov     DI,AX");

        Op1.Index=1;
      else
        Push(rgSI);

        Code(0,"mov     ES,DX");
        Code(0,"mov     SI,AX");

        Op1.Index=2;
      end

      Regs[rgAX]=0;
      Regs[rgDX]=0;

    case Op1.Seg=srDS:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          Push  (rgES);
          strcpy(@Buff,"les     DI,DS:[DI+");

        case Op1.Index=2:
          Pop   (rgSI);
          Push  (rgES);
          strcpy(@Buff,"les     SI,DS:[SI+");

        case Regs[rgDI]=0:
          Push  (rgES);
          strcpy(@Buff,"les     DI,DS:[");

          Op1.Index=1;

        default:
          Push  (rgES);
          Push  (rgSI);
          strcpy(@Buff,"les     SI,DS:[");

          Op1.Index=2;
      end

    case Op1.Seg=srBP:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          Push  (rgES);
          strcpy(@Buff,"les     DI,SS:[BP][DI+");

        case Op1.Index=2:
          Pop   (rgSI);
          Push  (rgES);
          strcpy(@Buff,"les     SI,SS:[BP][SI+");

        case Regs[rgDI]=0:
          Push  (rgES);
          strcpy(@Buff,"les     DI,SS:[BP+");

          Op1.Index=1;

        default:
          Push  (rgES);
          Push  (rgSI);
          strcpy(@Buff,"les     SI,SS:[BP+");

          Op1.Index=2;
      end

    case Op1.Seg=srBN:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          Push  (rgES);
          strcpy(@Buff,"les     DI,SS:[BP][DI-");

        case Op1.Index=2:
          Pop   (rgSI);
          Push  (rgES);
          strcpy(@Buff,"les     SI,SS:[BP][SI-");

        case Regs[rgDI]=0:
          Push  (rgES);
          strcpy(@Buff,"les     DI,SS:[BP-");

          Op1.Index=1;

        default:
          Push  (rgES);
          Push  (rgSI);
          strcpy(@Buff,"les     SI,SS:[BP-");

          Op1.Index=2;
      end

    case Op1.Seg=srES:
      select
        case Op1.Index=1:
          Pop   (rgDI);
          Pop   (rgES);
          strcpy(@Buff,"les     DI,ES:[DI+");

        case Op1.Index=2:
          Pop   (rgSI);
          Pop   (rgES);
          strcpy(@Buff,"les     SI,ES:[SI+");

        default:
          Stop(@emINTERNAL);
      end

    default:
      Stop(@emINTERNAL);
  end

  if Op1.Seg!=srAX then
    Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"]"));
  end

  select
    case Op1.Index=1:
      Regs[rgDI]=1;
      Regs[rgES]=1;

    case Op1.Index=2:
      Regs[rgSI]=1;
      Regs[rgES]=1;
  end

  Op1.Seg=srES;
  Op1.Ofs=0;
end

void STAX(OpInfo @Op1)
  if (Op1.Value=0)  then
    Stop(@emLVALUE);
  end

  if (Op1.Seg=srNO) then
    Stop(@emLVALUE);
  end

  char Buff [128];
  select
    case Op1.Seg=srDS:
      if (Op1.Index!=0) then
        Pop   (rgDI);
        strcpy(@Buff,"mov     DS:[DI+");
      else
        strcpy(@Buff,"mov     DS:[");
      end

    case Op1.Seg=srBP:
      if (Op1.Index!=0) then
        Pop   (rgDI);
        strcpy(@Buff,"mov     SS:[BP][DI+");
      else
        strcpy(@Buff,"mov     SS:[BP+");
      end

    case Op1.Seg=srBN:
      if (Op1.Index!=0) then
        Pop   (rgDI);
        strcpy(@Buff,"mov     SS:[BP][DI-");
      else
        strcpy(@Buff,"mov     SS:[BP-");
      end

    case Op1.Seg=srES:
      Pop   (rgDI);
      Pop   (rgES);
      strcpy(@Buff,"mov     ES:[DI+");

    default:
      Stop(@emINTERNAL);
  end

  word S=4;
  if (Op1.nPtr=0) then
    if (TTabl[Op1.pType].Lock=0) then
      Stop(@emFORWARD);
    end
    S=TTabl[Op1.pType].Size;
  end

  select
    case S=1:
      Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"],AL"));

    case S=2:
      Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"],AX"));

    case S=4:
      char    Temp [128];
      strcpy(@Temp,@Buff);

      word    Ofs=Op1.Ofs;

      Code(0,@strcat(@strcat(@Buff,@Str(Ofs,0)),"],AX"));

      if Op1.Seg!=srBN then
        Ofs=Ofs+2;
      else
        Ofs=Ofs-2;
      end

      Code(0,@strcat(@strcat(@Temp,@Str(Ofs,0)),"],DX"));

    case Op1.pType=ttREAL:
      Buff[0]='f';
      Buff[1]='s';
      Buff[2]='t';
      Buff[3]='p';

      Code(0,@strcat(@strcat(@Buff,@Str(Op1.Ofs,0)),"]"));

    default:
      Stop(@emINTERNAL);
  end
end

void MOVS(OpInfo @Op1, @Op2)
  if (Op1.Value=0)  then
    Stop(@emLVALUE);
  end

  if (Op1.Seg=srNO) then
    Stop(@emLVALUE);
  end

  if (Op2.Value=0)  then
    Stop(@emLVALUE);
  end

  if (Op2.Seg=srNO) then
    Stop(@emLVALUE);
  end

  Op2.Value=0;
  LDAX(@Op2);

  Code(0,"mov     SI,AX");
  Code(0,"mov     CX,DX");

  Regs[rgAX]=0;
  Regs[rgDX]=0;
  Regs[rgSI]=1;

  Op1.Value=0;
  LDAX(@Op1);
  Pop (rgSI);

  Code(0,"mov     DI,AX");
  Code(0,"mov     ES,DX");

  Code(0,"push    DS");
  Code(0,"mov     DS,CX");
  Code(0,@strcat(@strcpy(@Buff,"mov     CX,"),@Str(TTabl[Op1.pType].Size,0)));
  Code(0,"cld");
  Code(0,"rep     movsb");
  Code(0,"pop     DS");
end

char jump[8];
long comp;
word flag;

word Comp(word Size; char @Jump)
  char Buff [128];

  strcpy(@jump,@Jump);
  comp=Back();
  flag=Size;

  Code(0,    "mov     CL,1");  // xor     CL,CL

  select
    case Size=1:
      Code(0,    "cmp     AL,BL");
    case Size=2:
      Code(0,    "cmp     AX,BX");
    case Size=8:
      Code(0,    "sahf   ;fstsw");
    default:
      Stop(@emINTERNAL);
  end

  Code(0,    @strcat(@strcat(@strcpy(@Buff,@Jump),"     @"),@Str(Label,5)));
  Code(0,    "xor     CL,CL"); // mov     CL,1
  Code(Label,"mov     AL,CL");
  inc  Label;

  return ttBOOL;
end

word Test(word pType1; word nPtr1; OpInfo @Op2)
  if (nPtr1=0) then
    if (Op2.nPtr!=0) then
      Stop(@emPOINTER);
    end

    if (pType1=ttBYTE) then // if (strcmp(@TTabl[pType1].Name,"byte")=0) then
      if (Op2.pType=ttWORD) then // if (strcmp(@TTabl[Op2.pType].Name,"word")=0) then
        Op2.pType=ttBYTE;
        return 0;
      end

      if (Op2.pType=ttINT) then // if (strcmp(@TTabl[Op2.pType].Name,"int")=0) then
        Op2.pType=ttBYTE;
        return 0;
      end
    end

    if (pType1=ttWORD) then // if (strcmp(@TTabl[pType1].Name,"word")=0) then
      if (Op2.pType=ttBYTE) then // if (strcmp(@TTabl[Op2.pType].Name,"byte")=0) then
        if (Op2.Seg!=srNO) then // byte const
          LDAX(@Op2);
          Code(0,"xor     AH,AH");
          return 1;
        end

        Op2.pType=ttWORD;
        return 0;
      end

      if (Op2.pType=ttINT) then // if (strcmp(@TTabl[Op2.pType].Name,"int")=0) then
        Op2.pType=ttWORD;
        return 0;
      end
    end

    if (pType1=ttINT) then // if (strcmp(@TTabl[pType1].Name,"int")=0) then
      if (Op2.pType=ttBYTE) then // if (strcmp(@TTabl[Op2.pType].Name,"byte")=0) then
        if (Op2.Seg!=srNO) then // byte const
          LDAX(@Op2);
          Code(0,"xor     AH,AH");
          return 1;
        end

        Op2.pType=ttINT;
        return 0;
      end

      if (Op2.pType=ttWORD) then // if (strcmp(@TTabl[Op2.pType].Name,"word")=0) then
        Op2.pType=ttINT;
        return 0;
      end
    end

    if (pType1=ttREAL) then // (strcmp(@TTabl[pType1].Name,"real")=0) then
      if (Op2.pType=ttBYTE) then // (strcmp(@TTabl[Op2.pType].Name,"byte")=0) then
        LDAX(@Op2);
        Code(0,"sub     SP,2");
        Code(0,"mov     BX,SP");
        Code(0,"xor     AH,AH");
        Code(0,"mov     SS:[BX],AX");
        Code(0,"fild    SS:[BX]");
        Code(0,"add     SP,2");
        Regs[rgAX]=0;
        Op2.pType=ttREAL;
        return 1;
      end

      if (Op2.pType=ttWORD) then // (strcmp(@TTabl[Op2.pType].Name,"word")=0) then
        LDAX(@Op2);
        Code(0,"sub     SP,4");
        Code(0,"mov     BX,SP");
        Code(0,"mov     SS:[BX],AX");
        Code(0,"xor     AX,AX");
        Code(0,"mov     SS:[BX+2],AX");
        Code(0,"fild    dword ptr SS:[BX]");
        Code(0,"add     SP,4");
        Regs[rgAX]=0;
        Op2.pType=ttREAL;
        return 1;
      end

      if (Op2.pType=ttINT) then // (strcmp(@TTabl[Op2.pType].Name,"int")=0) then
        LDAX(@Op2);
        Code(0,"sub     SP,2");
        Code(0,"mov     BX,SP");
        Code(0,"mov     SS:[BX],AX");
        Code(0,"fild    SS:[BX]");
        Code(0,"add     SP,2");
        Regs[rgAX]=0;
        Op2.pType=ttREAL;
        return 1;
      end
    end

    if (pType1!=Op2.pType) then
      Stop(@emTYPE);
    end

    word P=pType1;
    word I=TTabl[P].pField;
    while TRUE do
      if I>=TTabl[P].nField then
        if TTabl[P].pBase=0 then
          exit
        end

        P=TTabl[P].pBase;
        I=TTabl[P].pField;
      end

      if FTabl[I].fMethod=obVIRT then
        Stop(@emTYPE);
      end

      inc I;
    end
  else
    if (Op2.nPtr=0) then
      Stop(@emNOPTR);
    end

    if (pType1=0) then
      if ((nPtr1=1) | (nPtr1=Op2.nPtr)) then
        return 0;
      end
    end

    if (Op2.pType=0) then
      if ((Op2.nPtr=1) | (Op2.nPtr=nPtr1)) then
        return 0;
      end
    end

    if (pType1!=Op2.pType) then
      word P=TTabl[Op2.pType].pBase;
      while TRUE do
        if P=0 then
          Stop(@emTYPE);
        end

        if pType1=P then
          exit
        end

        P=TTabl[P].pBase;
      end
    end

    if (nPtr1!=Op2.nPtr) then
      Stop(@emEQUAL);
    end
  end

  return 0;
end

void Expr(word P; char @Buff; OpInfo @Op1)
  word Flag=0;
  word Base=0;
  word Self=0;

  if ((Flag=0) & (strcmp(@Buff,"(")=0)) then
    if (P>4) then
      Stop(@emNOBRACKET);
    end
    Expr(0,@Scan(@Buff),@Op1);
    if (strcmp(@Buff,")")!=0) then
      Stop(@emCBRACKET);
    end
    Scan(@Buff);
    Flag=1;
  end

  if ((Flag=0) & (strcmp(@Buff,"!")=0)) then
    if (P>1) then
      Stop(@emOPERATOR);
    end

    Expr(4,@Scan(@Buff),@Op1);

    if (Op1.nPtr>0) then
      Stop(@emPOINTER);
    end

    if ((Flag=0) & (Op1.pType=ttBOOL)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"")=0)) then
      LDAX(@Op1);
      Code(0,"mov     AH,1");
      Code(0,"xor     AL,AH");
      Flag=1;
    end

    if ((Flag=0) & (Op1.pType=ttBYTE)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"byte")=0)) then
      LDAX(@Op1);
      Code(0,"not     AL");
      Flag=1;
    end

    if ((Flag=0) & (Op1.pType=ttWORD)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"word")=0)) then
      LDAX(@Op1);
      Code(0,"not     AX");
      Flag=1;
    end

    if (Flag=0) then
      Stop(@emTYPE);
    end

    Op1.Seg =srAX;
    Op1.Ofs =0;
    Op1.High=TTabl[Op1.pType].Size;

    flag=0;
  end

  if ((Flag=0) & (strcmp(@Buff,"-")=0)) then
    if (P>0) then
      Stop(@emOPERATOR);
    end

    Expr(4,@Scan(@Buff),@Op1);

    if (Op1.nPtr>0) then
      Stop(@emPOINTER);
    end

    if ((Flag=0) & (Op1.pType=ttBYTE)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"byte")=0)) then
      LDAX(@Op1);
      Code(0,"xor     AH,AH");
      Flag=1;
    end

    if ((Flag=0) & (Op1.pType=ttWORD)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"word")=0)) then
      LDAX(@Op1);
      Flag=1;
    end

    if ((Flag=0) & (Op1.pType=ttINT)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"int")=0)) then
      LDAX(@Op1);
      Flag=1;
    end

    if (Flag=1) then
      Code(0,"neg     AX");

      Op1.pType=ttINT;
      Op1.Seg  =srAX;
      Op1.Ofs  =0;
      Op1.High =TTabl[Op1.pType].Size;
    end

    if ((Flag=0) & (Op1.pType=ttREAL)) then
      LDAX(@Op1);

      Code(0,"fldz");
      Code(0,"fsubrp");

      Op1.Seg  =sr87;
      Flag     =1;
    end

    if (Flag=0) then
      Stop(@emTYPE);
    end
  end

  if ((Flag=0) & (strcmp(@Buff,"NULL")=0)) then
    Op1.pType=ttVOID;
    Op1.Seg  =srNO;
    Op1.Ofs  =0;
    Op1.nPtr =1;
    Op1.Index=0;
    Op1.Value=0;

    Scan(@Buff);

    Flag     =1;
  end

  if ((Flag=0) & (strchr(@Buff,#39)=0)) then
    Op1.pType=ttCHAR;
    Op1.Seg  =srNO;
    Op1.Ofs  =CharToByte(Read());
    Op1.nPtr =0;
    Op1.Index=0;
    Op1.Value=1;

    Next();
    if (Read()!=#39) then
      Stop(@emCHAR);
    end
    Next();

    Scan(@Buff);

    Flag     =1;
  end

  if ((Flag=0) & (strcmp(@Buff,"#")=0)) then
    long D=StoD(@Scan(@Buff));
    if ((D.High>0) | (D.Low>255)) then
      Stop(@emOVERFLOW);
    end
    Op1.pType=ttCHAR;
    Op1.Seg  =srNO;
    Op1.Ofs  =D.Low;
    Op1.nPtr =0;
    Op1.Index=0;
    Op1.Value=1;

    Scan(@Buff);

    Flag     =1;
  end

  if ((Flag=0) & (strchr(@Buff,#34)=0)) then
    word P=nByte;
    while TRUE do
      if (Read()=#13) then
        Stop(@emSTRING);
      end
      if (Read()=#10) then
        Stop(@emSTRING);
      end
      if (nByte>=cbSIZE) then
        Stop(@emNOMEMORY);
      end
      if (Read()=#34) then
        Next();
        exit
      end
      CBuff[nByte]=Read();
      Next ();
      inc nByte;
    end

    CBuff[nByte]=#0;
    inc   nByte;

    Op1.pType=ttCHAR;
    Op1.Seg  =srCS;
    Op1.Ofs  =P;
    Op1.nPtr =1;
    Op1.Index=0;
    Op1.Value=0;

    Scan(@Buff);

    Flag     =1;
  end

  if ((Flag=0) & ((isdigit(Buff[0])=0) | (Buff[0]='$'))) then
    word P=StoN(@Buff);
    if P<nReal then
      Op1.pType=ttREAL;
      Op1.Seg  =srCS;
      Op1.Ofs  =P;
      Op1.nPtr =0;
      Op1.Index=0;
      Op1.Value=1;
    else
      long D=StoD(@Buff);
      if (D.High>0) then
        Stop(@emOVERFLOW);
      end

      Op1.pType=ttBYTE;
      Op1.Seg  =srNO;
      Op1.Ofs  =D.Low;
      Op1.nPtr =0;
      Op1.Index=0;
      Op1.Value=1;

      if (D.Low>255) then
        Op1.pType=ttWORD;
      end
    end

    Scan(@Buff);

    Flag     =1;
  end

  if (Flag=0) then
    word pIndex;
    word nIndex;
    word nPtr;
    word N;
    word Call;

    N=0;
    while (strcmp(@Buff,"@")=0) do
      Scan(@Buff);
      inc N;
    end

    Call=0;

    if (Flag=0) then
      word I=FindVar(@Buff);
      if (I<nVar) then
        Op1.pType=VTabl[I].pType;
        Op1.Seg  =srBN;
        Op1.Ofs  =VTabl[I].Ofs;
        Op1.nPtr =N;
        Op1.Index=0;
        pIndex   =VTabl[I].pIndex;
        nIndex   =VTabl[I].nIndex;
        nPtr     =VTabl[I].nPtr;
        Flag     =1;

        Scan(@Buff); // 20.12.2003
      end
    end

    if ((Flag=0) & (pSub<nSub)) then
      word I=STabl[pSub].pParm;
      while (I<STabl[pSub].nParm) do
        if (strcmp(@Buff,@PTabl[I].Name)=0) then
          if strcmp(@Buff,"self")=0 then // 20.12.2003
            if strcmp(@Scan(@Buff),"[")=0 then
              Stop(@emNOINDEX);
            end
          else
            Scan(@Buff);
          end

          Op1.pType=PTabl[I].pType;
          Op1.Seg  =srBP;
          Op1.Ofs  =PTabl[I].Ofs;
          Op1.nPtr =N;
          Op1.Index=0;
          pIndex   =0;
          nIndex   =0;
          nPtr     =PTabl[I].nPtr;
          Flag     =1;
          exit
        end
        inc I;
      end
    /*if (Flag!=0) then
        if strcmp(@Buff,"self")=0 then
          if strcmp(@Scan(@Buff),"[")=0 then
            Stop(@emNOINDEX);
          end

          Keep();
        end

        Op1.pType=PTabl[I].pType;
        Op1.Seg  =srBP;
        Op1.Ofs  =PTabl[I].Ofs;
        Op1.nPtr =N;
        Op1.Index=0;
        pIndex   =0;
        nIndex   =0;
        nPtr     =PTabl[I].nPtr;
      end*/
    end

    if ((Flag=0) & (pStr<nType)) then
      word P=pStr;
      word I=TTabl[P].pField;
      while TRUE do
        if (I>=TTabl[P].nField) then
          if (TTabl[P].pBase=0) then
            exit
          end

          P=TTabl[P].pBase;
          I=TTabl[P].pField;
        end

        if (strcmp(@Buff,@FTabl[I].Name)=0) then
          Op1.pType=pStr;
          Op1.Seg  =srBP;
          Op1.Ofs  =PTabl[STabl[pSub].pParm].Ofs;
          Op1.nPtr =N;
          Op1.Index=0;
          pIndex   =0;
          nIndex   =0;
          nPtr     =1;

          Self     =1;
          Flag     =1;

        //Keep(); 20.12.2003
          exit
        end

        inc I;
      end
    end

    if Flag=0 then
      if strcmp(@Buff,"base")=0 then
        if pStr>=nType then
          Stop(@emMETHOD);
        end

        if TTabl[pStr].pBase=0 then
          Stop(@emNOBASE);
        end

        if strcmp(@Scan(@Buff),"[")=0 then
          Stop(@emNOINDEX);
        end

      //Keep(); 20.12.2003

        Op1.pType=TTabl[pStr].pBase;
        Op1.Seg  =srBP;
        Op1.Ofs  =PTabl[STabl[pSub].pParm].Ofs;
        Op1.nPtr =N;
        Op1.Index=0;
        pIndex   =0;
        nIndex   =0;
        nPtr     =1;

        Base     =1;
        Flag     =1;
      end
    end

    if (Flag=0) then
      word I=FindData(@Buff);
      if (I<nData) then
        Op1.pType=DTabl[I].pType;
        Op1.Seg  =srDS;
        Op1.Ofs  =DTabl[I].Ofs;
        Op1.nPtr =N;
        Op1.Index=0;
        pIndex   =DTabl[I].pIndex;
        nIndex   =DTabl[I].nIndex;
        nPtr     =DTabl[I].nPtr;
        Flag     =1;

        Scan(@Buff); // 20.12.2003
      end
    end

    if (Flag=0) then
      word I=FindConst(@Buff);
      if (I<nConst) then
        if (N!=CTabl[I].nPtr) then
          Stop(@emPOINTER);
        end

        if (N=0) then
          Op1.pType=CTabl[I].pType;
          Op1.Seg  =srNO;
          Op1.Ofs  =CTabl[I].Low;
          Op1.nPtr =CTabl[I].nPtr;
          Op1.Index=0;
        else
          Op1.pType=CTabl[I].pType;
          Op1.Seg  =srCS;
          Op1.Ofs  =CTabl[I].Low;
          Op1.nPtr =1;
          Op1.Index=0;
        end

        nPtr  =0;
        pIndex=0;
        nIndex=0;

        Flag  =1;

        Scan(@Buff); // 20.12.2003
      end
    end

    if (Flag=0) then
      word I=FindSub(@Buff);
      if (I<nSub) then
        Push(rgES);
        Push(rgDI);
        Push(rgSI);
        Push(rgDX);
        Push(rgAX);

        word S=4;
        if (STabl[I].nPtr=0) then
          if (TTabl[STabl[I].pType].Lock=0) then
            Stop(@emFORWARD);
          end
          S=TTabl[STabl[I].pType].Size;
        end
        if (S%2>0) then
          inc S;
        end

        if (strcmp(@Scan(@Buff),"(")!=0) then
          Stop(@emCBRACKET);
        end

        Scan(@Buff);

        word K=STabl[I].pParm;
        while (K<STabl[I].nParm) do
          if (K>STabl[I].pParm) then
            if (strcmp(@Buff,",")!=0) then
              Stop(@emCOMMA);
            end
            Scan(@Buff);
          end

          Expr(0,@Buff,@Op1);

          call=1;

          if (Test(PTabl[K].pType,PTabl[K].nPtr,@Op1)=0) then
            LDAX(@Op1);
          end

          call=0;

          word S1=4;
          if (PTabl[K].nPtr=0) then
            S1=TTabl[PTabl[K].pType].Size;
          end
          if (S1%2>0) then
            inc S1;
          end

          if push=0 then
            select
              case S1=1:
                Code(0,"push    AX");
                Regs[rgAX]=0;

              case S1=2:
                Code(0,"push    AX");
                Regs[rgAX]=0;

              case S1=4:
                Code(0,"push    DX");
                Code(0,"push    AX");
                Regs[rgDX]=0;
                Regs[rgAX]=0;

              case PTabl[K].pType=ttREAL:
                Code(0,"sub     SP,8");
                Code(0,"mov     BX,SP");
                Code(0,"fstp    SS:[BX]");

              default:
                Stop(@emNOTAVAIL);
            end
          end

          inc K;
        end

        if (strcmp(@Buff,")")!=0) then
          Stop(@emCBRACKET);
        end

        if (STabl[I].Ofs=0) then
          if (nRef>=rtSIZE) then
            Stop(@emNOMEMORY);
          end

          RTabl[nRef].Pos=Back();
          RTabl[nRef].Ref=I;
          inc   nRef;

          Code(0,"call    @00000");
        else
          Code(0,@strcat(@strcpy(@Buff,"call    @"),@Str(STabl[I].Ofs,5)));
        end

        select
          case S=1:
            Regs[rgAX]=1;
          case S=2:
            Regs[rgAX]=1;
          case S=4:
            Regs[rgAX]=1;
            Regs[rgDX]=1;
        end

        Op1.pType=STabl[I].pType;

        if ((STabl[I].pType!=ttREAL) | (STabl[I].nPtr!=0)) then
          Op1.Seg=srAX;
        else
          Op1.Seg=sr87;
        end

        Op1.Ofs  =0;
        Op1.High =S;
        Op1.nPtr =N;
        Op1.Index=0;
        pIndex   =0;
        nIndex   =0;
        nPtr     =STabl[I].nPtr;

        if (N=0) then
          Call   =1;
        end

        Flag     =1;

        Scan(@Buff); // 20.12.2003
      end
    end

    if (Flag=0) then
      Stop(@emEXPECTED);
    end

    while TRUE do
      word P=pIndex;
      while (pIndex<nIndex) do
      //if (strcmp(@Scan(@Buff),"[")!=0) then
        if (strcmp(@Buff,"[")!=0) then // 20.12.2003
          if pIndex!=P then // P<pIndex
            Stop(@emSBRACKET);
          end
          exit
        end

        if pIndex!=P then // new
          Push(rgDX);
          Code(0,@strcat(@strcpy(@Buff,"mov     DX,"),@Str(ITabl[pIndex],0)));
          Code(0,"mul     DX");
          Code(0,"mov     DX,AX");
          Regs[rgDX]=1;
          Regs[rgAX]=0;
        end

        OpInfo Op2;
        Expr(0,@Scan(@Buff),@Op2);

        if (strcmp(@Buff,"]")!=0) then
          Stop(@emSBRACKET);
        end

        if ((Op2.Seg=srNO) & (Op2.pType=ttBYTE)) then // if ((Op2.Seg=srNO) & (strcmp(@TTabl[Op2.pType].Name,"byte")=0)) then
          Op2.pType=ttWORD;
        end

        LDAX(@Op2); // LDBX(@Op2,ttWORD);

        Flag=0;
        if (Op2.pType=ttBYTE) then // if (strcmp(@TTabl[Op2.pType].Name,"byte")=0) then
          Code(0,"xor     AH,AH"); // xor     BH,BH
          Flag=1;
        end

        if (Op2.pType=ttWORD) then // if (strcmp(@TTabl[Op2.pType].Name,"word")=0) then
          Flag=1;
        end

        if (Op2.pType=ttINT)  then // if (strcmp(@TTabl[Op2.pType].Name,"int")=0)  then
          Flag=1;
        end

        if (Flag=0) then
          Stop(@emTYPE);
        end

        if (Op2.nPtr>0) then
          Stop(@emPOINTER);
        end

     /* if (P<pIndex) then
          Pop (rgSI);
          Push(rgDX);
          Push(rgAX);
          Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(ITabl[pIndex],0)));
          Code(0,"mul     SI");
          Code(0,"add     AX,BX");
          Code(0,"mov     SI,AX");
        else
          Push(rgSI);
          Code(0,"mov     SI,BX");
          Regs[rgSI]=1;
        end */

        if pIndex!=P then // new
          Pop (rgDX);
          Code(0,"add     AX,DX");
          Regs[rgDX]=0;
        end

        inc pIndex;

        Scan(@Buff); // 20.12.2003
      end

      if (P<nIndex) then
        if (pIndex<nIndex) then
          if (N<nPtr+1) then
            Stop(@emADDR);
          end
          exit
        end

        word S=4;
        if (nPtr=0) then
          S=TTabl[Op1.pType].Size;
        end

        select
          case S=1:
          case S=2:
            Code(0,"shl     AX,1"); // shl     SI,1
          case S=4:
            Code(0,"shl     AX,1"); // shl     SI,1
            Code(0,"shl     AX,1"); // shl     SI,1
          default:
            Push(rgDX);
         // Push(rgAX);
            char Temp[128]; // 20.12.2003
          //Code(0,@strcat(@strcpy(@Buff,"mov     DX,"),@Str(S,0))); // mov     AX
            Code(0,@strcat(@strcpy(@Temp,"mov     DX,"),@Str(S,0))); // mov     AX
            Code(0,"mul     DX");                                    // mul     SI
         // Code(0,"mov     SI,AX");
        end

        select
          case Op1.Index=1:
            Pop (rgDI);
            Code(0,"add     DI,AX");

          case Op1.Index=2:
            Pop (rgSI);
            Code(0,"add     SI,AX");

          case Regs[rgDI]=0:
            Code(0,"mov     DI,AX");
            Regs[rgDI]=1;

            Op1.Index=1;

          default:
            Push(rgSI);
            Code(0,"mov     SI,AX");
            Regs[rgSI]=1;

            Op1.Index=2;
        end

        Regs[rgAX]=0; // Regs[rgSI]=0;
      end

    //while (strcmp(@Scan(@Buff),"[")=0) do
      while (strcmp(@Buff,"[")=0) do // 20.12.2003
        if (nPtr<1) then
          exit
        end

        OpInfo Op2;
        Expr(0,@Scan(@Buff),@Op2);

        if (strcmp(@Buff,"]")!=0) then
          Stop(@emSBRACKET);
        end

        word S=4;
        if (nPtr<=1) then
          S=TTabl[Op1.pType].Size;
        end

        LDBX(@Op2,ttWORD);

        Flag=0;
        if (Op2.pType=ttBYTE) then // if (strcmp(@TTabl[Op2.pType].Name,"byte")=0) then
          Code(0,"xor     BH,BH");
          Flag=1;
        end

        if (Op2.pType=ttWORD) then // if (strcmp(@TTabl[Op2.pType].Name,"word")=0) then
          Flag=1;
        end

        if (Op2.pType=ttINT)  then // if (strcmp(@TTabl[Op2.pType].Name,"int")=0)  then
          Flag=1;
        end

        if (Op2.nPtr>0) then
          Stop(@emPOINTER);
        end
        if (Flag=0) then
          Stop(@emTYPE);
        end

        select
          case S=1:
          case S=2:
            Code(0,"shl     BX,1");
          case S=4:
            Code(0,"shl     BX,1");
            Code(0,"shl     BX,1");
          default:
            Push(rgDX);
            Push(rgAX);
            Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(S,0)));
            Code(0,"mul     BX");
            Code(0,"mov     BX,AX");
        end

        LPTR(@Op1);

        select
          case Op1.Index=1:
            Code(0,"add     DI,BX");

          case Op1.Index=2:
            Code(0,"add     SI,BX");
        end

        Call=0;

        dec nPtr;

        Scan(@Buff); // 20.12.2003
      end

      if Self=0 then
        if (strcmp(@Buff,".")!=0) then
          exit
        end

        Scan(@Buff); // 20.12.2003
    /*else
        Keep();*/
      end

      Self=0;

      word   nptr=nPtr;
      while (nPtr>0) do
        LPTR(@Op1);
        dec  nPtr;
      end

    //Scan(@Buff); 20.12.2003

      word pType=Op1.pType;

      P=TTabl[Op1.pType].pField;
      while TRUE do
        if (P>=TTabl[Op1.pType].nField) then
          if TTabl[Op1.pType].pBase=0 then
            Stop(@emFIELD);
          end

          Op1.pType=TTabl[Op1.pType].pBase;
          P        =TTabl[Op1.pType].pField;
        end

        if (strcmp(@Buff,@FTabl[P].Name)=0) then
          exit
        end

        inc P;
      end

      if FTabl[P].fMethod!=obDATA then
        if (nptr=0) then
          Op1.Value=0;
          LDAX(@Op1);
          Push(rgES);
          Push(rgSI);
          Push(rgDI);
          Push(rgDX);
          Push(rgAX);
        else
          select
            case Op1.Index=1:
              Push(rgSI);
              Push(rgDX);
              Push(rgAX);
              Push(rgES);
              Push(rgDI);
            case Op1.Index=2:
              Push(rgDI);
              Push(rgDX);
              Push(rgAX);
              Push(rgES);
              Push(rgSI);
            default:
              Stop(@emINTERNAL);
          end
        end

        dec  SP;
        dec  SP;

        word I=FTabl[P].pMethod;

        if (strcmp(@Scan(@Buff),"(")!=0) then
          Stop(@emCBRACKET);
        end

        Scan(@Buff);

        word K=STabl[I].pParm+1;
        while (K<STabl[I].nParm) do
          if (K>STabl[I].pParm+1) then
            if (strcmp(@Buff,",")!=0) then
              Stop(@emCOMMA);
            end
            Scan(@Buff);
          end

          Expr(0,@Buff,@Op1);

          call=1;

          if (Test(PTabl[K].pType,PTabl[K].nPtr,@Op1)=0) then
            LDAX(@Op1);
          end

          call=0;

          word S1=4;
          if (PTabl[K].nPtr=0) then
            S1=TTabl[PTabl[K].pType].Size;
          end
          if (S1%2>0) then
            inc S1;
          end

          if push=0 then
            select
              case S1=1:
                Code(0,"push    AX");
                Regs[rgAX]=0;

              case S1=2:
                Code(0,"push    AX");
                Regs[rgAX]=0;

              case S1=4:
                Code(0,"push    DX");
                Code(0,"push    AX");
                Regs[rgDX]=0;
                Regs[rgAX]=0;

              case PTabl[K].pType=ttREAL:
                Code(0,"sub     SP,8");
                Code(0,"mov     BX,SP");
                Code(0,"fstp    SS:[BX]");

              default:
                Stop(@emNOTAVAIL);
            end
          end

          inc K;
        end

        if (strcmp(@Buff,")")!=0) then
          Stop(@emCBRACKET);
        end

        if ((FTabl[P].fMethod=obSTAT) | (Base!=0) | (nptr=0)) then
          if (STabl[I].Ofs=0) then
            if (nRef>=rtSIZE) then
              Stop(@emNOMEMORY);
            end

            RTabl[nRef].Pos=Back();
            RTabl[nRef].Ref=I;
            inc   nRef;

            Code(0,"call    @00000");
          else
            Code(0,@strcat(@strcpy(@Buff,"call    @"),@Str(STabl[I].Ofs,5)));
          end
        else
          word T=pType;
          word J=TTabl[T].pField;
          word L;
          while TRUE do
            if J>=TTabl[T].nField then
              if TTabl[T].pBase=0 then
                exit
              end

              T=TTabl[T].pBase;
              J=TTabl[T].pField;
            end

            if strcmp(@FTabl[J].Name,"")=0 then
              L=J;
            end

            inc J;
          end

          Code  (0,"mov     DI,SP");
          Code  (0,@strcat(@strcat(@strcpy(@Buff,"les     DI,SS:[DI+"),@Str(PTabl[STabl[I].pParm].Ofs-4,0)),"]"));
          Code  (0,@strcat(@strcat(@strcpy(@Buff,"mov     DI,ES:[DI+"),@Str(FTabl[L].Ofs,0)),"]"));
          Code  (0,@strcat(@strcat(@strcpy(@Buff,"mov     DI,CS:[DI+"),@Str(2*(FTabl[P].Ofs-1),0)),"]"));
        //Code  (0,"call    DI");
          Code  (0,"db      FFH");
          Code  (0,"db      D7H");
        end

        word S=4;
        if (STabl[I].nPtr=0) then
          if (TTabl[STabl[I].pType].Lock=0) then
            Stop(@emFORWARD);
          end
          S=TTabl[STabl[I].pType].Size;
        end
        if (S%2>0) then
          inc S;
        end

        select
          case S=1:
            Regs[rgAX]=1;
          case S=2:
            Regs[rgAX]=1;
          case S=4:
            Regs[rgAX]=1;
            Regs[rgDX]=1;
        end

        Op1.pType=STabl[I].pType;

        if ((STabl[I].pType!=ttREAL) | (STabl[I].nPtr!=0)) then
          Op1.Seg=srAX;
        else
          Op1.Seg=sr87;
        end

        Op1.Ofs  =0;
        Op1.High =S;
        Op1.nPtr =N;
        Op1.Index=0;
        pIndex   =0;
        nIndex   =0;
        nPtr     =STabl[I].nPtr;

        if (N=0) then
          Call   =1;
        end
      else
        if (Op1.Seg!=srBN) then
          Op1.Ofs=Op1.Ofs+FTabl[P].Ofs;
        else
          Op1.Ofs=Op1.Ofs-FTabl[P].Ofs;
        end

        Op1.pType=FTabl[P].pType;
        pIndex   =FTabl[P].pIndex;
        nIndex   =FTabl[P].nIndex;
        nPtr     =FTabl[P].nPtr;
      end

      Scan(@Buff); // 20.12.2003
    end

    if ((P>5) & (strcmp(@Buff,";")=0)) then
      if (Call=0) then
        Stop(@emASSIGN);
      end
      return
    end

    if (N>nPtr) then
      dec N;
      if (N>nPtr) then
        Stop(@emADDR);
      end
      Op1.Value=0;
    else
      Op1.Value=1;
    end

    while (nPtr>N) do
      LPTR(@Op1);
      dec nPtr;
    end
  end

  while TRUE do
    word Sign=0;
    word P2  =0;

    if (strcmp(@Buff,"|")=0) then
      Sign= 1;
      P2  = 1;
    end

    if (strcmp(@Buff,"^")=0) then
      Sign= 2;
      P2  = 1;
    end

    if (strcmp(@Buff,"&")=0) then
      Sign= 3;
      P2  = 1;
    end

    if (strcmp(@Buff,"<")=0) then
      Sign= 4;
      P2  = 2;
    end

    if (strcmp(@Buff,"<=")=0) then
      Sign= 5;
      P2  = 2;
    end

    if (strcmp(@Buff,"=")=0) then
      Sign= 6;
      P2  = 2;
    end

    if (strcmp(@Buff,"!=")=0) then
      Sign= 7;
      P2  = 2;
    end

    if (strcmp(@Buff,">=")=0) then
      Sign= 8;
      P2  = 2;
    end

    if (strcmp(@Buff,">")=0) then
      Sign= 9;
      P2  = 2;
    end

    if (strcmp(@Buff,"+")=0) then
      Sign=10;
      P2  = 3;
    end

    if (strcmp(@Buff,"-")=0) then
      Sign=11;
      P2  = 3;
    end

    if (strcmp(@Buff,"*")=0) then
      Sign=12;
      P2  = 4;
    end

    if (strcmp(@Buff,"/")=0) then
      Sign=13;
      P2  = 4;
    end

    if (strcmp(@Buff,"%")=0) then
      Sign=14;
      P2  = 4;
    end

    if (P>=P2) then
      return
    end

    if Op1.nPtr=0 & Op1.Seg=srES & TTabl[Op1.pType].Size<=2 then
      LDAX(@Op1);

      Op1.Seg  =srAX;
      Op1.Ofs  =0;
      Op1.High =TTabl[Op1.pType].Size;
    end

    OpInfo Op2;

    Expr(P2,@Scan(@Buff),@Op2);

    if ((Op1.nPtr=0) & (Op2.nPtr=0)) then
      Flag=0;
      select
        case Op1.pType=ttBYTE: // case strcmp(@TTabl[Op1.pType].Name,"byte")=0:
          select
            case Op2.pType=ttWORD: // case strcmp(@TTabl[Op2.pType].Name,"word")=0:
              LDBX(@Op2,Op2.pType);
              LDAX(@Op1);
              Code(0,"xor     AH,AH");
              Op1.pType=ttWORD;
              Flag=1;

            case Op2.pType=ttINT: // case strcmp(@TTabl[Op2.pType].Name,"int")=0:
              LDBX(@Op2,Op2.pType);
              LDAX(@Op1);
              Code(0,"xor     AH,AH");
              Op1.pType=ttINT;
              Flag=1;

            case Op2.pType=ttREAL: // strcmp(@TTabl[Op2.pType].Name,"real")=0:
              LDAX(@Op1);
              Code(0,"sub     SP,2");
              Code(0,"mov     BX,SP");
              Code(0,"xor     AH,AH");
              Code(0,"mov     SS:[BX],AX");
              Code(0,"fild    SS:[BX]");
              Code(0,"add     SP,2");

              if Op2.Seg=sr87 then
                select
                  case Sign= 4:
                    Sign= 9;
                  case Sign= 5:
                    Sign= 8;
                  case Sign= 8:
                    Sign= 5;
                  case Sign= 9:
                    Sign= 4;
                  case Sign=11:
                    Sign=15;
                  case Sign=13:
                    Sign=16;
                end
              else
                LDAX(@Op2);
              end

              Op1.pType=FindType("real");

              Regs[rgAX]=0;
              Flag=1;
          end

        case Op1.pType=ttWORD: // case strcmp(@TTabl[Op1.pType].Name,"word")=0:
          select
            case Op2.pType=ttBYTE: // case strcmp(@TTabl[Op2.pType].Name,"byte")=0:
              LDBX(@Op2,Op1.pType);
              if Op2.Seg!=srNO then
                Code(0,"xor     BH,BH");
              end
              LDAX(@Op1);
              Flag=1;

            case Op2.pType=ttINT: // case strcmp(@TTabl[Op2.pType].Name,"int")=0:
              Op1.pType=ttINT;

            case Op2.pType=ttREAL: // strcmp(@TTabl[Op2.pType].Name,"real")=0:
              LDAX(@Op1);
              Code(0,"sub     SP,4");
              Code(0,"mov     BX,SP");
              Code(0,"mov     SS:[BX],AX");
              Code(0,"xor     AX,AX");
              Code(0,"mov     SS:[BX+2],AX");
              Code(0,"fild    dword ptr SS:[BX]");
              Code(0,"add     SP,4");

              if Op2.Seg=sr87 then
                select
                  case Sign= 4:
                    Sign= 9;
                  case Sign= 5:
                    Sign= 8;
                  case Sign= 8:
                    Sign= 5;
                  case Sign= 9:
                    Sign= 4;
                  case Sign=11:
                    Sign=15;
                  case Sign=13:
                    Sign=16;
                end
              else
                LDAX(@Op2);
              end

              Op1.pType=FindType("real");

              Regs[rgAX]=0;
              Flag=1;
          end

        case Op1.pType=ttINT: // case strcmp(@TTabl[Op1.pType].Name,"int")=0:
          select
            case Op2.pType=ttBYTE: // case strcmp(@TTabl[Op2.pType].Name,"byte")=0:
              LDBX(@Op2,Op1.pType);
              if Op2.Seg!=srNO then
                Code(0,"xor     BH,BH");
              end
              LDAX(@Op1);
              Flag=1;

            case Op2.pType=ttWORD: // case strcmp(@TTabl[Op2.pType].Name,"word")=0:
              Op2.pType=ttINT;

            case Op2.pType=ttREAL: // strcmp(@TTabl[Op2.pType].Name,"real")=0:
              LDAX(@Op1);
              Code(0,"sub     SP,2");
              Code(0,"mov     BX,SP");
              Code(0,"mov     SS:[BX],AX");
              Code(0,"fild    SS:[BX]");
              Code(0,"add     SP,2");

              if Op2.Seg=sr87 then
                select
                  case Sign= 4:
                    Sign= 9;
                  case Sign= 5:
                    Sign= 8;
                  case Sign= 8:
                    Sign= 5;
                  case Sign= 9:
                    Sign= 4;
                  case Sign=11:
                    Sign=15;
                  case Sign=13:
                    Sign=16;
                end
              else
                LDAX(@Op2);
              end

              Op1.pType=FindType("real");

              Regs[rgAX]=0;
              Flag=1;
          end

        case Op1.pType=ttREAL:
          select
            case Op2.pType=ttBYTE: // case strcmp(@TTabl[Op2.pType].Name,"byte")=0:
              LDAX(@Op1);
              LDAX(@Op2);
              Code(0,"sub     SP,2");
              Code(0,"mov     BX,SP");
              Code(0,"xor     AH,AH");
              Code(0,"mov     SS:[BX],AX");
              Code(0,"fild    SS:[BX]");
              Code(0,"add     SP,2");
              Regs[rgAX]=0;
              Flag=1;

            case Op2.pType=ttWORD: // case strcmp(@TTabl[Op2.pType].Name,"word")=0:
              LDAX(@Op1);
              LDAX(@Op2);
              Code(0,"sub     SP,4");
              Code(0,"mov     BX,SP");
              Code(0,"mov     SS:[BX],AX");
              Code(0,"xor     AX,AX");
              Code(0,"mov     SS:[BX+2],AX");
              Code(0,"fild    dword ptr SS:[BX]");
              Code(0,"add     SP,4");
              Regs[rgAX]=0;
              Flag=1;

            case Op2.pType=ttINT: // case strcmp(@TTabl[Op2.pType].Name,"int")=0:
              LDAX(@Op1);
              LDAX(@Op2);
              Code(0,"sub     SP,2");
              Code(0,"mov     BX,SP");
              Code(0,"mov     SS:[BX],AX");
              Code(0,"fild    SS:[BX]");
              Code(0,"add     SP,2");
              Regs[rgAX]=0;
              Flag=1;

            case Op2.pType=ttREAL:
              if Op2.Seg=sr87 & Op1.Seg!=sr87 then
                LDAX(@Op1);
                select
                  case Sign= 4:
                    Sign= 9;
                  case Sign= 5:
                    Sign= 8;
                  case Sign= 8:
                    Sign= 5;
                  case Sign= 9:
                    Sign= 4;
                  case Sign=11:
                    Sign=15;
                  case Sign=13:
                    Sign=16;
                end
              else
                LDAX(@Op1);
                LDAX(@Op2);
              end

              Flag=1;
          end
      end

      if (Flag=0) then
        if (Op1.pType!=Op2.pType) then
          Stop(@emTYPE);
        end

        LDBX(@Op2,Op2.pType);
        LDAX(@Op1);
      end

      flag=0;
      select
        case Op1.pType=ttBOOL:
          select
            case Sign=1:
              Code(0,    "or      AL,BL");

            case Sign=2:
              Code(0,    "xor     AL,BL");

            case Sign=3:
              Code(0,    "and     AL,BL");

            default:
              Stop(@emUNDEFOPR);
          end

        case Op1.pType=ttCHAR:
          select
            case Sign=4:
              Op1.pType=Comp(1,"jb "); // jae

            case Sign=5:
              Op1.pType=Comp(1,"jbe"); // ja

            case Sign=6:
              Op1.pType=Comp(1,"je "); // jne

            case Sign=7:
              Op1.pType=Comp(1,"jne"); // je

            case Sign=8:
              Op1.pType=Comp(1,"jae"); // jb

            case Sign=9:
              Op1.pType=Comp(1,"ja "); // jbe

            default:
              Stop(@emUNDEFOPR);
          end

        case Op1.pType=ttBYTE:
          select
            case Sign=1:
              Code(0,    "or      AL,BL");

            case Sign=2:
              Code(0,    "xor     AL,BL");

            case Sign=3:
              Code(0,    "and     AL,BL");

            case Sign=4:
              Op1.pType=Comp(1,"jb "); // jae

            case Sign=5:
              Op1.pType=Comp(1,"jbe"); // ja

            case Sign=6:
              Op1.pType=Comp(1,"je "); // jne

            case Sign=7:
              Op1.pType=Comp(1,"jne"); // je

            case Sign=8:
              Op1.pType=Comp(1,"jae"); // jb

            case Sign=9:
              Op1.pType=Comp(1,"ja "); // jbe

            case Sign=10:
              Code(0,    "add     AL,BL");

            case Sign=11:
              Code(0,    "sub     AL,BL");

            case Sign=12:
              Push(rgDX);
              Code(0,    "mul     BL");

            case Sign=13:
              Code(0,    "xor     AH,AH");
              Code(0,    "div     BL");

            case Sign=14:
              Code(0,    "xor     AH,AH");
              Code(0,    "div     BL");
              Code(0,    "mov     AL,AH");

            default:
              Stop(@emUNDEFOPR);
          end

        case Op1.pType=ttWORD:
          select
            case Sign=1:
              Code(0,    "or      AX,BX");

            case Sign=2:
              Code(0,    "xor     AX,BX");

            case Sign=3:
              Code(0,    "and     AX,BX");

            case Sign=4:
              Op1.pType=Comp(2,"jb "); // jae

            case Sign=5:
              Op1.pType=Comp(2,"jbe"); // ja

            case Sign=6:
              Op1.pType=Comp(2,"je "); // jne

            case Sign=7:
              Op1.pType=Comp(2,"jne"); // je

            case Sign=8:
              Op1.pType=Comp(2,"jae"); // jb

            case Sign=9:
              Op1.pType=Comp(2,"ja "); // jbe

            case Sign=10:
              Code(0,    "add     AX,BX");

            case Sign=11:
              Code(0,    "sub     AX,BX");

            case Sign=12:
              Push(rgDX);
              Code(0,    "mul     BX");

            case Sign=13:
              Push(rgDX);
              Code(0,    "xor     DX,DX");
              Code(0,    "div     BX");

            case Sign=14:
              Push(rgDX);
              Code(0,    "xor     DX,DX");
              Code(0,    "div     BX");
              Code(0,    "mov     AX,DX");

            default:
              Stop(@emUNDEFOPR);
          end

        case Op1.pType=ttINT:
          select
            case Sign=4:
              Op1.pType=Comp(2,"jl "); // jge

            case Sign=5:
              Op1.pType=Comp(2,"jle"); // jg

            case Sign=6:
              Op1.pType=Comp(2,"je "); // jne

            case Sign=7:
              Op1.pType=Comp(2,"jne"); // je

            case Sign=8:
              Op1.pType=Comp(2,"jge"); // jl

            case Sign=9:
              Op1.pType=Comp(2,"jg "); // jle

            case Sign=10:
              Code(0,    "add     AX,BX");

            case Sign=11:
              Code(0,    "sub     AX,BX");

            case Sign=12:
              Push(rgDX);
              Code(0,    "imul    BX");

            case Sign=13:
              Push(rgDX);
              Code(0,    "cwd");
              Code(0,    "idiv    BX");

            default:
              Stop(@emUNDEFOPR);
          end

        case Op1.pType=ttREAL:
          if (4<=Sign) & (Sign<=9) then
            Code(0,    "fcompp");
            Code(0,    "sub     SP,2");
            Code(0,    "mov     BX,SP");
            Code(0,    "fstsw   SS:[BX]");
            Code(0,    "fwait");
            Code(0,    "mov     AX,SS:[BX]");
            Code(0,    "add     SP,2");

            Regs[rgAX]=1;
          end

          select
            case Sign=4:
              Op1.pType=Comp(8,"jae");

            case Sign=5:
              Op1.pType=Comp(8,"ja ");

            case Sign=6:
              Op1.pType=Comp(8,"je");

            case Sign=7:
              Op1.pType=Comp(8,"jne ");

            case Sign=8:
              Op1.pType=Comp(8,"jb ");

            case Sign=9:
              Op1.pType=Comp(8,"jbe");

            case Sign=10:
              Code(0,    "faddp");

            case Sign=11:
              Code(0,    "fsubp");

            case Sign=12:
              Code(0,    "fmulp");

            case Sign=13:
              Code(0,    "fdivp");

            case Sign=15:
              Code(0,    "fsubrp");

            case Sign=16:
              Code(0,    "fdivrp");

            default:
              Stop(@emUNDEFOPR);
          end

        default:
          Stop(@emUNDEFOPR);
      end

      if Op1.pType!=ttREAL then
        Op1.Seg=srAX;
      else
        Op1.Seg=sr87;
      end

      Op1.Ofs  =0;
      Op1.High =TTabl[Op1.pType].Size;
    else
      if (Op1.nPtr=0) then
        Stop(@emNOPTR);
      end
      if (Op2.nPtr!=1) then
        Stop(@emNULL);
      end
      if (Op2.pType!=ttVOID) then
        Stop(@emNULL);
      end
      if (Op2.Value!=0) then
        Stop(@emNULL);
      end

      char Buff [128];

      LDAX(@Op1);

      select
        case Sign=6:
        //Code(0,    "xor     CL,CL");
        //Code(0,    "xor     DX,AX");
        //Code(0,    @strcat(@strcpy(@Buff,"jnz     @"),@Str(Label,5)));
        //Code(0,    "mov     CL,1");
        //Code(Label,"mov     AL,CL"); inc Label;
          strcpy(@jump,"jz ");

        case Sign=7:
        //Code(0,    "xor     CL,CL");
        //Code(0,    "xor     DX,AX");
        //Code(0,    @strcat(@strcpy(@Buff,"jz      @"),@Str(Label,5)));
        //Code(0,    "mov     CL,1");
        //Code(Label,"mov     AL,CL"); inc Label;
          strcpy(@jump,"jnz");

        default:
          Stop(@emUNDEFOPR);
      end

      comp=Back();
      flag=4;

      Code(0,    "mov     CL,1");
      Code(0,    "or      DX,AX");
      Code(0,    @strcat(@strcat(@strcpy(@Buff,@jump),"     @"),@Str(Label,5)));
      Code(0,    "xor     CL,CL");
      Code(Label,"mov     AL,CL");
      inc  Label;

      Regs[rgDX]=0;

      Op1.pType =ttBOOL;
      Op1.Seg   =srAX;
      Op1.Ofs   =0;
      Op1.High  =1;
      Op1.nPtr  =0;
    end
  end
end

void Tabl(char @Buff; word @S)
  while (strcmp(@Buff,"[")=0) do
    word I=FindConst(@Scan(@Buff));
    long D;
    if  (I<nConst) then
      word Flag=0;
      if (CTabl[I].pType=ttBYTE) then // if (strcmp(@TTabl[CTabl[I].pType].Name,"byte")=0) then
        Flag=1;
      end
      if (CTabl[I].pType=ttWORD) then // if (strcmp(@TTabl[CTabl[I].pType].Name,"word")=0) then
        Flag=1;
      end
      if (Flag=0) then
        Stop(@emTYPE);
      end
      D.Low =CTabl[I].Low;
      D.High=0;
    else
      D=StoD(@Buff);
      if (D.High>0) then
        Stop(@emOVERFLOW);
      end
    end

    if (D.Low<1) then // D.Low<2
      Stop(@emARRAY);
    end

    S=Mul(S,D.Low);
    if (S>65520) then
      Stop(@emSTRUCTURE);
    end

    if (strcmp(@Scan(@Buff),"]")!=0) then
      Stop(@emSBRACKET);
    end

    if (nIndex>=itSIZE) then
      Stop(@emNOMEMORY);
    end

    ITabl[nIndex]=D.Low;
    inc   nIndex;

    Scan(@Buff);
  end
end

word Retn;

void Ctrl(char @Buff)
  Retn=0;

  if (strcmp(@Buff,"if")=0) then
    OpInfo Op1;

    Init();
    Expr(0,@Scan(@Buff),@Op1);

    if (strcmp(@Buff,"then")!=0) then
      Stop(@emTHENEXP);
    end

    if (Op1.nPtr>0) then
      Stop(@emPOINTER);
    end

    if (Op1.pType!=ttBOOL) then
      Stop(@emBOOLEAN);
    end

 // LDAX(@Op1);

 // Code(0,    "or      AL,AL");
 // Code(0,    @strcat(@strcpy(@Buff,"jnz     @"),@Str(Label,5)));

    if flag!=0 then
      Seek(comp);

      Code(0,    "nop    ;CL,1");  // mov     CL,1

      select
        case flag=1:
          Code(0,    "cmp     AL,BL");
        case flag=2:
          Code(0,    "cmp     AX,BX");
        case flag=4:
          Code(0,    "or      DX,AX");
        case flag=8:
          Code(0,    "sahf   ;fstsw");
      end

      dec  Label;

      Code(0,    @strcat(@strcat(@strcpy(@Buff,@jump),"     @"),@Str(Label,5)));
      Code(0,    "nop    ;CL,CL"); // xor     CL,CL
      Code(0,    "nop    ;AL,CL"); // mov     AL,CL
    else
      Code(0,    @strcat(@strcpy(@Buff,"jnz     @"),@Str(Label,5)));
    end

    long P1=Back();
    long P2=P1;

    Jump(0);
    Code(Label,"nop"); inc Label;

    word VSize1 =VSize;
    word nVar1  =nVar;
    word nIndex1=nIndex;

    while TRUE do
      Scan(@Buff);

      if (strcmp(@Buff,"else")=0) then
        P2=Back();
        Jump(0);
        Code(0,    "even");
        Code(Label,"nop");
        Seek(P1);
        Jump(Label);
        inc  Label;
        Back();

        nIndex=nIndex1;
        nVar  =nVar1;
        VSize =VSize1;

        while (strcmp(@Scan(@Buff),"end")!=0) do
          Ctrl(@Buff);
        end

        exit
      end

      if (strcmp(@Buff,"end")=0) then
        exit
      end

      Ctrl(@Buff);
    end

    nIndex=nIndex1;
    nVar  =nVar1;
    VSize =VSize1;

    if P2.Low!=P1.Low | P2.High!=P1.High then
      Code(0,  "even");
    end

    Code(Label,"nop");
    Seek(P2);
    Jump(Label);
    inc  Label;
    Back();

    return
  end

  if (strcmp(@Buff,"select")=0) then
    long JTabl [jtSIZE];
    word nJump =0;

    word VSize1 =VSize;
    word nVar1  =nVar;
    word nIndex1=nIndex;

    word Flag   =0;
    long P;

    Scan(@Buff);
    while (strcmp(@Buff,"end")!=0) do
      if (Flag!=0) then
        if (nJump>=jtSIZE) then
          Stop(@emNOMEMORY);
        end

        JTabl[nJump]=Back();
        inc   nJump;

        Jump(0);

        Code(0,    "even");
        Code(Label,"nop");
        Seek(P);
        Jump(Label);
        inc  Label;

        Back();
      end

      nIndex=nIndex1;
      nVar  = nVar1;
      VSize =VSize1;

      if (strcmp(@Buff,"default")=0) then
        if (strcmp(@Scan(@Buff),":")!=0) then
          Stop(@emCOLON);
        end

        while (strcmp(@Scan(@Buff),"end")!=0) do
          Ctrl(@Buff);
        end

        Flag=0;

        loop
      end

      if (strcmp(@Buff,"case")=0) then
        OpInfo Op1;

        Init();
        Expr(0,@Scan(@Buff),@Op1);

        if (strcmp(@Buff,":")!=0) then
          Stop(@emCOLON);
        end

        if (Op1.nPtr>0) then
          Stop(@emPOINTER);
        end

        if (Op1.pType!=ttBOOL) then
          Stop(@emBOOLEAN);
        end

     // LDAX(@Op1);

     // Code(0,"or      AL,AL");
     // Code(0,@strcat(@strcpy(@Buff,"jnz     @"),@Str(Label,5)));

        if flag!=0 then
          Seek(comp);

          Code(0,    "nop    ;CL,1");  // mov     CL,1

          select
            case flag=1:
              Code(0,    "cmp     AL,BL");
            case flag=2:
              Code(0,    "cmp     AX,BX");
            case flag=4:
              Code(0,    "or      DX,AX");
            case flag=8:
              Code(0,    "sahf   ;fstsw");
          end

          dec  Label;

          Code(0,    @strcat(@strcat(@strcpy(@Buff,@jump),"     @"),@Str(Label,5)));
          Code(0,    "nop    ;CL,CL"); // xor     CL,CL
          Code(0,    "nop    ;AL,CL"); // mov     AL,CL
        else
          Code(0,    @strcat(@strcpy(@Buff,"jnz     @"),@Str(Label,5)));
        end

        P=Back();
        Jump(0);
        Code(Label,"nop"); inc Label;

        while TRUE do
          Scan(@Buff);
          if (strcmp(@Buff,"case")=0) then
            exit
          end
          if (strcmp(@Buff,"default")=0) then
            exit
          end
          if (strcmp(@Buff,"end")=0) then
            exit
          end
          Ctrl(@Buff);
        end

        Flag=1;

        loop
      end

      Stop(@emCASEEXP);
    end

    Code(0,    "even");
    Code(Label,"nop");

    while (nJump>0) do
      dec nJump;
      Seek(JTabl[nJump]);
      Jump(Label);
    end

    if (Flag!=0) then
      Seek(P);
      Jump(Label);
    end

    inc Label;

    Back();

    nIndex=nIndex1;
    nVar  = nVar1;
    VSize =VSize1;

    return
  end

  if (strcmp(@Buff,"repeat")=0) then
    word VSize1 =VSize;
    word nVar1  =nVar;
    word nIndex1=nIndex;
    word Loop1  =Loop;
    word nJump1 =nJump;

    Loop=Label;

    Code(0,    "even");
    Code(Label,"nop");
    inc  Label;

    while (strcmp(@Scan(@Buff),"until")!=0) do
      Ctrl(@Buff);
    end

    OpInfo Op1;

    Init();
    Expr(0,@Scan(@Buff),@Op1);

    if (strcmp(@Buff,";")!=0) then
      Stop(@emSEMICOLON);
    end

    if (Op1.nPtr>0) then
      Stop(@emPOINTER);
    end

    if (Op1.pType!=ttBOOL) then
      Stop(@emBOOLEAN);
    end

 // LDAX(@Op1);

 // Code(0,"or      AL,AL");
 // Code(0,@strcat(@strcpy(@Buff,"jnz     @"),@Str(Label,5)));

    if flag!=0 then
      Seek(comp);

      Code(0,    "nop    ;CL,1");  // mov     CL,1

      select
        case flag=1:
          Code(0,    "cmp     AL,BL");
        case flag=2:
          Code(0,    "cmp     AX,BX");
        case flag=4:
          Code(0,    "or      DX,AX");
        case flag=8:
          Code(0,    "sahf   ;fstsw");
      end

      dec  Label;

      Code(0,    @strcat(@strcat(@strcpy(@Buff,@jump),"     @"),@Str(Label,5)));
      Code(0,    "nop    ;CL,CL"); // xor     CL,CL
      Code(0,    "nop    ;AL,CL"); // mov     AL,CL
      Back();
    else
      Code(0,    @strcat(@strcpy(@Buff,"jnz     @"),@Str(Label,5)));
    end

    Jump(Loop);
    Code(Label,"nop");

    while (nJump>nJump1) do
      dec nJump;
      Seek(JTabl[nJump]);
      Jump(Label);
    end
    inc Label;

    Back();

    Loop  =Loop1;
    nIndex=nIndex1;
    nVar  =nVar1;
    VSize =VSize1;

    return
  end

  if (strcmp(@Buff,"while")=0) then
    word VSize1 =VSize;
    word nVar1  =nVar;
    word nIndex1=nIndex;
    word Loop1  =Loop;
    word nJump1 =nJump;

    Loop=Label;

    Code(0,    "even");
    Code(Label,"nop");
    inc  Label;

    if strcmp(@Scan(@Buff),"TRUE")!=0 then
      OpInfo Op1;

      Init();
      Expr(0,@Buff,@Op1);

      if (strcmp(@Buff,"do")!=0) then
        Stop(@emDOEXPECTED);
      end

      if (Op1.nPtr>0) then
        Stop(@emPOINTER);
      end

      if (Op1.pType!=ttBOOL) then
        Stop(@emBOOLEAN);
      end

   // LDAX(@Op1);

   // Code(0,"or      AL,AL");
   // Code(0,@strcat(@strcpy(@Buff,"jnz     @"),@Str(Label,5)));

      if flag!=0 then
        Seek(comp);

        Code(0,    "nop    ;CL,1");  // mov     CL,1

        select
          case flag=1:
            Code(0,    "cmp     AL,BL");
          case flag=2:
            Code(0,    "cmp     AX,BX");
          case flag=4:
            Code(0,    "or      DX,AX");
          case flag=8:
            Code(0,    "sahf   ;fstsw");
        end

        dec  Label;

        Code(0,    @strcat(@strcat(@strcpy(@Buff,@jump),"     @"),@Str(Label,5)));
        Code(0,    "nop    ;CL,CL"); // xor     CL,CL
        Code(0,    "nop    ;AL,CL"); // mov     AL,CL
      else
        Code(0,    @strcat(@strcpy(@Buff,"jnz     @"),@Str(Label,5)));
      end

      if (nJump>=jtSIZE) then
        Stop(@emNOMEMORY);
      end

      JTabl[nJump]=Back();
      inc   nJump;

      Jump(0);

      Code(Label,"nop"); inc Label;
    else
      if (strcmp(@Scan(@Buff),"do")!=0) then
        Stop(@emDOEXPECTED);
      end
    end

    while (strcmp(@Scan(@Buff),"end")!=0) do
      Ctrl(@Buff);
    end

    Jump(Loop);

    Code(0,    "even");
    Code(Label,"nop");

    while (nJump>nJump1) do
      dec nJump;
      Seek(JTabl[nJump]);
      Jump(Label);
    end
    inc Label;

    Back();

    Loop  =Loop1;
    nIndex=nIndex1;
    nVar  =nVar1;
    VSize =VSize1;

    return
  end

  if (strcmp(@Buff,"loop")=0) then
    if (Loop=0) then
      Stop(@emLOOP);
    end

    Jump(Loop);

    return
  end

  if (strcmp(@Buff,"exit")=0) then
    if (Loop=0) then
      Stop(@emLOOP);
    end

    if (nJump>=jtSIZE) then
      Stop(@emNOMEMORY);
    end

    JTabl[nJump]=Back();
    inc   nJump;

    Jump(0);

    return
  end

  if (strcmp(@Buff,"inc")=0) then
    OpInfo Op1;

    Init();
    Expr(5,@Scan(@Buff),@Op1);

    if (Op1.nPtr>0) then
      Stop(@emPOINTER);
    end

    if (strcmp(@Buff,";")!=0) then
      Stop(@emSEMICOLON);
    end

 // LDAX(@Op1);

    word Flag=0;
    if ((Flag=0) & (Op1.pType=ttBYTE)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"byte")=0)) then
 //   Code(0,"inc     AL");
      Flag=1;
    end

    if ((Flag=0) & (Op1.pType=ttWORD)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"word")=0)) then
 //   Code(0,"inc     AX");
      Flag=2; // 1
    end

    if ((Flag=0) & (Op1.pType=ttINT))  then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"int")=0))  then
 //   Code(0,"inc     AX");
      Flag=2; // 1
    end

    if (Flag=0) then
      Stop(@emTYPE);
    end

 // Regs[rgDI]=1;
 // Regs[rgES]=1;

 // STAX(@Op1);

    long P=Back();
    LDBX(@Op1,Op1.pType);
    code[0]='n';
    code[1]='o';
    code[2]='p';
    code[7]=';';

    Seek(P);
    Code(0,@code);
    Back();

    char Temp [64];
    select
      case Flag=1:
        strcpy(@Temp,"inc     byte ptr ");
      default:
        strcpy(@Temp,"inc     word ptr ");
    end

    Code(0,@strcat(@Temp,@code[11]));

    return
  end

  if (strcmp(@Buff,"dec")=0) then
    OpInfo Op1;

    Init();
    Expr(5,@Scan(@Buff),@Op1);

    if (Op1.nPtr>0) then
      Stop(@emPOINTER);
    end

    if (strcmp(@Buff,";")!=0) then
      Stop(@emSEMICOLON);
    end

 // LDAX(@Op1);

    word Flag=0;
    if ((Flag=0) & (Op1.pType=ttBYTE)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"byte")=0)) then
 //   Code(0,"dec     AL");
      Flag=1;
    end

    if ((Flag=0) & (Op1.pType=ttWORD)) then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"word")=0)) then
 //   Code(0,"dec     AX");
      Flag=2; // 1
    end

    if ((Flag=0) & (Op1.pType=ttINT))  then // if ((Flag=0) & (strcmp(@TTabl[Op1.pType].Name,"int")=0))  then
 //   Code(0,"dec     AX");
      Flag=2; // 1
    end

    if (Flag=0) then
      Stop(@emTYPE);
    end

 // Regs[rgDI]=1;
 // Regs[rgES]=1;

 // STAX(@Op1);

    long P=Back();
    LDBX(@Op1,Op1.pType);
    code[0]='n';
    code[1]='o';
    code[2]='p';
    code[7]=';';

    Seek(P);
    Code(0,@code);
    Back();

    char Temp [64];
    select
      case Flag=1:
        strcpy(@Temp,"dec     byte ptr ");
      default:
        strcpy(@Temp,"dec     word ptr ");
    end

    Code(0,@strcat(@Temp,@code[11]));

    return
  end

  if (strcmp(@Buff,"return")=0) then
    if (pSub<nSub) then
      word S=4;
      if (STabl[pSub].nPtr=0) then
        S=TTabl[STabl[pSub].pType].Size;
      end

      if (S>0) then
        OpInfo Op1;

        Init();
        Expr(0,@Scan(@Buff),@Op1);

        if (strcmp(@Buff,";")!=0) then
          Stop(@emSEMICOLON);
        end

        if (Test(STabl[pSub].pType,STabl[pSub].nPtr,@Op1)=0) then
          LDAX(@Op1);
        end
      end

      Code(0,    "mov     SP,BP");
      Code(0,    "pop     BP");
      Code(0,    @strcat(@strcpy(@Buff,"retn    "),@Str(PSize,0)));
    else
      Code(0,    "mov     AX,4C00H");
      Code(0,    "int     21H");
    end

    Retn=1;

    return
  end

  if (strcmp(@Buff,"asm")=0) then
    while ((Read()=#09) | (Read()=#32)) do
      Next();
    end

    word P=0;
    while ((Read()!=#13) & (Read()!=#10)) do
      Buff[P]=Read();
      inc  P;
      Next();
    end
    Buff[P]=#0;

    Code(0,@Buff);

    return
  end

  word P=FindType(@Buff);
  if (P<nType) then
    while TRUE do
      word N=0;
      while (strcmp(@Scan(@Buff),"@")=0) do
        inc N;
      end

      if (isalpha(Buff[0])!=0) then
        Stop(@emEXPECTED);
      end

      if (FindVar(@Buff)<nVar) then
        Stop(@emDOUBLE);
      end

      if (nVar>=vtSIZE) then
        Stop(@emNOMEMORY);
      end

      VTabl[nVar].pType =P;      strcpy(@VTabl[nVar].Name,@Buff);
      VTabl[nVar].pIndex=nIndex;
      VTabl[nVar].nIndex=0;
      VTabl[nVar].nPtr  =N;

      word S=4;
      if (N=0) then
        if (TTabl[P].Lock=0) then
          Stop(@emFORWARD);
        end
        S=TTabl[P].Size;
      end

      Tabl(@Scan(@Buff),@S);

      if (S%2!=0) then
        inc S;
      end

      VSize=Add(VSize,S);
      if (Add(VSize,Add(PSize,Add(RSize,4)))>Smax) then
        Stop(@emSTRUCTURE);
      end

      if (SSize<VSize) then
        SSize=VSize;
      end

      VTabl[nVar].nIndex=nIndex;
      VTabl[nVar].Ofs   =VSize;

      if (strcmp(@Buff,"=")=0) then
        OpInfo Op1,Op2;

        if (nIndex>VTabl[nVar].pIndex) then
          Stop(@emINIT);
        end

        Op1.pType=VTabl[nVar].pType;
        Op1.Seg  =srBN;
        Op1.Ofs  =VTabl[nVar].Ofs;
        Op1.nPtr =VTabl[nVar].nPtr;
        Op1.Index=0;
        Op1.Value=1;

        Init();
        Expr(0,@Scan(@Buff),@Op2);

        word Flag=Test(Op1.pType,Op1.nPtr,@Op2);
        if Op1.nPtr>0 | TTabl[Op1.pType].Size=1 | TTabl[Op1.pType].Size=2 | TTabl[Op1.pType].Size=4 | Op1.pType=ttREAL then
          if Flag=0 then
            LDAX(@Op2);
          end

          STAX(@Op1);
        else
          MOVS(@Op1,@Op2);
        end
      else
        word J=TTabl[P].pField;
        while ((N=0) & (J<TTabl[P].nField)) do
          if (strcmp(@FTabl[J].Name,"")=0) then
          /*if (VTabl[nVar].pIndex<VTabl[nVar].nIndex) then
              Stop(@emNOTAVAIL);
            end

            char Temp[128];

            Code(0,"mov     AX,BP");
            Code(0,@strcat(@strcpy(@Temp,"sub     AX,"),@Str(VTabl[nVar].Ofs,0)));
            Code(0,"push    SS");
            Code(0,"push    AX");
            Code(0,@strcat(@strcpy(@Temp,"call    @"),@Str(STabl[FTabl[J].pMethod].Ofs,5)));*/

            word  K1=VTabl[nVar].pIndex;
            word  L1=1;
            while K1<VTabl[nVar].nIndex do
              L1 =L1*ITabl[K1];
              inc K1;
            end

            char Temp[128];

            Code(0,"mov     DI,BP");
            Code(0,@strcat(@strcpy(@Temp,"sub     DI,"),@Str(VTabl[nVar].Ofs,0)));

            if L1>1 then
              Code(0,    "xor     CX,CX");
              Code(Label,"push    CX");
              Code(0,    "push    DI");
            end

            Code(0,      "push    SS");
            Code(0,      "push    DI");
            Code(0,      @strcat(@strcpy(@Temp,"call    @"),@Str(STabl[FTabl[J].pMethod].Ofs,5)));

            if L1>1 then
              Code(0,    "pop     DI");
              Code(0,    "pop     CX");
              Code(0,    @strcat(@strcpy(@Temp,"add     DI,"),@Str(TTabl[VTabl[nVar].pType].Size,0)));
              Code(0,    "inc     CX");
              Code(0,    @strcat(@strcpy(@Temp,"cmp     CX,"),@Str(L1,0)));
              Code(0,    @strcat(@strcpy(@Temp,"jb      @"),  @Str(Label,5)));
              inc  Label;
            end

            exit
          end

          inc J;
        end
      end

      inc nVar;

      if (strcmp(@Buff,";")=0) then
        exit
      end

      if (strcmp(@Buff,",")!=0) then
        Stop(@emCOMMA);
      end
    end

    return
  end

  OpInfo Op1,Op2;

  Init();
  Expr(6,@Buff,@Op1);

  if (strcmp(@Buff,";")=0) then
    return
  end

  if (strcmp(@Buff,"=")!=0) then
    Stop(@emASSIGN);
  end

  Expr(0,@Scan(@Buff),@Op2);

  if (strcmp(@Buff,";")!=0) then
    Stop(@emSEMICOLON);
  end

  word Flag=Test(Op1.pType,Op1.nPtr,@Op2);
  if Op1.nPtr>0 | TTabl[Op1.pType].Size=1 | TTabl[Op1.pType].Size=2 | TTabl[Op1.pType].Size=4 | Op1.pType=ttREAL then
    if Flag=0 then
      LDAX(@Op2);
    end

    STAX(@Op1);
  else
    MOVS(@Op1,@Op2);
  end
end

void FVMT(word pType; word @nMethod; word @VMT)
  if pType=0 then
    return
  end

  FVMT(TTabl[pType].pBase,@nMethod,@VMT);

  word I=TTabl[pType].pField;
  while I<TTabl[pType].nField do
    if FTabl[I].fMethod=obVIRT then
      if STabl[FTabl[I].pMethod].Ofs=0 then
        char Buff [128];
        Stop(@strcat(@strcat(@strcat(@strcpy(@Buff,@TTabl[pType].Name),"."),@FTabl[I].Name),": функция не опpеделена"));
      end

      VMT[FTabl[I].Ofs]=STabl[FTabl[I].pMethod].Ofs;

      if nMethod<FTabl[I].Ofs then
        nMethod=FTabl[I].Ofs;
      end
    end

    inc I;
  end
end

void Type(char @Name; word Size)
  TTabl[nType].pBase =0; strcpy(@TTabl[nType].Name,@Name);
  TTabl[nType].pField=0;
  TTabl[nType].nField=0;
  TTabl[nType].Size  =Size;
  TTabl[nType].Lock  =1;
  inc   nType;
end

begin
  word @Size=@Ptr(GetPSP(),128);
  char @Parm=@Ptr(GetPSP(),129);
  char  Buff [256];

  word  I=0;
  while I<Size%256 & Parm[I] =' ' do
    inc I;
  end

  word  P=0;
  word  N=0;
  word  K=0;
  while I<Size%256 & Parm[I]!=' ' do
    Buff[K]=Parm[I];
    select
      case Buff[K]='.':
        P=K;

      case Buff[K]='\':
        N=K+1;
        P=0;
    end

    inc  K;
    inc  I;
  end
  Buff[K]=#0;

  if K=0 then
    outs("Тpанслятоp языка Context. Веpсия 1.2");
    outs("(C) Хохлов А.В.  г. Москва 1995-2003");
    outs("Использование:  context  <имя файла>");
    return
  end

  if P=0 then
    P=K;
    strcpy(@Buff[P],".CTX");
  end

  if strlen(@Buff[N])>12 then
    puts(@Buff[N]);
    puts("(0): Слишком длинное имя файла");
    return
  end

  strcpy(@Name,@Buff[N]);

  F1=open(@Buff);
  if F1=$FFFF then
    puts(@Name);
    puts("(0): Невозможно откpыть файл");
    return
  end

  strcpy(@Buff[P],".ASM");

  F2=create(@Buff);

  nType =0;
  nField=0;
  nSub  =0;
  nRef  =0;
  nParm =0;
  DSize =0;
  nData =0;
  nConst=0;
  nByte =0;
  nReal =0;
  nIndex=0;
  nJump =0;

  Loop  =0;

  nChar =0;
  pChar =0;

//Ready =0;

  pDest =0;
  fDest =0;

  call  =0;

  Type("void",0);
  Type("",    1);
  Type("char",1);
  Type("byte",1);
  Type("word",2);
  Type("int", 2);
  Type("real",8);

  Class=49152;
  Label=    2;

  Code(0,"mov     AX,4096");
  Code(0,"mov     DX,CS");
  Code(0,"add     DX,AX");
  Code(0,"mov     DS,DX");
  Code(0,"add     DX,AX");
  Code(0,"mov     SS,DX");

  JTabl[nJump]=Back();
  inc   nJump;

  Jump(0);

  Line =1;

  word   Flag;
  while (strcmp(@Scan(@Buff),"begin")!=0) do
    if (strcmp(@Buff,"define")=0) then
      Scan(@Buff);
      Flag=0;
      if (strcmp(@Buff,"@")=0) then
        Scan(@Buff);
        Flag=1;
      end

      if (isalpha(Buff[0])!=0) then
        Stop(@emEXPECTED);
      end

      if (FindConst(@Buff)<nConst) then
        Stop(@emDOUBLE);
      end

      if (nConst>=ctSIZE) then
        Stop(@emNOMEMORY);
      end

      strcpy(@CTabl[nConst].Name,@Buff);

      Scan(@Buff);
      if (Flag!=0) then
        if (strchr(@Buff,#34)!=0) then
          Stop(@emSTRING);
        end
        CTabl[nConst].pType=ttCHAR;
        CTabl[nConst].nPtr =1;
        CTabl[nConst].Low  =nByte;

        while TRUE do
          if (Read()=#13) then
            Stop(@emSTRING);
          end
          if (Read()=#10) then
            Stop(@emSTRING);
          end
          if (nByte>=cbSIZE) then
            Stop(@emLONG);
          end
          if (Read()=#34) then
            Next();
            exit
          end
          CBuff[nByte]=Read();
          Next ();
          inc nByte;
        end
        CBuff[nByte]=#0;
        inc   nByte;
      else
        if (strchr(@Buff,#39)=0) then
          CTabl[nConst].pType=ttCHAR;
          CTabl[nConst].nPtr =0;
          CTabl[nConst].Low  =CharToByte(Read());
          Next();
          if (Read()!=#39) then
            Stop(@emCHAR);
          end
          Next();
        else
          if (strcmp(@Buff,"#")=0) then
            long D=StoD(@Scan(@Buff));
            if ((D.High>0) | (D.Low>255)) then
              Stop(@emOVERFLOW);
            end
            CTabl[nConst].pType=ttCHAR;
            CTabl[nConst].nPtr =0;
            CTabl[nConst].Low  =D.Low;
          else
            long D=StoD(@Buff);
            if (D.High>0) then
              Stop(@emOVERFLOW);
            end
            CTabl[nConst].pType=ttBYTE;
            CTabl[nConst].nPtr =0;
            CTabl[nConst].Low  =D.Low;
            if (D.Low>255) then
              CTabl[nConst].pType=ttWORD;
            end
          end
        end
      end

      inc nConst;
      loop
    end

    if (strcmp(@Buff,"struct")=0) then
      Scan(@Buff);
      if (isalpha(Buff[0])!=0) then
        Stop(@emEXPECTED);
      end

      P=FindType(@Buff);
      if (P>=nType) then
        if (nType>=ttSIZE) then
          Stop(@emNOMEMORY);
        end

        TTabl[nType].Lock=0; strcpy(@TTabl[nType].Name,@Buff);
        P  =  nType;
        inc   nType;
      end

      if (TTabl[P].Lock!=0) then
        Stop(@emDOUBLE);
      end

      if (strcmp(@Scan(@Buff),";")=0) then
        loop
      end

      word N1 =nField;
      word P0 =0;
      word S1 =0;
      word S2 =0;
      word Ofs=0;
      word VMT=0;
      word VM0=0;
      word VM1=0;

      if strcmp(@Buff,"(")=0 then
        P0=FindType(@Scan(@Buff));
        if P0>=P then
          Stop(@emNOTYPE);
        end

        if TTabl[P0].Lock=0 then
          Stop(@emFORWARD);
        end

        if TTabl[P0].nField=0 then
          Stop(@emCLASSEXP);
        end

        if strcmp(@Scan(@Buff),")")!=0 then
          Stop(@emCBRACKET);
        end

        word P1=P0;
        word I1=TTabl[P1].pField;
        while TRUE do
          if I1>=TTabl[P1].nField then
            if TTabl[P1].pBase=0 then
              exit
            end

            P1=TTabl[P1].pBase;
            I1=TTabl[P1].pField;
          end

          if FTabl[I1].fMethod=obVIRT then
            if Ofs<FTabl[I1].Ofs then
              Ofs=FTabl[I1].Ofs;
            end

            VMT=1;
          end

          if strcmp(@FTabl[I1].Name,"")=0 then
            VM0=1;
          end

          inc I1;
        end

        S1=TTabl[P0].Size;
        S2=TTabl[P0].Size;

        Scan(@Buff); // 20.12.2003
    /*else
        Keep();*/
      end

      TTabl[P].pBase =P0;
      TTabl[P].pField=nField;

    //while (strcmp(@Scan(@Buff),"end")!=0) do
      while (strcmp(@Buff,"end")!=0) do // 20.12.2003
        if (strcmp(@Buff,"section")=0) then
          if (P0!=0) then
            Stop(@emNOSECTION);
          end

          if (S1=0) then
            Stop(@emEMPTY);
          end

          S1=0;

          Scan(@Buff); // 20.12.2003
          loop
        end

        K=FindType(@Buff);
        if (K>=nType) then
          Stop(@emEXPECTED);
        end

        Flag=0;
        while TRUE do
          N=0;
          while (strcmp(@Scan(@Buff),"@")=0) do
            inc N;
          end

          if (isalpha(Buff[0])!=0) then
            Stop(@emEXPECTED);
          end

          if (N=0) then
            word P1=K;
            word I1=TTabl[P1].pField;
            while TRUE do
              if I1>=TTabl[P1].nField then
                if TTabl[P1].pBase=0 then
                  exit
                end

                P1=TTabl[P1].pBase;
                I1=TTabl[P1].pField;
              end

              if strcmp(@FTabl[I1].Name,"")=0 then
                VM1=1;
                exit
              end

              inc I1;
            end
          end

          I=N1;
          while (I<nField) do
            if (strcmp(@Buff,@FTabl[I].Name)=0) then
              Stop(@emDOUBLE);
            end

            inc I;
          end

          if (nField>=ftSIZE) then
            Stop(@emNOMEMORY);
          end

          FTabl[nField].pType  =K;      strcpy(@FTabl[nField].Name,@Buff);
          FTabl[nField].fMethod=obDATA;
          FTabl[nField].pIndex =nIndex;
          FTabl[nField].nIndex =0;
          FTabl[nField].nPtr   =N;
          FTabl[nField].Ofs    =S1;

          if (strcmp(@Scan(@Buff),"(")=0) then
            if Flag!=0 then
              Stop(@emFUNCTION);
            end

            if (nSub>=stSIZE) then
              Stop(@emNOMEMORY);
            end

            word S3=4;
            if N=0 then
              S3=TTabl[K].Size;
            end

            if ((S3!=0) & (S3!=1) & (S3!=2) & (S3!=4) & (K!=ttREAL)) then
              Stop(@emNOTAVAIL);
            end

            STabl[nSub].pType=K;        strcpy(@STabl[nSub].Name,"");
            STabl[nSub].nPtr =N;
            STabl[nSub].Ofs  =0;
            STabl[nSub].pParm=nParm;

            if (nParm>=ptSIZE) then
              Stop(@emNOMEMORY);
            end

            PTabl[nParm].pType=P;       strcpy(@PTabl[nParm].Name,"self");
            PTabl[nParm].nPtr =1;
            inc   nParm;

            while TRUE do
              word L=FindType(@Scan(@Buff));
              while (L<nType) do
                N=0;
                while (strcmp(@Scan(@Buff),"@")=0) do
                  inc N;
                end

                if (isalpha(Buff[0])!=0) then
                  Stop(@emEXPECTED);
                end

                I=STabl[nSub].pParm;
                while (I<nParm) do
                  if (strcmp(@PTabl[I].Name,@Buff)=0) then
                    Stop(@emDOUBLE);
                  end

                  inc I;
                end

                if (nParm>=ptSIZE) then
                  Stop(@emNOMEMORY);
                end

                PTabl[nParm].pType=L; strcpy(@PTabl[nParm].Name,@Buff);
                PTabl[nParm].nPtr =N;
                inc   nParm;

                Scan(@Buff);

                if (strcmp(@Buff,")")=0) then
                  exit
                end

                if (strcmp(@Buff,";")=0) then
                  exit
                end

                if (strcmp(@Buff,",")=0) then
                  loop
                end

                Stop(@emCOMMA);
              end

              if (strcmp(@Buff,")")=0) then
                exit
              end

              if (strcmp(@Buff,";")=0) then
                loop
              end

              Stop(@emSEMICOLON);
            end

            if (strcmp(@Scan(@Buff),"virtual")=0) then
              FTabl[nField].fMethod=obVIRT;
              Scan (@Buff);
            else
              FTabl[nField].fMethod=obSTAT;
            end

            word P1 =P0;
            word I1 =TTabl[P1].pField;
            while TRUE do
              if I1>=TTabl[P1].nField then
                if TTabl[P1].pBase=0 then
                  if FTabl[nField].fMethod=obVIRT then
                    inc   Ofs;
                    FTabl[nField].Ofs=Ofs;
                  end

                  exit
                end

                P1=TTabl[P1].pBase;
                I1=TTabl[P1].pField;
              end

              if (strcmp(@FTabl[nField].Name,@FTabl[I1].Name)=0) then
                if FTabl[nField].fMethod!=obVIRT & FTabl[I1].fMethod!=obVIRT then
                  exit
                end

                if FTabl[nField].fMethod!=obVIRT | FTabl[I1].fMethod!=obVIRT then
                  Stop(@emNOTMATCH);
                end

                if FTabl[nField].pType!=FTabl[I1].pType then
                  Stop(@emNOTMATCH);
                end

                if FTabl[nField].nPtr!=FTabl[I1].nPtr then
                  Stop(@emNOTMATCH);
                end

                word J1=STabl[nSub].pParm+1;
                word J2=STabl[FTabl[I1].pMethod].pParm+1;
                while TRUE do
                  if J1>=nParm then
                    if J2<STabl[FTabl[I1].pMethod].nParm then
                      Stop(@emNOTMATCH);
                    end

                    exit
                  end

                  if J2>=STabl[FTabl[I1].pMethod].nParm then
                    Stop(@emNOTMATCH);
                  end

                  inc J1;
                  inc J2;
                end

                FTabl[nField].Ofs=FTabl[I1].Ofs;

                exit
              end

              inc I1;
            end

            FTabl[nField].pMethod=nSub;
            inc   nField;

            STabl[nSub]  .nParm  =nParm;
            inc   nSub;

            if strcmp(@Buff,";")!=0 then
              Stop(@emSEMICOLON);
            end

            exit
          end

          word S0=4;
          if (N=0) then
            if (TTabl[K].Lock=0) then
              Stop(@emFORWARD);
            end
            S0=TTabl[K].Size;
          end

        //Keep();

          Tabl(@Buff,@S0);

          S1=Add(S1,S0);
          if (S1>65520) then
            Stop(@emSTRUCTURE);
          end

          if (S2<S1) then
            S2=S1;
          end

          FTabl[nField].nIndex=nIndex;
          inc   nField;

          Flag=1;

          if (strcmp(@Buff,";")=0) then
            exit
          end

          if (strcmp(@Buff,",")=0) then
            loop
          end

          Stop(@emCOMMA);
        end

        Scan(@Buff); // 20.12.2003
      end

      if ((Ofs!=0) | (VMT!=0) | (VM0!=0) | (VM1!=0)) then
        if (nSub>=stSIZE) then
          Stop(@emNOMEMORY);
        end

        if (nField>=ftSIZE) then
          Stop(@emNOMEMORY);
        end

        FTabl[nField].pType=ttVOID;
        FTabl[nField].Ofs  =0;

        word pVMT=nField;
        word pINI;

        if (VM0!=0) then
          word P1=TTabl[P] .pBase;
          word I1=TTabl[P1].pField;
          while TRUE do
            if (I1>=TTabl[P1].nField) then
              if TTabl[P1].pBase=0 then
                exit
              end

              P1=TTabl[P1].pBase;
              I1=TTabl[P1].pField;
            end

            if (strcmp(@FTabl[I1].Name,"")=0) then
              if P1=TTabl[P].pBase then
                pINI=I1;
              end

              if (FTabl[I1].pType!=ttVOID) then
                pVMT=I1;
              end
            end

            inc I1;
          end
        end

        if ((VMT=0) & (Ofs!=0)) then
          FTabl[nField].pType=ttWORD;
          FTabl[nField].Ofs  =S1;

          S1=Add(S1,2);
          if (S1>65520) then
            Stop(@emSTRUCTURE);
          end

          if (S2<S1) then
            S2=S1;
          end
        end

        FTabl[nField].fMethod=obSTAT;        strcpy(@FTabl[nField].Name,"");
        FTabl[nField].pMethod=nSub;
        FTabl[nField].pIndex =0;
        FTabl[nField].nIndex =0;
        FTabl[nField].nPtr   =0;

        STabl[nSub].pType=ttVOID;            strcpy(@STabl[nSub].Name,"");
        STabl[nSub].nPtr =0;
        STabl[nSub].Ofs  =Label;
        STabl[nSub].pParm=nParm;
        STabl[nSub].nParm=nParm;

        Code(0,    "");
        Code(Label,"push    BP");
        inc  Label;
        Code(0,    "mov     BP,SP");

        if (VM0!=0) then
          Code(0,  "les     DI,SS:[BP+4]");
          Code(0,  "push    ES");
          Code(0,  "push    DI");
          Code(0,  @strcat(@strcpy(@Buff,"call    @"),@Str(STabl[FTabl[pINI].pMethod].Ofs,5)));
        end

        if ((VMT!=0) | (Ofs!=0)) then
          Code(0,    "les     DI,SS:[BP+4]");
          Code(0,    @strcat(@strcat(@strcpy(@Buff,"mov     AX,offset @"),@Str(Class,5))," + 0"));
          Code(0,    @strcat(@strcat(@strcpy(@Buff,"mov     ES:[DI+"),@Str(FTabl[pVMT].Ofs,0)),"],AX"));
        end

        word I1=TTabl[P].pField;
        while (I1<nField) do
          if ((FTabl[I1].fMethod=obDATA) & (FTabl[I1].nPtr=0)) then
            word J1=TTabl[FTabl[I1].pType].pField;
            while (J1<TTabl[FTabl[I1].pType].nField) do
              if (strcmp(@FTabl[J1].Name,"")=0) then
                word  K1=FTabl[I1].pIndex;
                word  L1=1;
                while K1<FTabl[I1].nIndex do
                  L1 =L1*ITabl[K1];
                  inc K1;
                end

                Code(0,"les     DI,SS:[BP+4]");
                Code(0,@strcat(@strcpy(@Buff,"add     DI,"),@Str(FTabl[I1].Ofs,0)));

                if L1>1 then
                  Code(0,    "xor     CX,CX");
                  Code(Label,"push    CX");
                  Code(0,    "push    ES");
                  Code(0,    "push    DI");
                end

                Code(0,      "push    ES");
                Code(0,      "push    DI");
                Code(0,      @strcat(@strcpy(@Buff,"call    @"),@Str(STabl[FTabl[J1].pMethod].Ofs,5)));

                if L1>1 then
                  Code(0,    "pop     DI");
                  Code(0,    "pop     ES");
                  Code(0,    "pop     CX");
                  Code(0,    @strcat(@strcpy(@Buff,"add     DI,"),@Str(TTabl[FTabl[I1].pType].Size,0)));
                  Code(0,    "inc     CX");
                  Code(0,    @strcat(@strcpy(@Buff,"cmp     CX,"),@Str(L1,0)));
                  Code(0,    @strcat(@strcpy(@Buff,"jb      @"),  @Str(Label,5)));
                  inc  Label;
                end

                exit
              end

              inc J1;
            end
          end

          inc I1;
        end

        Code(0,    "mov     SP,BP");
        Code(0,    "pop     BP");
        Code(0,    "retn    4");

        inc  nSub;
        inc  nField;
      end

      if (S1=0) then
        Stop(@emEMPTY);
      end

      TTabl[P].nField=nField;
      TTabl[P].Size  =S2;
      TTabl[P].Lock  =1;
      TTabl[P].Ofs   =Class;

      inc   Class;

      loop
    end

    P=FindType(@Buff);
    if (P<nType) then
      Flag=0;
      while TRUE do
        char Name[128];

        N=0;
        while (strcmp(@Scan(@Name),"@")=0) do
          inc N;
        end

        if (isalpha(Name[0])!=0) then
          Stop(@emEXPECTED);
        end

        word fMethod=obSTAT;

        if (strcmp(@Scan(@Buff),"(")!=0) then
          if (strcmp(@Buff,".")!=0) then
            if (FindData(@Name)<nData) then
              Stop(@emDOUBLE);
            end

            if (nData>=dtSIZE) then
              Stop(@emNOMEMORY);
            end

            DTabl[nData].pType =P;      strcpy(@DTabl[nData].Name,@Name);
            DTabl[nData].pIndex=nIndex;
            DTabl[nData].nIndex=0;
            DTabl[nData].nPtr  =N;
            DTabl[nData].Ofs   =DSize;

            word S0=4;
            if (N=0) then
              if (TTabl[P].Lock=0) then
                Stop(@emFORWARD);
              end
              S0=TTabl[P].Size;
            end

          //Keep();

            Tabl(@Buff,@S0);

            if (S0%2!=0) then
              inc S0;
            end

            DSize=Add(DSize,S0);
            if (DSize>65520) then
              Stop(@emSTRUCTURE);
            end

            DTabl[nData].nIndex=nIndex;
            inc   nData;

            if (strcmp(@Buff,";")=0) then
              exit
            end

            Flag=1;

            if (strcmp(@Buff,",")=0) then
              loop
            end

            Stop(@emCOMMA);
          else
            pStr=FindType(@Name);
            if pStr>=nType then
              Stop(@emNOTYPE);
            end

            Scan(@Buff);

            I=TTabl[pStr].pField;
            while TRUE do
              if (I>=TTabl[pStr].nField) then
                Stop(@emEXPECTED);
              end

              if (strcmp(@Buff,@FTabl[I].Name)=0) then
                exit
              end

              inc I;
            end

            fMethod=FTabl[I].fMethod;

            if fMethod=obDATA then
              Stop(@emNOTMATCH);
            end

            if (strcmp(@Scan(@Buff),"(")!=0) then
              Stop(@emCBRACKET);
            end

            pSub=FTabl[I].pMethod;
          end
        else
          pStr=nType;
          pSub=FindSub(@Name);
        end

        if Flag!=0 then
          Stop(@emFUNCTION);
        end

        if pSub>=nSub then
          if (nSub>=stSIZE) then
            Stop(@emNOMEMORY);
          end

          word S3=4;
          if N=0 then
            S3=TTabl[P].Size;
          end

          if ((S3!=0) & (S3!=1) & (S3!=2) & (S3!=4) & (K!=ttREAL)) then
            Stop(@emNOTAVAIL);
          end

          STabl[pSub].pType=P;          strcpy(@STabl[pSub].Name,@Name);
          STabl[pSub].pParm=nParm;
          STabl[pSub].nPtr =N;
          STabl[pSub].Ofs  =0;

          while TRUE do
            K=FindType(@Scan(@Buff));
            while (K<nType) do
              N=0;
              while (strcmp(@Scan(@Buff),"@")=0) do
                inc N;
              end

              if (isalpha(Buff[0])!=0) then
                Stop(@emEXPECTED);
              end

              I=STabl[pSub].pParm;
              while (I<nParm) do
                if (strcmp(@PTabl[I].Name,@Buff)=0) then
                  Stop(@emDOUBLE);
                end

                inc I;
              end

              if (nParm>=ptSIZE) then
                Stop(@emNOMEMORY);
              end

              PTabl[nParm].pType=K; strcpy(@PTabl[nParm].Name,@Buff);
              PTabl[nParm].nPtr =N;
              inc   nParm;

              Scan(@Buff);

              if (strcmp(@Buff,")")=0) then
                exit
              end

              if (strcmp(@Buff,";")=0) then
                exit
              end

              if (strcmp(@Buff,",")=0) then
                loop
              end

              Stop(@emCOMMA);
            end

            if (strcmp(@Buff,")")=0) then
              exit
            end

            if (strcmp(@Buff,";")=0) then
              loop
            end

            Stop(@emSEMICOLON);
          end

          STabl[pSub].nParm=nParm;
          inc   nSub;
        else
          if (STabl[pSub].pType!=P) then
            Stop(@emNOTMATCH);
          end

          if (STabl[pSub].nPtr!=N) then
            Stop(@emNOTMATCH);
          end

          K=STabl[pSub].nParm;
          I=STabl[pSub].pParm;
          if pStr<nType then
            inc I;
          end

          while TRUE do
            word P2=FindType(@Scan(@Buff));
            while ((P2<nType) & (I<K)) do
              N=0;
              while (strcmp(@Scan(@Buff),"@")=0) do
                inc N;
              end

              if (strcmp(@PTabl[I].Name,@Buff)!=0) then
                Stop(@emNOTMATCH);
              end

              if (P2!=PTabl[I].pType) then
                Stop(@emNOTMATCH);
              end

              if (N!=PTabl[I].nPtr) then
                Stop(@emNOTMATCH);
              end

              inc I;

              Scan(@Buff);

              if (strcmp(@Buff,")")=0) then
                exit
              end

              if (strcmp(@Buff,";")=0) then
                exit
              end

              if (strcmp(@Buff,",")=0) then
                loop
              end

              Stop(@emCOMMA);
            end

            if (strcmp(@Buff,")")=0) then
              exit
            end

            if (strcmp(@Buff,";")=0) then
              loop
            end

            Stop(@emSEMICOLON);
          end
        end

        if (strcmp(@Scan(@Buff),";")=0) then
          if (pStr<nType) then
            Stop(@emDEFINE);
          end

          exit
        end

        if fMethod=obVIRT then
          if (strcmp(@Buff,"virtual")!=0) then
            Stop(@emNOTMATCH);
          end

          Scan(@Buff); // 20.12.2003
      /*else
          Keep();*/
        end

        if STabl[pSub].Ofs!=0 then
          Stop(@emDOUBLE);
        end

        RSize=4;
        if (STabl[pSub].nPtr=0) then
          if (TTabl[STabl[pSub].pType].Lock=0) then
            Stop(@emFORWARD);
          end

          RSize=TTabl[STabl[pSub].pType].Size;
        end

        SSize=0;
        VSize=0;
        PSize=0;
        nVar =0;

        K=STabl[pSub].pParm;
        while (K<STabl[pSub].nParm) do
          word S=4;
          if (PTabl[K].nPtr=0) then
            S=TTabl[PTabl[K].pType].Size;
          end
          if (S%2>0) then
            inc S;
          end
          PSize=Add(PSize,S);
          if (Add(PSize,Add(RSize,4))>Smax) then
            Stop(@emSTRUCTURE);
          end
          PTabl[K].Ofs=PSize;
          inc   K;
        end

        K=STabl[pSub].pParm;
        while (K<STabl[pSub].nParm) do
          PTabl[K].Ofs=(PSize-PTabl[K].Ofs)+4;
          inc   K;
        end

        STabl[pSub].Ofs=Label;

        Code(0,    "");
        Code(0,    "even");
        Code(Label,"push    BP");
        Code(0,    "mov     BP,SP");
        inc  Label;

        long S=Back();
     // Code(0,    "mov     AX,00000");
     // Code(0,    "sub     SP,AX");

        Code(0,    "sub     SP,00000");

      /*while (strcmp(@Scan(@Buff),"end")!=0) do
          Ctrl(@Buff);
        end*/

        while (strcmp(@Buff,"end")!=0) do
          Ctrl(@Buff);
          Scan(@Buff);
        end

        Seek(S);
     // Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(SSize,5)));

        if SSize>0 then
          Code(0,@strcat(@strcpy(@Buff,"sub     SP,"),@Str(SSize,5)));
        else
          Code(0,    "nop    ;SP,00000");
        end

        Back();

        if Retn=0 then
          Code(0,    "mov     SP,BP");
          Code(0,    "pop     BP");
          Code(0,    @strcat(@strcpy(@Buff,"retn    "),@Str(PSize,0)));
        end

        exit
      end

      loop
    end

    Stop(@emEXPECTED);
  end

  dec nJump;
  Seek(JTabl[nJump]);

  Jump(Label);
  Code(0,    "");
  Code(Label,"push    BP");
  Code(0,    "mov     BP,SP");
  inc Label;

  long S=Back();
//Code(0,    "mov     AX,00000");
//Code(0,    "sub     SP,AX");

  Code(0,    "sub     SP,00000");

  I=0;
  while (I<nData) do
    word J=TTabl[DTabl[I].pType].pField;
    while ((DTabl[I].nPtr=0) & (J<TTabl[DTabl[I].pType].nField)) do
      if (strcmp(@FTabl[J].Name,"")=0) then
      /*if (DTabl[I].pIndex<DTabl[I].nIndex) then
          Stop(@emNOTAVAIL);
        end

        Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(DTabl[I].Ofs,0)));
        Code(0,"push    DS");
        Code(0,"push    AX");
        Code(0,@strcat(@strcpy(@Buff,"call    @"),@Str(STabl[FTabl[J].pMethod].Ofs,5)));*/

        word  K1=DTabl[I].pIndex;
        word  L1=1;
        while K1<DTabl[I].nIndex do
          L1 =L1*ITabl[K1];
          inc K1;
        end

        Code(0,@strcat(@strcpy(@Buff,"mov     DI,"),@Str(DTabl[I].Ofs,0)));

        if L1>1 then
          Code(0,    "xor     CX,CX");
          Code(Label,"push    CX");
          Code(0,    "push    DI");
        end

        Code(0,      "push    DS");
        Code(0,      "push    DI");
        Code(0,      @strcat(@strcpy(@Buff,"call    @"),@Str(STabl[FTabl[J].pMethod].Ofs,5)));

        if L1>1 then
          Code(0,    "pop     DI");
          Code(0,    "pop     CX");
          Code(0,    @strcat(@strcpy(@Buff,"add     DI,"),@Str(TTabl[DTabl[I].pType].Size,0)));
          Code(0,    "inc     CX");
          Code(0,    @strcat(@strcpy(@Buff,"cmp     CX,"),@Str(L1,0)));
          Code(0,    @strcat(@strcpy(@Buff,"jb      @"),  @Str(Label,5)));
          inc  Label;
        end

        exit
      end

      inc J;
    end

    inc I;
  end

  pSub =nSub;
  RSize=0;
  PSize=0;
  SSize=0;
  VSize=0;
  nVar =0;
  while (strcmp(@Scan(@Buff),"end")!=0)   do
    Ctrl(@Buff);
  end

  Seek(S);
//Code(0,@strcat(@strcpy(@Buff,"mov     AX,"),@Str(SSize,5)));

  if SSize>0 then
    Code(0,@strcat(@strcpy(@Buff,"sub     SP,"),@Str(SSize,5)));
  else
    Code(0,    "nop    ;SP,00000");
  end

  Back();

  if Retn=0 then
    Code(0,    "mov     SP,BP");
    Code(0,    "pop     BP");
    Code(0,    "mov     AX,4C00H");
    Code(0,    "int     21H");
  end

  while (nRef>0) do
    dec nRef;
    if (STabl[RTabl[nRef].Ref].Ofs=0) then
      strcpy(@Buff,@STabl[RTabl[nRef].Ref].Name);

      I=0;
      while Buff[0]=#0 & I<nType do
        K=TTabl[I].pField;
        while K<TTabl[I].nField do
          if FTabl[K].fMethod!=obDATA & FTabl[K].pMethod=RTabl[nRef].Ref then
            strcat(@strcat(@strcpy(@Buff,@TTabl[I].Name),"."),@FTabl[K].Name);
            exit
          end

          inc K;
        end

        inc I;
      end

      Stop(@strcat(@Buff,": функция не опpеделена"));
    end
    Seek(RTabl[nRef].Pos);
    Code(0,@strcat(@strcpy(@Buff,"call    @"),@Str(STabl[RTabl[nRef].Ref].Ofs,5)));
    Back(); // !!!
  end

  P=16384;
  I=0;
  while (I<nByte) do
    K=strlen(@strcpy(@Buff,"db      "));
    Buff[K]=#34;
    inc  K;
    while ((I<nByte) & (CBuff[I]!=#0)) do
      Buff[K]=CBuff[I]; inc I;
      inc  K;
    end
    Buff[K]=#34;
    strcpy(@Buff[K+1],",0");
    if P!=0 then
      Code(0,"");
    end
    Code  (P,@Buff);
    P=0;
    inc I;
  end

  P=32768;
  I=0;
  while (I<nReal) do
    if P!=0 then
      Code(0,"");
    end
    Code(P,@strcat(@strcpy(@Buff,"db      "),@Str(CharToByte(RBuff[I]),3)));
    P =  0;
    inc  I;
  end

  I=0;
  while I<nType do
    word VMT [ftSIZE];
    word nMethod=0;

    FVMT(I,@nMethod,@VMT);

    if nMethod>0 then
      word L=TTabl[I].Ofs;
      word M=1;
      while M<=nMethod do
        if L!=0 then
          Code(0,"");
        end
        Code(L,@strcat(@strcpy(@Buff,"dw      @"),@Str(VMT[M],5)));
        L  = 0;
        inc  M;
      end
    end

    inc  I;
  end

  if pDest>0 then
    if (write(F2,@Dest,pDest)!=pDest) then
      Stop(@emWRITEERR);
    end
  end

  putc  (#13);
  puts  (@strcat(@strcat(@strcat(@strcpy(@Buff,@Name),"("),@Str(Line,0)),")"));

  close (F2);
  close (F1);
end
