Unit Expressify;
{* S Compiler, ver 1.00.
   Copyright (C) 1994, Henri LESOURD.

   This software is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This compiler is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  *}

Interface

Uses
    Crt,Errorify,Symbolize,Lexify,Assemblify,Addressify;

Procedure DeRefIt(Var TA : TypedAddress);
Procedure CompileParm(P,T : BoxPtr);
Procedure CompileCall(FName,ListParms : BoxPtr);
Procedure CompileOpPouvr(Var Resu : TypedAddress; B : BoxPtr);
Procedure Compile(Var Resu : TypedAddress; B : BoxPtr);
Procedure CompileExpr(Var Resu : TypedAddress; B : BoxPtr);

Implementation

{ **************************
  Inf‚rence du type d'1 expr
  ************************** }
Var
   CalculatingType : Boolean;

Procedure CalcTypeExpr(Var Resu : TypedAddress;
                              B : BoxPtr;
                       YouDeRef : Boolean);
Var
   C : ContextCompilo;
   O : Boolean;
Begin
{ Record contexte }
  O:=CalculatingType;
  SaveContextCompilo(C);
{ CalcType }
  CalculatingType:=True;
  Compile(Resu,B);
  If YouDeRef Then DeRefIt(Resu);
{ Restore contexte }
  RestoreContextCompilo(C);
  CalculatingType:=O;
End;

{ Procedure de d‚r‚f‚rencement; Prend 1 ref (au sens du compilo)
  sur la valeur d'un objet de type @ç, et la transcrit en 1 ref
  (tjrs au sens du compilo) sur l'objet point‚ par la ref (au
  sens du langage, cette fois ci). }
Procedure DeRefIt(Var TA : TypedAddress);
Var
   C : Boolean;
Begin
  If TA.SType^.Nature=Symbol Or ValTVRef Then
    Case TA.C Of
      Reg32:
        Begin
        { Checks }
          If (HiWord(TA.Value)<>rDS) And
             (HiWord(TA.Value)<>rSS) And
             (HiWord(TA.Value)<>rES)
          Then
            Error('DeRefIt : Reg32 : High must be a SegReg');

          If (LoWord(TA.Value)<>BX) And
             (LoWord(TA.Value)<>SI) And
             (LoWord(TA.Value)<>DI)
          Then
            Error('DeRefIt : Reg32 : Low must be an @Reg');

          If TA.Value=(rSS Shl 16) And BX Then Error('DeRefIt : Reg32 : Zob');

        { High(TA.Value) ==> Class(TA) }
          Case HiWord(TA.VAlue) Of
            rDS     : TA.C:=DS;
            rSS     : TA.C:=SS;
            rES     : TA.C:=ES;
          End;

        { Low }
          TA.Value:=TA.Value And $FFFF;
          TA.M:=IndReg;
          TVRefPtr(TA.SType):=TVRefPtr(TA.SType)^.Next;
        End;
      DS,SS,ES:
        Begin
          GetAddrReg32(TA,TA);
          TA.C:=ES;
          TA.M:=IndReg;
          TA.Value:=TA.Value And $FFFF;
          TVRefPtr(TA.SType):=TVRefPtr(TA.SType)^.Next;
        End
      Else
        Error('DeRefIt : bad TA.C');
    End;
End;

{ **************
  AccŠs symboles
  ************** }
{ Le ch. syst‚matique ds ES risque de poser problŠme...
  Je crois que c'est OK, en fait. }
Var
   NoParmsDefs : Boolean;

Procedure CompileAccessSymbol(Var Resu : TypedAddress; B : BoxPtr);
Var
   A1 : TypedAddress;
Begin
{ Checks }
  If SymbPtr(B)^.Addr.C=Null Then Error('CompileAccessSymbol : unbound variable')
  Else
  If NoParmsDefs And (
                        (SymbPtr(B)^.Addr.SType^.Nature=KeySub) Or
                        (SymbPtr(B)^.Addr.SType^.Nature=KeyDef)
                     )
  Then
    Begin
      CompileOpPouvr(Resu,B);
      Exit;
    End
    ;
  Resu:=SymbPtr(B)^.Addr;
  If Resu.C=Extern Then
    Begin
      Resu.C:=ES;
      SetHiWord(Resu.Value,0);
      If Not RegFree[rES] Then Error('CompileAccessSymbol extern : ES !Free');
      RegFree[rES]:=False;
      ImmAddr.Value:=$1234;
      GetReg16(A1,ImmAddr);
    { Ch. de reprise }
      PokeWAt(GetBPtr-2,Word(HiWord(SymbPtr(B)^.Addr.Value)));
      If Not CalculatingType Then SetHiWord(SymbPtr(B)^.Addr.Value,GetBPtr-2);
    { Chargement ES }
      Assemble(MOV,Reg[rES],A1);
      FreeReg16(A1);
    End
  ;
End;

{ ******************
  Appels de fonction
  ****************** }
Procedure CompileParm(P,T : BoxPtr);
Var
   TA : TypedAddress;
Begin
  Compile(TA,P);
  If (T^.Nature=Symbol Or ValTVRef) Or
     (T^.Nature=Symbol Or PredReference)
  Then
    If (TA.SType^.Nature=Symbol Or ValTVRef) Or
       (TA.SType^.Nature=Symbol Or PredReference)
    Then
    { Ref/Ref : pipeau }
      Begin
        If (T^.Nature<>Symbol Or PredReference) And
           (TA.SType^.Nature<>Symbol Or PredReference) And
           (Not TypeEQ(TVPtrPtr(TA.SType),TVPtrPtr(T)))
        Then
          Error('CompileParm : Ref/Ref : operand type doesnt match')
        ;
        StackIt(TA);
      End
    Else
    { THE passage en Var : passer l'ADRESSE de l'op‚rande : donc si ce
      n'est pas d‚j… 1 r‚f‚rence, erreur }
      Begin
      { Check ç }
        If (T^.Nature<>Symbol Or PredReference) And
           (Not TypeEQ(TVPtrPtr(TA.SType),TVPtrPtr(T)^.Next))
        Then
          Error('CompileParm : Ref/Val : operand type doesnt match')
        ;
      { Segment }
        Case TA.C Of
          SS: Assemble(PUSH,Reg[rSS],NullAddr);
          CS: Assemble(PUSH,Reg[rCS],NullAddr);
          DS: Assemble(PUSH,Reg[rDS],NullAddr);
          ES: Assemble(PUSH,Reg[rES],NullAddr);
          Else
            Error('CompileParm : Ref/Val : lvalue expected for PEs');
        End;

      { FreeRegs }
        FreeReg16(TA);

      { Offset }
        If TA.M=IndReg Then
          Begin
            Assemble(PUSH,Reg[LoWord(TA.Value)],NullAddr);
          End
        Else
          Begin
            If (TA.M<>IndOfs) Or (TA.C=SS) Then CurCOP:=LEA
                                           Else TA.C:=Immediate;
            GetReg16(TA,TA);
            Assemble(PUSH,TA,NullAddr);
            CurCOP:=MOV;
          End;
      End
  Else
  { Val/Ref; De toute fa‡on, il faut passer 1 Val, donc DeRef+StackIt }
    Begin
      DeRefIt(TA);
      If Not TypeEQ(TVPtrPtr(TA.SType),TVPtrPtr(T)) Then CastIt(TA,@T^);
      StackIt(TA);
    End;
End;

Procedure CompileCall(FName,ListParms : BoxPtr);
Var
   Proto : BoxPtr;
Begin
{ Free Tmps : VERIFIER si c'est bien -SizVarLoc (Id. ds CompileExpr). }
  SizTmp:=0;
  TopOfStack.Value:=-SizVarLoc;
  FreeAllRegs;
{ GetProto }
  Proto:=GetFuncType(FName)^.Gauche;
  If Proto^.Nature=Operator Or OpPouvr Then
    If Proto^.Gauche<>FName Then Error('CompileCall : Big hardos error')
                            Else Proto:=Proto^.Droite
  Else
  If Nature(Proto^.Nature)=Symbol Then
    If Proto<>FName Then Error('CompileCall : Big hardos error(2)')
                    Else Proto:=Nil
  Else
    Error('CompileCall : Big hardos error(3)');

{ Si Call … 1 fn externe, faire pusher DS }
  If SymbPtr(FName)^.Addr.C=Extern Then Assemble(PUSH,Reg[rDS],NullAddr);

{ Faire stacker les parms en checkant les types }
  While (ListParms<>Nil) And (ListParms^.Nature=Operator Or OpVirg) Do
  Begin
    If Proto=Nil Then Error('CompileCall : Big couille(0)');
    If Proto^.Nature<>Operator Or OpVirg Then Error('CompileCall : LPF <=> LPE : no match');

    If (Proto^.Droite=Nil) Or
       (Proto^.Droite^.Nature<>Operator Or OpAs) Or
       (Proto^.Droite^.Droite=Nil)
    Then
      Error('CompileCall : Big couille(1)');

    CompileParm(ListParms^.Droite,Proto^.Droite^.Droite);
    FreeAllRegs;
    ListParms:=ListParms^.Gauche;
    Proto:=Proto^.Gauche;
  End;

  If (Proto<>Nil) Then
    Begin
      If (Proto^.Nature<>Operator Or OpAs) Or
         (Proto^.Droite=Nil)
      Then
        Error('CompileCall : Big couille(2)');

      CompileParm(ListParms,Proto^.Droite);
      FreeAllRegs;
    End
  Else
    If ListParms<>Nil Then Error('CompileCall : 0 parms expected');

{ Generer le call }
  If SymbPtr(FName)^.Addr.C=Extern Then
    Begin
      Assemble(FCALL,SymbPtr(FName)^.Addr,NullAddr);
      If Not CalculatingType Then SetHiWord(SymbPtr(FName)^.Addr.Value,GetBPtr-2);
      Assemble(POP,Reg[rDS],NullAddr);
    End
  Else
    Begin
      If (SymbPtr(FName)^.Addr.C=Export) Or
         (SymbPtr(FName)^.Addr.C=NullExport)
      Then
        Assemble(PUSH,Reg[rCS],NullAddr)
        ;
      Assemble(NCALL,SymbPtr(FName)^.Addr,NullAddr);
    End
End;

Procedure CompileOpSize(Var Resu : TypedAddress; B : BoxPtr);
Begin
{ Check B }
  If B=Nil Then Error('OpSize : Nil B');
{ Compil B }
  If (Nature(B^.Nature)=Symbol) And (SymbPtr(B)^.Addr.C<>CType) Then
    Begin
      If SymbPtr(B)^.Addr.C=Null Then Error('OpSize : unbound symbol');
      B:=BoxPtr(SymbPtr(B)^.Addr.SType);
    End
  Else
    CalcType(B)
  ;
{ Set Resu }
  Resu.C:=Immediate;
  Resu.Value:=GetTypeSize(B);
  Resu.SType:=@SymbWord;
End;

Procedure CompileOpHigh(Var Resu : TypedAddress; B : BoxPtr);
Begin
{ Check B }
  If B=Nil Then Error('OpHigh : Nil B');
{ Compil B }
  Compile(Resu,B);
  DeRefIt(Resu);
{ Burst type }
  If (Resu.SType=Nil) Or (Nature(Resu.SType^.Nature)<>Symbol) Then Error('OpHigh : Khouill(1)');
  Case Name(Resu.SType^.Nature) Of
    PredInt,PredWord:
      Begin
        Case Resu.C Of
          Register:
            Begin
              If Not IsDataReg[Resu.Value] Then GetDataReg16(Resu,Resu,False);
              ByteAddr:=True;
              Assemble(MOV,Reg[Resu.Value],Reg[RegHigh[Resu.Value]]);
              ByteAddr:=False;
            End;
          Immediate:
            Resu.Value:=Hi(Resu.Value)
          ;
          CS,DS,SS,ES:
            Case Resu.M Of
              IndOfs: Inc(Resu.Value);
              IndReg:
                Begin
                  Resu.M:=IndRegOfs;
                  SetHiWord(Resu.Value,1);
                End;
              IndRegOfs: SetHiWord(Resu.Value,HiWord(Resu.Value)+1);
              Else
                Error('OpHigh : bad M');
            End;
          Else
            Error('OpHigh : bad C');
        End;
        If Name(Resu.SType^.Nature)=PredInt Then Resu.SType:=@SymbShortInt
                                            Else Resu.SType:=@SymbByte;
      End;
    PredLongWord,PredPointer,PredReference,ValTVPtr:
      Begin
        GetHigh(Resu,Resu);
        If Name(Resu.SType^.Nature)=PredLongInt Then Resu.SType:=@SymbInt
                                                Else Resu.SType:=@SymbWord;
        If (Resu.C=Register) And (IsSegReg[Resu.Value]) Then
          Begin
            GetDataReg16(Resu,Resu,False);
          End;
      End;
    Else
      Error('OpHigh : bad type');
  End;
End;

Procedure CompileOpLow(Var Resu : TypedAddress; B : BoxPtr);
Begin
{ Check B }
  If B=Nil Then Error('OpLow : Nil B');
{ Compil B }
  Compile(Resu,B);
  DeRefIt(Resu);
{ Burst type }
  If (Resu.SType=Nil) Or (Nature(Resu.SType^.Nature)<>Symbol) Then Error('OpLow : Khouill(1)');
  Case Name(Resu.SType^.Nature) Of
    PredInt,PredWord:
      Begin
        Case Resu.C Of
          Register : If Not IsDataReg[Resu.Value] Then GetDataReg16(Resu,Resu,False);
          Immediate: Resu.Value:=Lo(Resu.Value);
          CS,DS,SS,ES:
            Case Resu.M Of
              IndOfs,IndReg,IndRegOfs:;
              Else
                Error('OpLow : bad M');
            End;
          Else
            Error('OpLow : bad C');
        End;
        Resu.SType:=@SymbByte;
      End;
    PredLongWord,PredPointer,PredReference,ValTVPtr:
      Begin
        GetLow(Resu,Resu);
        Resu.SType:=@SymbWord;
      End;
    Else
      Error('OpLow : bad type');
  End;
End;

Procedure CompileOpPouvr(Var Resu : TypedAddress; B : BoxPtr);
Var
   A1,A2 : TypedAddress;
   BP : BoxPtr;
   BP2 : Box;
Begin
{ Check : B^.Gauche=Symbol }
  If (Nature(B^.Nature)<>Symbol) And
     (
        (Nature(B^.Nature)<>Operator) Or
        (B^.Gauche=Nil) Or
        (Nature(B^.Gauche^.Nature)<>Symbol)
     )
  Then
    Error('CompileOpPouvr : B|B^.Gauche=Symbol expected')
    ;
  If Nature(B^.Nature)=Symbol Then
    Begin
      BP2.Gauche:=B;
      BP2.Droite:=Nil;
      B:=@BP2;
      B^.Nature:=Operator Or OpPouvr;
    End
    ;
{ D‚codage : named cast (C=CType), pred func (C=Null), user func }
  Case SymbPtr(B^.Gauche)^.Addr.C Of
    CType:
      Begin
      { Check B^.Droite }
        If B^.Droite=Nil Then Error('Named cast : Nil B');
      { Compil B }
        Compile(Resu,B^.Droite);
        DeRefIt(Resu);
      { Cast }
        If Name(B^.Gauche^.Nature)=$3FFF
        Then
          BP:=BoxPtr(SymbPtr(B^.Gauche)^.Addr.Value)
        Else
          BP:=B^.Gauche
        ;
        If GetTypeSize(BP)=GetTypeSize(BoxPtr(Resu.SType))
        Then
          Resu.SType:=SymbPtr(BP)
        Else
          CastIt(Resu,SymbPtr(BP));
      End;
    Null:
      Case Name(B^.Gauche^.Nature) Of
        PredSize: CompileOpSize(Resu,B^.Droite);
        PredHigh: CompileOpHigh(Resu,B^.Droite);
        PredLow : CompileOpLow (Resu,B^.Droite);
        Else
          Error('CompileOpPouvr : bad pred func');
      End;
    Else
    { Appel de fns user }
      Begin
      { Ca a l'air d'ˆtre bon, … pr‚sent, mais je
        n'en mettrais pas ma main au feu... }
      { Faire GetReg des registres de sortie de la fn (AX, ou DX,AX) }
        GetFuncResultLocation(A1,B^.Gauche);
        ReallocReg(A1);
      { Faire stacker les registres !Free et enregistrer
        l'ensemble des regs ! Free ds 1 var. recursive }
        A2.Value:=StackUsedRegs;
      { Appeller CompileCall }
        CompileCall(B^.Gauche,B^.Droite);
      { Faire gen. le code pour le depilage des regs ! Free }
        FreeAllRegs;
        SetRegContainsOn(Resu,A1);
        UnStackRegSet(A2.Value);
      End;
  End;
End;

{ *****************************
  Compilation d'1 accŠs tableau
  ***************************** }
{ REMARQUE : Pour l'instant, on charge tjrs l'offset ds 1 reg@. Il
  faudra faire remonter l'info jusqu'ici si on veut optimiser & faire
  charger ‡a ds 1 regdata. Indispensable d'ailleurs pour les calcs ptr,
  ds le cas du segment. }
Procedure CompileAccessOffset(
                                Var      Resu : TypedAddress;
                                Var   TabTree : BoxPtr;
                                Var    Offset : TypedAddress;
                                Var      KhiO : Word;
                                            B : BoxPtr
                             );
Var
   A1,A2 : TypedAddress;
Begin
  If B=Nil Then Error('CompileAccessOffset : Nil B');
  If B^.Nature<>Operator Or OpCrouvr Then
    Begin
    { Calcul de l'@ du tab }
      CalcTypeExpr(Resu,B,True);
      TabTree:=B;
    End
  Else
    Begin
    { Calcul de l'@ du tab & compil du calc des indices de gauche }
      CompileAccessOffset(Resu,TabTree,Offset,KhiO,B^.Gauche);
    { Res est 1 TA contenant la CLASSE, et le type. A part la classe,
      les infos ne sont PAS calcul‚es (c'est math. impossible).
      Le seul autre truc qui puisse l'ˆtre … peu prŠs, c'est le
      mode : si mode=IndOfs, c'est que le tab est 1 var nomm‚e. }
      If (Ord(Resu.C)<Ord(DS)) Or (Ord(Resu.C)>Ord(ES)) Then Error('CompileAccessOffset : big couille(1)');

    { Calcul de l'indice }
      If B^.Droite=Nil Then Error('CompileAccessOffset : big couille(3)');
      If Nature(B^.Droite^.Nature)<>Constant Then
        Begin
          Compile(A1,B^.Droite);
          DeRefIt(A1);
          LoadIt(A2,A1,DefaultMode);
        End
      Else
        Begin
          Compile(A2,B^.Droite);
          DeRefIt(A2);
        End;


    { A2=Int, Register ou immediate }
      If (A2.C<>Immediate) And (A2.C<>Register) Then Error('CompileAccessOffset : big couille(2)');

      If Resu.SType^.Nature<>Symbol Or ValTVArray Then Error('CompileAccessOffset : X[Y] : Type(X)=Array expected');
      Case Name(A2.SType^.Nature) Of
        PredByte,PredLongWord:    CastIt(A2,@SymbWord);
        PredShortInt,PredLongInt: CastIt(A2,@SymbInt);
        PredInt,PredWord:;
        Else
          Error('CompileAccessOffset : Tab[Y] : Type(Y)=Int/Word expected');
      End;

    { Trait. FirstInd. Par la suite, il vaudra mieux donner au
      tab 1 @ factice=@Reelle-FirstInd*Sizelems. Ds ce cas, il
      faudra voir ce ki sse passe si on copie le tab ou si on
      passe son @ }
      ImmAddr.Value:=TVArrayPtr(Resu.SType)^.FirstInd;
      If ImmAddr.Value<>0 Then
        If A2.C=Immediate Then
          Begin
            A2.Value:=A2.Value-ImmAddr.Value;
          End
        Else
          Assemble(SUB,A2,ImmAddr);

    { Setting Type(Resu) }
      Resu.SType:=SymbPtr(TVArrayPtr(Resu.SType)^.Next);

    { Traitement * indice par Size(SubType) }
      ImmAddr.Value:=GetTypeSize(BoxPtr(Resu.SType));
      If ImmAddr.Value<>1 Then
        If A2.C=Immediate Then
          Begin
            A2.Value:=A2.Value*ImmAddr.Value;
          End
        Else
        { ATTENTION A CA : il faut verifier av. debug
          ke IMUL imm. n'ecrase pas DX (sinon, s'il
          y a 1 res. inter. dedans, pas la peine de
          faire un dessin...)
       =>
          C'est OK pour ‡a. }
        { A2.C=Register }
          Begin
            If A2.Value=AX Then
              Begin
                GetNamedReg16(A1,DX,ImmAddr);
                Assemble(MUL,A1,NullAddr);
                FreeReg16(A1);
              End
            Else
              Begin
                If (Not RegFree[DX]) And (A2.Value<>DX) Then ReallocNamedReg16(DX);
                If RegFree[DX] Then
                  Begin
                    RegFree[DX]:=False;
                    GetNamedReg16(A1,AX,ImmAddr);
                    RegFree[DX]:=True;
                  End
                Else
                  GetNamedReg16(A1,AX,ImmAddr);

                Assemble(MUL,A2,NullAddr);
                FreeReg16(A2);
                A2:=Reg[AX];
                RegContains[AX]:=@A2;
              End;
          End;

    { *******************************************************
      Arriv‚ l…, on a le morceau d'offset correspondant ds A2
      ******************************************************* }

    { Si l'offset n'a tjrs pas n‚c‚ssit‚ l'utilisation d'1 reg d'@ : en
      allouer un et MOVer A2 dedans; Pas super : il aurait fallu que …
      l'int‚rieur de Compile elle-mˆme, on fasse g‚n‚rer la 1st alloc
      ds 1 reg @ (au cas o— il n'y a ni MUL/DIV ni cast). Bref, on
      manque d'une vraie strat‚gie d'alloc regs.
      REM : TP ne le fait pas : il calcule tjrs l'indice ds 1 regdata,
      et ensuite, il fait, f.e, MOV DI,AX }
      If A2.C<>Immediate Then
        If Offset.C=Null Then
          If Resu.M=IndOfs Then GetAddrReg16(Offset,A2,Resu.C<>SS)
          Else
            Begin
              Offset:=A2;
              RegContains[A2.Value]:=@Offset;
            End
        Else
          Begin
            Assemble(ADD,Offset,A2);
            FreeReg16(A2);
          End
      Else
        Inc(KhiO,A2.Value)
      ;
    End
  ;
End;

Procedure CompileAccessArray(Var Resu : TypedAddress; B : BoxPtr);
Var
   Offset,TA : TypedAddress;
   TabTree : BoxPtr;
   KhiO : Word;
Begin
{ Compil du calcul de l'offset }
  KhiO:=0;
  TabTree:=Nil;
  Offset.C:=Null;
  CompileAccessOffset(Resu,TabTree,Offset,KhiO,B);

{ M‚mo du type de l'‚l‚ment acc‚d‚ }
  B:=BoxPtr(Resu.SType);

{ Check TabTree }
  If TabTree=Nil Then Error('CompileAccess : Nil TabTree');

{ Compil de l'@ de l'objet tableau }
  Compile(Resu,TabTree);
  DeRefIt(Resu);

{ ****************************
  Mix de @Tab & offset ds Resu
  **************************** }
{ Trait. KhiO }
  Case Resu.M Of
    IndOfs: Inc(Resu.Value,KhiO);
    IndReg:
      Begin
        Resu.M:=IndRegOfs;
        SetHiWord(Resu.Value,KhiO);
      End;
    IndRegOfs: SetHiWord(
                          Resu.Value,
                          HiWord(Resu.Value)+KhiO
                        );
  End;

{ Trait. Offset variable (au cas ou Offset.C<>Null, donc). }
  If (Offset.C=Register) Or (Offset.C=SS) Then
    Case Resu.M Of
      IndOfs:
      { REM : On ch. tjrs ds 1 reg@. La ref est tjrs suppos‚e ˆtre
        utilis‚e pour effectuer ensuite un accŠs (et pas pour servir
        … un calcul; La data est de type ptr, pas donn‚e). }
        Begin
          Resu.M:=IndRegOfs;
          SetHiWord(Resu.Value,Resu.Value);
        { Ds ce cas, il faut que Offset soit 1
          reg d'@, ou le foutre ds 1 reg d'@ }
          If (Offset.C=Register) And
             (
                (
                  (Offset.Value>=SI) And (Offset.Value<=DI)
                )
              Or
                (
                  (Offset.Value=BX) And (Resu.C<>SS)
                )
             )
          Then
            Begin
              SetLoWord(Resu.Value,Offset.Value);
              RegContains[Offset.Value]:=@Resu;
            End
          Else
            Begin
              GetAddrReg16(TA,Offset,Resu.C<>SS);
              SetLoWord(Resu.Value,TA.Value);
              RegContains[TA.Value]:=@Resu;
            End;
        End;
      IndReg,IndRegOfs:
        Begin
          Assemble(ADD,Reg[LoWord(Resu.Value)],Offset);
          FreeReg16(Offset);
        End;
    End
  Else
    If Offset.C<>Null Then Error('CompileAccess : BigKhouill(Offset)(I)');

{ Maj SType(Resu) }
  Resu.SType:=SymbPtr(B);
End;

{ ************
  AccŠs record
  ************ }
Procedure CompileAccessRecord(Var Resu : TypedAddress; B : BoxPtr);
Var
   A2 : TypedAddress;
Begin
  Compile(Resu,B^.Gauche);
  DeRefIt(Resu);
{ Resu est tjrs 1 REFERENCE, de type Record. Au cas ou le
  record est obtenu par l'intermediaire d'1 pointeur,
  c'est l'opn ^ qui doit se charger de retranscrire
  cette VALEUR de type pointeur en 1 reference. }
  If (Ord(Resu.C)<Ord(DS)) Or (Ord(Resu.C)>Ord(ES)) Then Error('Compile : OpPoint : big couille(1)');
  If B^.Droite=Nil Then Error('Compile : OpPoint : big couille(3)');

{ Calcul de l'offset du champ, d‚not‚ par B^.Droite }
  If Nature(B^.Droite^.Nature)=Symbol Then
    Begin
      A2.Value:=0;
      A2.SType:=Resu.SType;
      If A2.SType^.Nature<>Symbol Or ValTVRecord Then Error('Compile : OpPoint : R.S, Type(R)=Record expected');
      TVRecElemPtr(A2.SType):=TVRecordPtr(A2.SType)^.First;
      While (A2.SType<>Nil) And
            (TVRecElemPtr(A2.SType)^.Name<>SymbPtr(B^.Droite)) Do
      Begin
        Inc(A2.Value,
            GetTypeSize(
                BoxPtr(
                   TVRecElemPtr(A2.SType)^.SType
                )
            )
        );
        TVRecElemPtr(A2.SType):=TVRecElemPtr(A2.SType)^.Next
      End;
      If A2.SType=Nil Then Error('Compile : OpPoint : field !Found');
    { Arriv‚ ici, on a A2.Value=Offset ds le record, et
                       A2.SType=Type du champ
    }
    End
  Else
    Error('Compile : OpPoint : (ExprLValue).SYMB expected');

{ Modes possibles pour la ref sur Resu: IndOfs,IndReg,IndRegOfs.
  Pour l'instant, je suppose tjrs k'1 ref style [Ri] a le Ri
  valide (d'ailleurs, MajRegContains se plante sur 1 @ comme ca). }

{ Setting Type(Resu) }
  Resu.SType:=TVRecElemPtr(A2.SType)^.SType;

{ Calcul de la r‚f‚rence sur l'elem du record }
  Case Resu.M Of
    IndOfs: Inc(Resu.Value,A2.Value);
    IndReg:
      Begin
        Resu.M:=IndRegOfs;
        SetHiWord(Resu.Value,A2.Value);
      End;
    IndRegOfs: SetHiWord(
                          Resu.Value,
                          HiWord(Resu.Value)+A2.Value
                        );
  End;
End;

{ **************
  AccŠs pointeur
  ************** }
Procedure CompileAccessPointer(Var Resu : TypedAddress; B : BoxPtr);
Var
   A2 : TypedAddress;
Begin
  If B^.Droite<>Nil Then Error('Compile : access : X^ expected : X^Y found');
  Compile(A2,B^.Gauche);
  DeRefIt(A2);
  LoadIt(Resu,A2,DefaultMode);
  If (Resu.SType^.Nature<>Symbol Or ValTVPtr) Then Error('Compile : access : X^ : type(X)=^type'' expected');

  If (Resu.C<>Reg32) Or
     (
        (HiWord(Resu.Value)<>rDS) And
        (HiWord(Resu.Value)<>rSS) And
        (HiWord(Resu.Value)<>rES)
     )
  Or
     (
        (LoWord(Resu.Value)<>BX) And
        (LoWord(Resu.Value)<>SI) And
        (LoWord(Resu.Value)<>DI)
     )
  Then
    Error('Compile : access : only Reg32 DS,SS,ES:Reg@ for pointer values now');

  Case HiWord(Resu.Value) Of
    rDS:      Resu.C:=DS;
    rSS:      Resu.C:=SS;
    rES:      Resu.C:=ES;
  End;
  Resu.Value:=LoWord(Resu.Value);
  Resu.M:=IndReg;
  Resu.SType:=SymbPtr(TVPtrPtr(Resu.SType)^.Next);
End;

{ *****************
  Op‚rateur adresse
  ***************** }
Procedure CompileOpAdr(Var Resu : TypedAddress; B : BoxPtr);
Var
   A1,A2 : TypedAddress;
Begin
  If B^.Gauche<>Nil Then Error('Compile : OpAdr : @Y expected : X@Y found');
  If B^.Droite=Nil Then Error('Compile : OpAdr : parm expected');
  If Nature(B^.Droite^.Nature)=Symbol Then NoParmsDefs:=False;
  Compile(A1,B^.Droite);
  NoParmsDefs:=True;
  If ((Ord(A1.C)>Ord(ES)) Or (Ord(A1.C)<Ord(CS))) And
      (A1.SType^.Nature<>Symbol Or PredReference) And
      (A1.SType^.Nature<>Symbol Or ValTVRef) And
      (A1.C<>Export)
  Then
    Error('Compile : OpAdr (Val) : lvalue expected')
  ;
{ Je change ce truc, car il n'est plus d'actualit‚ : une fn qui calcule une
  r‚f‚rence peut trŠs bien renvoyer son r‚sultat ds un Reg32, f.e }
{ A‹e, a‹e, a‹e !!! Ca commence … bronxer sec !!! }
  If A1.SType^.Nature=Symbol Or ValTVRef Then
    Begin
      A1.SType:=CalcTVPtr(TVPtrPtr(A1.SType)^.Next);
      SetRegContainsOn(Resu,A1);
    End
  Else
  If A1.SType^.Nature=Symbol Or PredReference Then
    Begin
      A1.SType:=@SymbPointer;
      SetRegContainsOn(Resu,A1);
    End
  Else
    Begin
      FreeReg16(A1);
      A2:=A1;
      If (A1.M<>IndOfs) Or (A1.C=SS) Then CurCOP:=LEA
                                     Else A1.C:=Immediate;
      GetAddrReg16(Resu,A1,True);
      CurCOP:=MOV;
      If (A2.C=CS) Or (A2.C=Export) Then SetHiWord(Resu.Value,rCS)
      Else
      If A2.C=SS Then SetHiWord(Resu.Value,rSS)
      Else
      If A2.C=DS Then SetHiWord(Resu.Value,rDS)
      Else
        SetHiWord(Resu.Value,rES);

      Resu.C:=Reg32;
      Resu.SType:=CalcTVPtr(Resu.SType);
    End;
End;

{ *************************
  Op‚rateurs de comparaison
  ************************* }
Var
   TA,TA1,TA2 : TypedAddress;
   InvJump : Array[JZ..JAE] Of COP;
   CutJump : Array[JZ..JAE] Of COP;
   STestCOP : Array[OpEq..OpSupEq] Of COP;
   UTestCOP : Array[OpEq..OpSupEq] Of COP;
Procedure CompileOpCmp(OpName : Word; Var Resu,A1,A2 : TypedAddress);
Var
   CP : COP;
Begin
  If (A1.SType=@SymbInt) Or (A1.SType=@SymbWord) Or
     (A1.SType=@SymbShortInt) Or (A1.SType=@SymbByte) Then
  Begin
    If (A1.C=Register) Or (A2.C=Register) Then
      Begin
        Assemble(CMP,A1,A2);
        FreeReg16(A1);
        FreeReg16(A2);
      End
    Else
      Begin
        GetNamedReg16(Resu,AX,A1);
        Assemble(CMP,Resu,A2);
        FreeReg16(Resu);
        FreeReg16(A2);
      End;

    If CurLabel.C<>Null Then
      Begin
        If (A1.SType=@SymbInt) Or (A1.SType=@SymbShortInt) Then
          CP:=STestCOP[OpName]
        Else
          CP:=UTestCOP[OpName];

        If InvCondJump Then CP:=InvJump[CP];
        Assemble(CP,CurLabel,NullAddr);
      End
    Else
      Error('OpCmp : Uninitialized CurLabel(16)');

    Resu:=NullAddr;
    Resu.SType:=@SymbInt{Boolean};
  End
  Else
  If (IsPointer(A1.SType)) Or
     (A1.SType=@SymbLongInt) Or
     (A1.SType=@SymbLongWord) Then
  Begin
  { Check CurLabel }
    If CurLabel.C=Null Then Error('OpCmp : Uninitialized CurLabel(32)');

  { Comparaison poids forts }
    GetHigh(TA1,A1);
    GetHigh(TA2,A2);
    If (A1.C=Reg32) Or (A1.C=RegMem32) Then
      Begin
        If IsSegReg[TA1.Value] Then GetReg16(TA1,TA1);
        Assemble(CMP,TA1,TA2);
        FreeReg16(TA1);
        FreeReg16(TA2);
      End
    Else
    If (A2.C=Reg32) Or (A2.C=RegMem32) Then
      Begin
        If IsSegReg[TA2.Value] Then GetReg16(TA2,TA2);
        Assemble(CMP,TA1,TA2);
        FreeReg16(TA1);
        FreeReg16(TA2);
      End
    Else
      Begin
        GetNamedReg16(TA,DX,TA1);
        Assemble(CMP,TA,TA2);
        FreeReg16(TA);
      End;

  { Le label AfterTest (New) }
    NewLabel(Resu);

  { 1er test }
    If (OpName<>OpEq) And (OpName<>OpNeq) Then
      Begin
        If A1.SType=@SymbLongInt Then CP:=STestCOP[OpName]
                                 Else CP:=UTestCOP[OpName];
        If InvCondJump Then CP:=InvJump[CP];
        CP:=CutJump[CP];
        Assemble(CP,CurLabel,NullAddr);
        CP:=CutJump[InvJump[CP]];
        Assemble(CP,Resu,NullAddr);
      End
    Else
      Begin
        CP:=UTestCop[OpName];
        If InvCondJump Then CP:=InvJump[CP];
        If CP=JZ Then Assemble(JNZ,Resu,NullAddr)
                 Else Assemble(JNZ,CurLabel,NullAddr);
      End;

  { Comparaison poids faibles }
    GetLow(TA1,A1);
    GetLow(TA2,A2);
    If (A1.C=Reg32) Or (A1.C=RegMem32) Then
      Begin
        Assemble(CMP,TA1,TA2);
        FreeReg16(TA1);
        FreeReg16(TA2);
      End
    Else
    If (A2.C=Reg32) Or (A2.C=RegMem32) Then
      Begin
        Assemble(CMP,TA1,TA2);
        FreeReg16(TA1);
        FreeReg16(TA2);
      End
    Else
      Begin
        GetNamedReg16(TA,DX,TA1);
        Assemble(CMP,TA,TA2);
        FreeReg16(TA);
      End;

  { 2nd test (lexico) }
    CP:=UTestCOP[OpName];
    If InvCondJump Then CP:=InvJump[CP];
    Assemble(CP,CurLabel,NullAddr);

  { Le label AfterTest (Put) }
    PutLabel(Resu);

  { Cassos }
    Resu:=NullAddr;
    Resu.SType:=@SymbInt{Boolean};
  End
  Else
    Error('CompileCmpOp : bad type');
End;

{ *******************
  Op‚rateurs logiques
  ******************* }
Procedure CompileNot(Var Resu : TypedAddress; B : BoxPtr);
Var
   TA : TypedAddress;
   OI : Boolean;
Begin
  If CurLabel.C=Null Then Error('CompileNot : Null CurLabel');
  If (B^.Gauche<>Nil) Or (B^.Droite=Nil) Then Error('CompileNot : Bad operands');
  OI:=InvCondJump;
  InvCondJump:=Not InvCondJump;
  Compile(TA,B^.Droite);
  If TA.C<>Null Then
  Begin
    ByteAddr:=GetTypeSize(BoxPtr(TA.SType))=1;
    Assemble(CMP,TA,ImmZero);
    If InvCondJump Then Assemble(JZ,CurLabel,NullAddr)
                   Else Assemble(JNZ,CurLabel,NullAddr);
    ByteAddr:=False;
  End;
  InvCondJump:=OI;
  Resu.C:=Null;
  Resu.SType:=@SymbInt;
End;

Procedure CompileAnd(Var Resu : TypedAddress; B : BoxPtr);
Var
   OC,TA : TypedAddress;
   OI : Boolean;
Begin
  If CurLabel.C=Null Then Error('CompileAnd : Null CurLabel');

  OI:=InvCondJump;
  InvCondJump:=True;
  If Not OI Then
    Begin
      OC:=CurLabel;
      NewLabel(CurLabel);
    End;

  While (B^.Nature=Operator Or OpAnd) Do
  Begin
    If (B^.Gauche=Nil) Or (B^.Droite=Nil) Then Error('CompileAnd : missing operand');
    If Nature(B^.Gauche^.Nature)=Symbol Then
      Begin
        TA:=SymbPtr(B^.Gauche)^.Addr;
        Assemble(CMP,TA,ImmZero);
        Assemble(JNZ,CurLabel,NullAddr);
      End
    Else
      Compile(TA,B^.Gauche);

    If TA.SType<>@SymbInt Then Error('CompileAnd : Int operands expected');
    FreeReg16(TA);

    B:=B^.Droite;
  End;

  If Nature(B^.Nature)=Symbol Then
    Begin
      TA:=SymbPtr(B)^.Addr;
      Assemble(CMP,TA,ImmZero);
      Assemble(JNZ,CurLabel,NullAddr);
    End
  Else
    Compile(TA,B);

  If TA.SType<>@SymbInt Then Error('CompileAnd : Int operands expected');
  FreeReg16(TA);

  If Not OI Then
    Begin
      Assemble(JMP,OC,NullAddr);
      PutLabel(CurLabel);
      CurLabel:=OC;
    End;

  InvCondJump:=OI;
  Resu.C:=Null;
  Resu.SType:=@SymbInt;
End;

Procedure CompileOr(Var Resu : TypedAddress; B : BoxPtr);
Var
   OC,TA : TypedAddress;
   OI : Boolean;
Begin
  If CurLabel.C=Null Then Error('CompileOr : Null CurLabel');

  OI:=InvCondJump;
  InvCondJump:=False;
  If OI Then
    Begin
      OC:=CurLabel;
      NewLabel(CurLabel);
    End;

  While (B^.Nature=Operator Or OpOr) Do
  Begin
    If (B^.Gauche=Nil) Or (B^.Droite=Nil) Then Error('CompileOr : missing operand');
    If Nature(B^.Gauche^.Nature)=Symbol Then
      Begin
        TA:=SymbPtr(B^.Gauche)^.Addr;
        Assemble(CMP,TA,ImmZero);
        Assemble(JZ,CurLabel,NullAddr);
      End
    Else
      Compile(TA,B^.Gauche);

    If TA.SType<>@SymbInt Then Error('CompileOr : Int operands expected');
    FreeReg16(TA);

    B:=B^.Droite;
  End;

  If Nature(B^.Nature)=Symbol Then
    Begin
      TA:=SymbPtr(B)^.Addr;
      Assemble(CMP,TA,ImmZero);
      Assemble(JZ,CurLabel,NullAddr);
    End
  Else
    Compile(TA,B);

  If TA.SType<>@SymbInt Then Error('CompileOr : Int operands expected');
  FreeReg16(TA);

  If OI Then
    Begin
      Assemble(JMP,OC,NullAddr);
      PutLabel(CurLabel);
      CurLabel:=OC;
    End;

  InvCondJump:=OI;
  Resu.C:=Null;
  Resu.SType:=@SymbInt;
End;

{ ***********
  Op‚rateur +
  *********** }
Procedure CompileAdditiveOp(Var Resu,A1,A2 : TypedAddress; HiCOP,LoCOP : COP);
Begin
  If (A1.SType=@SymbInt) Or (A1.SType=@SymbWord) Or
     (A1.SType=@SymbShortInt) Or (A1.SType=@SymbByte) Then
  Begin
    If A1.C=Register Then
      Begin
        Assemble(LoCOP,A1,A2);
        Resu:=A1;
        RegContains[A1.Value]:=@Resu;
        FreeReg16(A2);
      End
    Else
    If A2.C=Register Then
      Begin
        Assemble(LoCOP,A2,A1);
        Resu:=A2;
        RegContains[A2.Value]:=@Resu;
        FreeReg16(A1);
      End
    Else
      Begin
        GetNamedReg16(Resu,AX,A1);
        Assemble(LoCOP,Resu,A2);
      End;
  End
  Else
  If (A1.SType=@SymbLongInt) Or (A1.SType=@SymbLongWord) Then
  Begin
  { Poids faible }
    Resu.C:=Reg32;
    Resu.SType:=A1.SType;
    GetLow(TA1,A1);
    GetLow(TA2,A2);
    If (A1.C=Reg32) Or (A1.C=MemReg32) Then
      Begin
        Assemble(LoCOP,TA1,TA2);
        SetLow(Resu,TA1);
        RegContains[TA1.Value]:=@Resu;
        FreeReg16(TA2);
      End
    Else
    If (A2.C=Reg32) Or (A2.C=MemReg32) Then
      Begin
        Assemble(LoCOP,TA2,TA1);
        SetLow(Resu,TA2);
        RegContains[TA2.Value]:=@Resu;
        FreeReg16(TA1);
      End
    Else
      Begin
        GetNamedReg16(TA,AX,TA1);
        RegContains[AX]:=@Resu;
        Assemble(LoCOP,TA,TA2);
        SetLow(Resu,TA);
      End;

  { Poids fort }
    GetHigh(TA1,A1);
    GetHigh(TA2,A2);
    If (A1.C=Reg32) Or (A1.C=RegMem32) Then
      Begin
        Assemble(HiCOP,TA1,TA2);
        SetHigh(Resu,TA1);
        RegContains[TA1.Value]:=@Resu;
        FreeReg16(TA2);
      End
    Else
    If (A2.C=Reg32) Or (A2.C=RegMem32) Then
      Begin
        Assemble(HiCOP,TA2,TA1);
        SetHigh(Resu,TA2);
        RegContains[TA2.Value]:=@Resu;
        FreeReg16(TA1);
      End
    Else
      Begin
        GetNamedReg16(TA,DX,TA1);
        Assemble(HiCOP,TA,TA2);
        SetHigh(Resu,TA);
      End;
  End
  Else
    Error('Compile : + : bad type');
End;

{ ***********
  Op‚rateur -
  *********** }
Procedure CompileOpSub(Var Resu,A1,A2 : TypedAddress);
Begin
  If (A1.SType=@SymbInt) Or (A1.SType=@SymbWord) Or
     (A1.SType=@SymbShortInt) Or (A1.SType=@SymbByte) Then
  Begin
    If A1.C=Register Then
      Begin
        Assemble(SUB,A1,A2);
        Resu:=A1;
        RegContains[A1.Value]:=@Resu;
        FreeReg16(A2);
      End
    Else
    If A2.C=Register Then
      Begin
        Assemble(SUB,A2,A1);
        Assemble(NEG,A2,NullAddr);
        Resu:=A2;
        RegContains[A2.Value]:=@Resu;
        FreeReg16(A1);
      End
    Else
      Begin
        GetNamedReg16(Resu,AX,A1);
        Assemble(SUB,Resu,A2);
      End;
  End
  Else
  If (A1.SType=@SymbLongInt) Or (A1.SType=@SymbLongWord) Then
  Begin
  { Poids faible }
    Resu.C:=Reg32;
    Resu.SType:=A1.SType;
    GetLow(TA1,A1);
    GetLow(TA2,A2);
    If (A1.C=Reg32) Or (A1.C=MemReg32) Then
      Begin
        Assemble(SUB,TA1,TA2);
        SetLow(Resu,TA1);
        RegContains[TA1.Value]:=@Resu;
        FreeReg16(TA2);
      End
    Else
    If (A2.C=Reg32) Or (A2.C=MemReg32) Then
      Begin
        GetReg16(TA,TA1);
        Assemble(SUB,TA,TA2);
        SetLow(Resu,TA);
        RegContains[TA.Value]:=@Resu;
        FreeReg16(TA2);
      End
    Else
      Begin
        GetNamedReg16(TA,AX,TA1);
        RegContains[AX]:=@Resu;
        Assemble(SUB,TA,TA2);
        SetLow(Resu,TA);
      End;

  { Poids fort }
    GetHigh(TA1,A1);
    GetHigh(TA2,A2);
    If (A1.C=Reg32) Or (A1.C=RegMem32) Then
      Begin
        Assemble(SBB,TA1,TA2);
        SetHigh(Resu,TA1);
        RegContains[TA1.Value]:=@Resu;
        FreeReg16(TA2);
      End
    Else
    If (A2.C=Reg32) Or (A2.C=RegMem32) Then
      Begin
        GetReg16(TA,TA1);
        Assemble(SBB,TA,TA2);
        SetHigh(Resu,TA);
        RegContains[TA.Value]:=@Resu;
        FreeReg16(TA2);
      End
    Else
      Begin
        GetNamedReg16(TA,DX,TA1);
        Assemble(SBB,TA,TA2);
        SetHigh(Resu,TA);
      End;
  End
  Else
    Error('Compile : - : bad type');
End;

{ ***********
  Op‚rateur *
  *********** }
Procedure CompileOpMul(Var Resu,A1,A2 : TypedAddress);
Var
   CP : COP;
Begin
  If (A1.SType=@SymbInt) Or (A1.SType=@SymbWord) Or
     (A1.SType=@SymbShortInt) Or (A1.SType=@SymbByte) Then
  Begin
    If (A1.SType=@SymbInt) Or (A1.SType=@SymbShortInt)
    Then
      CP:=IMUL
    Else
      CP:=MUL;

    If (RegFree[DX]=False) And
       (Not
            (
               ((A1.C=Register) And (A1.Value=DX)) Or
               ((A2.C=Register) And (A2.Value=DX))
            )
       )
    Then
      ReallocNamedReg16(DX);

    If (A1.C=Register) And (A1.Value=AX) Then
      Begin
        If A2.C=Immediate Then
          Begin
            Assemble(MOV,Reg[DX],A2);
            Assemble(CP,Reg[DX],NullAddr);
          End
        Else
          Assemble(CP,A2,NullAddr);

        Resu:=A1;
        RegContains[A1.Value]:=@Resu;
        FreeReg16(A2);
      End
    Else
    If (A2.C=Register) And (A2.Value=AX) Then
      Begin
        If A1.C=Immediate Then
          Begin
            Assemble(MOV,Reg[DX],A1);
            Assemble(CP,Reg[DX],NullAddr);
          End
        Else
          Assemble(CP,A1,NullAddr);

        Resu:=A2;
        RegContains[A2.Value]:=@Resu;
        FreeReg16(A1);
      End
    Else
    If A2.C=Immediate Then
      Begin
        GetNamedReg16(Resu,AX,A2);
        Assemble(CP,A1,NullAddr);
        FreeReg16(A1);
      End
    Else
      Begin
        GetNamedReg16(Resu,AX,A1);
        Assemble(CP,A2,NullAddr);
        FreeReg16(A2);
      End
  End
  Else
  If (A1.SType=@SymbLongInt) Or (A1.SType=@SymbLongWord) Then Error('Mul32 ! yet')
  Else
    Error('Compile : * : bad type');
End;

{ **************
  Op‚rateurs /,%
  ************** }
Procedure CompileOpDivMod(OpName : Word; Var Resu,A1,A2 : TypedAddress);
Var
   OpCOP : COP;
Begin
  Case Name(A1.SType^.Nature) Of
    PredByte,PredWord,PredShortInt,PredInt:
    Begin
      Case Name(A1.SType^.Nature) Of
        PredShortInt,PredInt: OpCOP:=IDIV;
        Else                  OpCOP:=UDIV;
      End;
      If Not RegFree[DX] Then ReallocNamedReg16(DX);
      If (A1.C<>Register) Or (A1.Value<>AX) Then
      Begin
        RegFree[DX]:=False;
        GetNamedReg16(Resu,AX,A1);
        RegFree[DX]:=True;
      End;
      If A2.C=Immediate Then
      Begin
        SetFirstLastReg(CX,BX);
        GetReg16(A2,A2);
        SetFirstLastReg(AX,BX);
      End;
      Assemble(OpCOP,A2,NullAddr);
      Case OpName Of
        OpDiv: SetRegContainsOn(Resu,Reg[AX]);
        OpMod:
          Begin
            FreeReg16(A1);
            SetRegContainsOn(Resu,Reg[DX]);
          End;
        Else
          Error('Compile : /,% : Khouill(Bad OpName)');
      End;
      FreeReg16(A2);
    End;
    PredLongWord,PredLongInt: Error('Div32/Mod32 !Yet');
    Else
      Error('Compile : /,% : bad type');
  End;
End;

{ ***********
  +/- unaires
  *********** }
Procedure CompileOpPlusMoins(Var Resu : TypedAddress; B : BoxPtr);
Var
   A1,A2,R : TypedAddress;
Begin
  If (B=Nil) Or (B^.Droite=Nil) Then Error('Unary +/-/~ : Nil B or B^.D');
  Compile(Resu,B^.Droite);
  DeRefIt(Resu);
  If Resu.C=Immediate Then CalcExprConst(Resu,Name(B^.Nature),ImmAddr,Resu)
  Else
    Begin
      If Not IsInteger(Resu.SType) Then Error('Unary +/-/~ : bad type');
      If B^.Nature=Operator Or OpLogNot Then
      Begin
        ByteAddr:=GetTypeSize(BoxPtr(Resu.SType))=1;
        Case Name(Resu.SType^.Nature) Of
          PredByte,PredWord,
          PredShortInt,PredInt:
            Begin
              LoadIt(Resu,Resu,DefaultMode);
              Assemble(CNOT,Resu,NullAddr);
              If ByteAddr Then Resu.SType:=@SymbByte
                          Else Resu.SType:=@SymbWord;
            End;
          PredLongWord,PredLongInt:
            Begin
              LoadIt(Resu,Resu,DefaultMode);
              GetLow(A1,Resu);
              Assemble(CNOT,A1,NullAddr);
              GetHigh(A1,Resu);
              Assemble(CNOT,A1,NullAddr);
              Resu.SType:=@SymbLongWord;
            End;
          Else
            Error('Unary ~ : bad type(2)');
        End;
        ByteAddr:=False;
      End
      Else If B^.Nature=Operator Or OpMoins Then
      Begin
        ByteAddr:=GetTypeSize(BoxPtr(Resu.SType))=1;
        Case Name(Resu.SType^.Nature) Of
          PredByte,PredWord,
          PredShortInt,PredInt:
            Begin
              LoadIt(Resu,Resu,DefaultMode);
              Assemble(NEG,Resu,NullAddr);
              If ByteAddr Then Resu.SType:=@SymbShortInt
                          Else Resu.SType:=@SymbInt;
            End;
          PredLongWord,PredLongInt:
            Begin
              GetReg32(R,ImmZero);
              GetLow(A1,R);
              GetLow(A2,Resu);
              Assemble(SUB,A1,A2);
              GetHigh(A1,R);
              GetHigh(A2,Resu);
              Assemble(SBB,A1,A2);
              FreeReg32(Resu);
              SetRegContainsOn(Resu,R);
              Resu.SType:=@SymbLongInt;
            End;
          Else
            Error('Unary +/- : bad type(2)');
        End;
        ByteAddr:=False;
      End;
    End
  ;
End;

{ ********************
  Ptr +/- Int16/Word16
  ******************** }
{ Pour le +,Iî(&H0000,&HFFF0); Idem -Int16; Par contre, pour -Word16,
  I doit ˆtre < &H7FFF, … cause de la normalisation utilis‚e. }
Procedure CompileAddPtr16(OpName : Word; Var Resu,AP,I : TypedAddress);
Var
   D1,D2,D3 : TypedAddress;
   C : COP;
Begin
{ Check ç(I) }
  Case I.SType^.Nature Of
    Symbol Or PredByte    : CastIt(I,@SymbWord);
    Symbol Or PredShortInt: CastIt(I,@SymbInt);
    Symbol Or PredInt,Symbol Or PredWord:;
    Else
      Error('CompileAddPtr16 : Ptr+<Badç>');
  End;
{ Set C }
  Case OpName Of
    OpAdd: C:=ADD;
    OpSub: C:=SUB;
    Else
      Error('AddrPtr16 : bad OpName');
  End;
{ Get Lo/Hi }
  GetHigh(D1,AP);
  GetLow(D2,AP);
{ ADD D2,I }
  If I.C=Register Then
    Begin
      Assemble(C,I,D2);
      FreeReg16(D2);
      SetRegContainsOn(D2,I);
      If C=SUB Then Assemble(NEG,D2,NullAddr);
    End
  Else
  If D2.C=Register Then
    Begin
      Assemble(C,D2,I);
      FreeReg16(I);
    End
  Else
    Error('AddPtr16 : ADD D2,I')
  ;
{ MOV D3,D2 }
  AllocReg16(D3);
  Assemble(MOV,D3,D2);
{ AND D2,&H000F }
  ImmAddr.Value:=$000F;
  Assemble(CAND,D2,ImmAddr);
{ SxR D3,4 }
  ImmAddr.Value:=$0004;
  If (C=SUB) Or (I.SType=@SymbInt) Then Assemble(SAR,D3,ImmAddr)
                                   Else Assemble(CSHR,D3,ImmAddr);
{ ADD D1,D3 }
  Assemble(ADD,D3,D1);
{ Resu=(D3,D2) }
  FreeReg16(D1);
  Resu.C:=Reg32;
  SetHigh(Resu,D3);
  SetLow(Resu,D2);
  Resu.SType:=AP.SType;
End;

{ ********************
  Ptr +/- Int32/Word32
  ******************** }
Procedure CompileAddPtr32(OpName : Word; Var Resu,A1,A2 : TypedAddress);
Begin
  Error('AddrPtr32 !Yet');
End;

{ *****************
  Operateurs values
  ***************** }
Procedure CompileOpBin(Var Resu : TypedAddress; B : BoxPtr);
Var
   A1,A2 : TypedAddress;
Begin
{ Checks }
  If (B^.Gauche=Nil) Or (B^.Droite=Nil) Then Error('OpBin : Nil G or Nil D');
{ Compil des 2 op‚randes }
  If (Nature(B^.Droite^.Nature)<>Operator) Or
     (Nature(B^.Gauche^.Nature)=Operator)
  Then
    Begin
      Compile(A1,B^.Gauche);
      DeRefIt(A1);
      If A1.C<>Immediate Then LoadIt(A1,A1,AddrDataMode);
      Compile(A2,B^.Droite);
      DeRefIt(A2);
    End
  Else
    Begin
      Compile(A2,B^.Droite);
      DeRefIt(A2);
      If A2.C<>Immediate Then LoadIt(A2,A2,DefaultMode);
      Compile(A1,B^.Gauche);
      DeRefIt(A1);
    End
  ;
{ Test Ptr }
  If ((B^.Nature=Operator Or OpAdd) Or (B^.Nature=Operator Or OpSub)
     )
     And
         IsPointer(A1.SType)
  Then
    Case A2.SType^.Nature Of
      Symbol Or PredShortInt,Symbol Or PredByte,
      Symbol Or PredInt,Symbol Or PredWord:
        CompileAddPtr16(Name(B^.Nature),Resu,A1,A2)
      ;
      Symbol Or PredLongInt,Symbol Or PredLongWord:
        CompileAddPtr32(Name(B^.Nature),Resu,A1,A2)
      ;
      Else
        Error('Compile : AddPtr/SubPtr : Ptr+<Badç>');
    End
  Else
    Begin
    { Check cast }
      If Not TypeEQ(@A1.SType^,@A2.SType^) Then
        If IsPointer(A1.SType) Then CastIt(A1,A2.SType)
        Else
        If IntTypeSup(A1.SType,A2.SType) Then CastIt(A2,A1.SType)
                                         Else CastIt(A1,A2.SType);
    { Const check }
      If (A1.C=Immediate) And (A2.C=Immediate)
      Then
        CalcExprConst(Resu,Name(B^.Nature),A1,A2)
      Else
        Begin
          ByteAddr:=GetTypeSize(BoxPtr(A1.SType))=1;
          Case Name(B^.Nature) Of
            OpEq,OpNeq,
            OpInf,OpInfEq,
            OpSup,OpSupEq : CompileOpCmp(Name(B^.Nature),Resu,A1,A2);
            OpAdd         : CompileAdditiveOp(Resu,A1,A2,ADC,ADD);
            OpLogAnd      : CompileAdditiveOp(Resu,A1,A2,CAND,CAND);
            OpLogOr       : CompileAdditiveOp(Resu,A1,A2,COR,COR);
            OpLogXor      : CompileAdditiveOp(Resu,A1,A2,CXOR,CXOR);
            OpSub         : CompileOpSub(Resu,A1,A2);
            OpMul         : CompileOpMul(Resu,A1,A2);
            OpDiv,OpMod   : CompileOpDivMod(Name(B^.Nature),Resu,A1,A2);
          End;
        End;
    End;
End;

{ *********
  D‚calages
  ********* }
Procedure KerCompileOpShift(OpName : Word; Var Resu,A1,A2 : TypedAddress);
Var
   A3,A4 : TypedAddress;
   HiCOP,LoCOP : COP;
Begin
{ Check casts }
  If A2.SType<>@SymbByte Then CastIt(A2,@SymbByte);
  If Not IsInteger(A1.SType) Then Error('OpShift : num operands expected');
{ Cas imm‚diat }
  If (A1.C=Immediate) And (A2.C=Immediate) Then Error('Shift : Imm !Yet')
  Else
    Begin
    { Set ByteAddr }
      ByteAddr:=GetTypeSize(BoxPtr(A1.SType))=1;
    { CalcHi/LoCOP }
      If OpName=OpRightShift Then
        Case Name(A1.SType^.Nature) Of
          PredByte,PredWord: LoCOP:=CSHR;
          PredLongWord:
            Begin
              LoCOP:=RCR;HiCOP:=CSHR;
            End;
          PredShortInt,PredInt: LoCOP:=SAR;
          PredLongInt:
            Begin
              LoCOP:=RCR;HiCOP:=SAR;
            End;
        End
      Else
        Begin
          LoCOP:=CSHL;HiCOP:=RCL;
        End
      ;
    { Burst }
      Case GetTypeSize(BoxPtr(A1.SType)) Of
        1,2:
          Begin
            If A2.C<>Immediate Then GetNamedReg16(A2,CX,A2);
            Assemble(LoCOP,A1,A2);
            FreeReg16(A2);
          End;
        4:
          If (A2.C=Immediate) And (A2.Value=1) Then
            If OpName=OpLeftShift Then
              Begin
              { Poids Faible }
                GetLow(A3,A1);
                GetLow(A4,A2);
                Assemble(LoCOP,A3,A4);
              { Poids Fort }
                GetHigh(A3,A1);
                Assemble(HiCOP,A3,A4);
                FreeReg32(A2);
              End
            Else
              Begin
              { Poids Fort }
                GetHigh(A3,A1);
                GetLow(A4,A2);
                Assemble(HiCOP,A3,A4);
              { Poids Faible }
                GetLow(A3,A1);
                Assemble(LoCOP,A3,A4);
                FreeReg32(A2);
              End
          Else
            Begin
              Error('Long Shift Var !Yet');
            End;
        Else
          Error('Shift cast : Big Khouill(1)');
      End;
      ByteAddr:=False;
      SetRegContainsOn(Resu,A1);
    End;
End;

Procedure CompileOpShift(Var Resu : TypedAddress; B : BoxPtr);
Var
   A1,A2 : TypedAddress;
Begin
{ Compil des 2 op‚randes }
  Compile(A1,B^.Gauche);
  DeRefIt(A1);
  If A1.C<>Immediate Then LoadIt(A1,A1,AddrDataMode);
  Compile(A2,B^.Droite);
  DeRefIt(A2);
  KerCompileOpShift(Name(B^.Nature),Resu,A1,A2);
End;

Procedure CompileOpShiftLet(Var Resu : TypedAddress; B : BoxPtr);
Var
   A1,A2 : TypedAddress;
Begin
{ Compil des 2 op‚randes }
  Compile(A1,B^.Gauche);
  DeRefIt(A1);
  If A1.C<>Immediate Then LoadIt(A1,A1,AddrDataMode);
  Compile(A2,B^.Droite);
  DeRefIt(A2);
  KerCompileOpShift(Name(B^.Nature),Resu,A1,A2);
End;

{ *******
  Mul/Div
  ******* }
Procedure CompileOpMulDiv(Var Resu : TypedAddress; B : BoxPtr);
Begin
  If Not RegFree[AX] Then
    If RegFree[DX] Then
      Begin
        RegFree[DX]:=False;
        ReallocNamedReg16(AX);
        RegFree[DX]:=True;
      End
    Else
      ReallocNamedReg16(AX)
  ;
  CompileOpBin(Resu,B);
End;

{ *************************
  Op‚rateur d'agglom‚ration
  ************************* }
Procedure CompileOpVirg(Var Resu : TypedAddress; B : BoxPtr);
Var
   A1,A2 : TypedAddress;
Begin
{ Compil des 2 op‚randes }
  If (Nature(B^.Droite^.Nature)<>Operator) Or
     (Nature(B^.Gauche^.Nature)=Operator)
  Then
    Begin
      Compile(A1,B^.Gauche);
      DeRefIt(A1);
      LoadIt(A1,A1,DefaultMode);
      Compile(A2,B^.Droite);
      DeRefIt(A2);
      LoadIt(A2,A2,DefaultMode);
    End
  Else
    Begin
      Compile(A2,B^.Droite);
      DeRefIt(A2);
      LoadIt(A2,A2,DefaultMode);
      Compile(A1,B^.Gauche);
      DeRefIt(A1);
      LoadIt(A1,A1,DefaultMode);
    End
  ;
{ Check sizes= }
  If GetTypeSize(BoxPtr(A1.SType))<>GetTypeSize(BoxPtr(A2.SType)) Then
    Case Name(A1.SType^.Nature) Of
      PredShortInt,PredInt,PredLongInt: CastIt(A1,@SymbInt);
      PredByte,PredWord,PredLongWord: CastIt(A2,@SymbWord);
    End
  ;
{ Burst on size }
  Case GetTypeSize(BoxPtr(A1.SType)) Of
    1: Begin
         If A2.SType<>@SymbByte Then CastIt(A2,@SymbByte);
         If A2.C<>Register Then LoadIt(A2,A2,DefaultMode);
         Resu.C:=Register;
         Resu.Value:=A2.Value;
         RegContains[Resu.Value]:=@Resu;
         ByteAddr:=True;
         Assemble(MOV,Reg[RegHigh[Resu.Value]],A1);
         ByteAddr:=False;
         FreeReg16(A1);
         Case Name(A1.SType^.Nature) Of
           PredShortInt: Resu.Stype:=@SymbInt;
           PredByte    : Resu.Stype:=@SymbWord;
         End;
       End;
    2: Begin
         If A2.SType<>@SymbWord Then CastIt(A2,@SymbWord);
         SetRegContainsOn(Resu,A1);
         SetRegContainsOn(Resu,A2);
         Resu.C:=Reg32;
         SetHigh(Resu,A1);
         SetLow(Resu,A2);
         Case Name(A1.SType^.Nature) Of
           PredInt : Resu.Stype:=@SymbLongInt;
           PredWord: Resu.Stype:=@SymbLongWord;
         End;
       End;
  End;
End;

{ ***********
  Affectation
  *********** }

Procedure CompileAdditiveLet(Var Resu,A1,A2 : TypedAddress; HiCOP,LoCOP : COP);
Var
   TA1,TA2 : TypedAddress;
Begin
  If IsScalaire8(A1.SType) Or IsScalaire16(A1.SType) Then
  { Let8/Let16 }
    Begin
    { Set ByteAddr }
      ByteAddr:=GetTypeSize(BoxPtr(A1.SType))=1;
    { Check A1 }
      Case A1.C Of
        Register,DS,SS,ES:;
        Else
          Error('CompileAdditiveLet(8-16) : check A1');
      End;
    { Check A2 }
      Case A2.C Of
        Immediate,Register,DS,SS,ES:;
        Else
          Error('CompileAdditiveLet(8-16) : check A2');
      End;
    { Codage }
      If A1.C=Register Then
        Begin
          SetRegContainsOn(Resu,A1);
          FreeReg16(A2);
        End
      Else
        Begin
        { Cas Mem=Mem }
          If (A2.C<>Register) And (A2.C<>Immediate) Then GetReg16(A2,A2);
        { Optim single let }
          If LoCOP=MOV Then
            Begin
              SetRegContainsOn(Resu,A2);
              FreeReg16(A1);
            End
          Else
            Begin
              SetRegContainsOn(Resu,A1);
              FreeReg16(A2);
            End
        End
      ;
      Assemble(LoCOP,A1,A2);
    End
  Else
  If GetTypeSize(@A1.SType^)=4 Then
  { Let32 }
    Begin
    { Check ByteAddr }
      If ByteAddr Then Error('CompileAdditiveLet(32) : ByteAddr');
    { Check A1 }
      Case A1.C Of
        DS,SS,ES:;
        Else
          Error('CompileAdditiveLet(32) : check A1');
      End;
    { Check A2 }
      Case A2.C Of
        Immediate,Reg32,RegMem32,MemReg32,Mem32,DS,SS,ES:;
        Else
          Error('CompileAdditiveLet(32) : check A2');
      End;
    { Init Resu }
      If A2.C=Immediate Then Resu:=A2 Else Resu.C:=Reg32;
    { Codage let loword }
      GetLow(TA1,A1);
      GetLow(TA2,A2);
      If (TA2.C<>Immediate) And (TA2.C<>Register) Then GetReg16(TA2,TA2);
      If TA2.C<>Immediate Then SetLow(Resu,TA2);
      Assemble(LoCOP,TA1,TA2);
    { Codage let hiword }
      GetHigh(TA1,A1);
      GetHigh(TA2,A2);
      If (TA2.C<>Immediate) And (TA2.C<>Register) Then GetReg16(TA2,TA2);
      If TA2.C<>Immediate Then SetHigh(Resu,TA2);
      Assemble(HiCOP,TA1,TA2);
    { Set Resu }
      FreeReg32(A1);
      SetRegContainsOn(Resu,Resu);
    End
  Else
    Error('Compile : let : bad type');
End;

Procedure CompileAddPtrLet16(OpName : Word; Var Resu,AP,I : TypedAddress);
Var
   D1,D2,D3 : TypedAddress;
   C : COP;
Begin
{ Check ç(I) }
  Case I.SType^.Nature Of
    Symbol Or PredByte    : CastIt(I,@SymbWord);
    Symbol Or PredShortInt: CastIt(I,@SymbInt);
    Symbol Or PredInt,Symbol Or PredWord:;
    Else
      Error('CompileAddPtr16 : Ptr+<Badç>');
  End;
{ Check AP }
  Case AP.C Of
  { Immediate: BGRShlu; }
    DS,SS,ES:;
    Else
      Error('CompileAddPtrLet16 : check AP');
  End;
{ Set C }
  Case OpName Of
    OpAddLet: C:=ADD;
    OpSubLet: C:=SUB;
    Else
      Error('AddrPtr16 : bad OpName');
  End;
{ Get Lo/Hi }
  GetHigh(D1,AP);
  GetLow(D2,AP);
{ ADD D2,I }
  If I.C<>Register Then LoadIt(I,I,CopyMode);
  Assemble(C,D2,I);
  FreeReg16(I);
{ MOV D3,D2 }
  GetReg16(D3,D2);
{ AND D3,&H000F }
  ImmAddr.Value:=$000F;
  Assemble(CAND,D2,ImmAddr);
{ SxR D3,4 }
  ImmAddr.Value:=$0004;
  If (C=SUB) Or (I.SType=@SymbInt) Then Assemble(SAR,D3,ImmAddr)
                                   Else Assemble(CSHR,D3,ImmAddr);
{ ADD D1,D3 }
  Assemble(ADD,D1,D3);
  FreeReg16(D3);
{ Resu=AP }
  SetRegContainsOn(Resu,AP);
End;

Procedure CompileAddPtrLet32(OpName : Word; Var Resu,A1,A2 : TypedAddress);
Begin
  Error('AddrPtrLet32 !Yet');
End;

Procedure CompileOpXLet(Var Resu : TypedAddress; B : BoxPtr);
Var
   A1,A2 : TypedAddress;
   HiCOP,LoCOP : COP;
Begin
  Case Name(B^.Nature) Of
    OpAddLet,OpSubLet,OpLogAndLet,OpLogXorLet,OpLogOrLet,OpLet,
    OpLeftShiftLet,OpRightShiftLet:
      Begin
      { Compil A2 }
        Compile(A2,B^.Droite);
        DeRefIt(A2);
      { Loader A2 si A1 n'est pas un registre
               et si A2 mobilise des registres }
        If Not IsReg(B^.Gauche^.Nature) Then
          Case A2.C Of
            Reg32: If HiWord(A2.Value)=rES Then LoadIt(A2,A2,AddrDataMode);
            DS,SS: If A2.M<>IndOfs Then LoadIt(A2,A2,CopyMode);
               ES: LoadIt(A2,A2,CopyMode);
          End
        ;
      { Compil A1 }
        Compile(A1,B^.Gauche);
        DeRefIt(A1);
      { D‚codage Shift/Others }
        Case Name(B^.Nature) Of
          OpLeftShiftLet:
            KerCompileOpShift(OpLeftShift,Resu,A1,A2)
          ;
          OpRightShiftLet:
            KerCompileOpShift(OpRightShift,Resu,A1,A2)
          ;
          OpAddLet,OpSubLet,OpLogAndLet,OpLogXorLet,OpLogOrLet,OpLet:
            Begin
            { D‚codage Add/Sub Num/Ptr }
              If IsPointer(A1.SType) And
                 ((Name(B^.Nature)=OpAddLet) Or
                  (Name(B^.Nature)=OpSubLet)
                 )
              Then
                Begin
                  Case A2.SType^.Nature Of
                    Symbol Or PredShortInt,Symbol Or PredByte,
                    Symbol Or PredInt,Symbol Or PredWord:
                      CompileAddPtrLet16(Name(B^.Nature),Resu,A1,A2)
                    ;
                    Symbol Or PredLongInt,Symbol Or PredLongWord:
                      CompileAddPtrLet32(Name(B^.Nature),Resu,A1,A2)
                    ;
                    Else
                      Error('Compile : AddLetPtr/SubLetPtr : Ptr+<Badç>');
                  End
                End
              Else
                Begin
                { Cast implicite }
                  If Not TypeEQ(@A1.SType^,@A2.SType^) Then CastIt(A2,A1.SType);
                { Codage let }
                  Case Name(B^.Nature) Of
                    OpLogAndLet: CompileAdditiveLet(Resu,A1,A2,CAND,CAND);
                    OpLogXorLet: CompileAdditiveLet(Resu,A1,A2,CXOR,CXOR);
                    OpLogOrLet:  CompileAdditiveLet(Resu,A1,A2,COR,COR);
                    OpAddLet:    CompileAdditiveLet(Resu,A1,A2,ADC,ADD);
                    OpSubLet:    CompileAdditiveLet(Resu,A1,A2,SBB,SUB);
                    OpLet:       CompileAdditiveLet(Resu,A1,A2,MOV,MOV);
                  End;
                End;
            End;
        End;
      End;
    OpMulLet,OpDivLet,OpModLet:
      Begin
      { Modify B^.Nature }
        Case Name(B^.Nature) Of
          OpMulLet: B^.Nature:=Operator Or OpMul;
          OpDivLet: B^.Nature:=Operator Or OpDiv;
          OpModLet: B^.Nature:=Operator Or OpMod;
        End;
      { Compile DirectCalc Opn }
        CompileOpBin(A2,B);
      { Compil A1 }
        Compile(A1,B^.Gauche);
        DeRefIt(A1);
      { Cast implicite }
        If Not TypeEQ(@A1.SType^,@A2.SType^) Then CastIt(A2,A1.SType);
      { Codage let }
        CompileAdditiveLet(Resu,A1,A2,MOV,MOV);
      End;
    Else
      Error('CompileOpXLet : bad opn');
  End;
End;

{ ***************
  Courts-circuits
  *************** }
Procedure CompileShortCircuit(OpName : Word; Var Resu : TypedAddress; B : BoxPtr);
Var
   A1 : TypedAddress;
   CurLabVal : Boolean;
Begin
  CurLabVal:=False;
  If CurLabel.C=Null Then
  Begin
    CurLabVal:=True;
    NewLabel(CurLabel);
    InvCondJump:=True;
  End;
  Case Name(B^.Nature) Of
    OpNot             : CompileNot(Resu,B);
    OpAnd             : CompileAnd(Resu,B);
    OpOr              : CompileOr(Resu,B);
    Else
                        CompileOpBin(Resu,B);
  End;
  If CurLabVal Then
  Begin
    GetReg16(Resu,ImmOne);
    NewLabel(A1);
    Assemble(JMP,A1,NullAddr);
    PutLabel(CurLabel);
    Assemble(CXOR,Resu,Resu);
    PutLabel(A1);
    CurLabel.C:=Null;
  End;
End;

{ ****************************************************
  La proc‚dure r‚cursive pour compiler des expressions
  **************************************************** }
Procedure Compile(Var Resu : TypedAddress; B : BoxPtr);
Begin
  If B=Nil Then Error('Compile : Nil B');
  Case Nature(B^.Nature) Of
    Symbol  : CompileAccessSymbol(Resu,B);
    Constant: CalcConst(Resu,B);
    Operator:
      Case Name(B^.Nature) Of
        OpPouvr           : CompileOpPouvr(Resu,B);
        OpCrouvr          : CompileAccessArray(Resu,B);
        OpPoint           : CompileAccessRecord(Resu,B);
        OpFleche          : CompileAccessPointer(Resu,B);
        OpAdr             : CompileOpAdr(Resu,B);
        OpNot,OpAnd,OpOr,
        OpEq,OpNeq,
        OpInf,OpInfEq,
        OpSup,OpSupEq     : CompileShortCircuit(Name(B^.Nature),Resu,B);
        OpLeftShift,
        OpRightShift      : CompileOpShift(Resu,B);
        OpLogNot,
        OpPlus,OpMoins    : CompileOpPlusMoins(Resu,B);
        OpMul,OpDiv       : CompileOpMulDiv(Resu,B);
        OpVirg            : CompileOpVirg(Resu,B);
        OpLet,
        OpLogXorLet,
        OpAddLet,OpSubLet,
        OpLogOrLet,OpLogAndLet,
        OpMulLet,OpDivLet,OpModLet,
        OpLeftShiftLet,OpRightShiftLet : CompileOpXLet(Resu,B);
        Else
                                         CompileOpBin(Resu,B);
      End;
    Else
      Error('Compile : unexpected KeyWord');
  End;
{ Reset ByteAddr }
  ByteAddr:=False;
End;

Procedure CompileExpr(Var Resu : TypedAddress; B : BoxPtr);
Begin
  SizTmp:=0;
  TopOfStack.Value:=-SizVarLoc;
  FreeAllRegs;
  Compile(Resu,B);
  TA.C:=Immediate;
  TA.Value:=SizTmp;
  If SizTmp<>0 Then Assemble(ADD,Reg[SP],TA);
End;

Begin
{ Init CalculatingType }
  CalculatingType:=False;
{ Init NoParmsDefs }
  NoParmsDefs:=True;
{ Init UTestCOP }
  UTestCOP[OpEq]:=JZ;
  UTestCOP[OpNeq]:=JNZ;
  UTestCOP[OpInf]:=JB;
  UTestCOP[OpInfEq]:=JBE;
  UTestCOP[OpSup]:=JA;
  UTestCOP[OpSupEq]:=JAE;
{ Init STestCOP }
  STestCOP[OpEq]:=JZ;
  STestCOP[OpNeq]:=JNZ;
  STestCOP[OpInf]:=JL;
  STestCOP[OpInfEq]:=JLE;
  STestCOP[OpSup]:=JG;
  STestCOP[OpSupEq]:=JGE;
{ Init InvJump }
  InvJump[JZ]:=JNZ;
  InvJump[JNZ]:=JZ;
  InvJump[JL]:=JGE;
  InvJump[JLE]:=JG;
  InvJump[JG]:=JLE;
  InvJump[JGE]:=JL;
  InvJump[JB]:=JAE;
  InvJump[JBE]:=JA;
  InvJump[JA]:=JBE;
  InvJump[JAE]:=JB;
{ Init CutJump }
  CutJump[JZ]:=JZ;
  CutJump[JNZ]:=JNZ;
  CutJump[JL]:=JL;
  CutJump[JLE]:=JL;
  CutJump[JG]:=JG;
  CutJump[JGE]:=JG;
  CutJump[JB]:=JB;
  CutJump[JBE]:=JB;
  CutJump[JA]:=JA;
  CutJump[JAE]:=JA;
End.