  (*$p**************************************************************************)
  (*                                                                           *)
  (*                          File: CODE.2.TEXT                                *)
  (*                                                                           *)
  (*              (C) Copyright 1981 Silicon Valley Software, Inc.             *)
  (*                            1983, 1984 Apple Computer, Inc.                *)
  (*                                                                           *)
  (*                            All rights reserved.               18-Jul-82   *)
  (*                                                                           *)
  (*****************************************************************************)
  {[j=0/0/80!,@=6,i=1]}
  {$S SEG1}

  FUNCTION GetBase(fLevel: Integer): Register;

    VAR
      A, A2: Register;
      i: Integer;

    BEGIN
      IF fLevel <= 1 THEN
        GetBase := A5
      ELSE IF fLevel = ProcLvl THEN
        GetBase := A6
      ELSE
        BEGIN
        A := GetReg(Alow, Ahigh);
        GenRR($206E, A, 0); { MOVE.L 8(A6),A }
        Gen(8);
        FOR i := fLevel TO ProcLvl - 2 DO
          BEGIN
          FreeReg(A); A2 := GetReg(Alow, Ahigh);
          GenRR($2068, A2, A); { MOVE.L 8(A),A2 }
          Gen(8);
          A := A2;
          END;
        GetBase := A;
        END;
    END; {getbase}

  PROCEDURE GlobRef(fLinkName, fUserName: Alfa8; fRefLoc: Integer);

    VAR
      lpRoc: pProcRef;
      lInt: pIntList;
      Done: Boolean;

    BEGIN
      lpRoc := ProcList; Done := False;
      WHILE (NOT Done) AND (lpRoc <> NIL) DO
        IF lpRoc^.LinkName = fLinkName THEN
          Done := True
        ELSE
          lpRoc := lpRoc^.Next;
      IF NOT Done THEN
        BEGIN
        New(lpRoc);
        WITH lpRoc^ DO
          BEGIN
          RefList := NIL; LinkName := fLinkName;
          UserName := fUserName; Next := ProcList;
          END;
        ProcList := lpRoc;
        END;
      New(lInt);
      WITH lInt^ DO
        BEGIN
        Int := fRefLoc; Next := lpRoc^.RefList; lpRoc^.RefList := lInt;
        END;
    END; {globref}

  PROCEDURE GenJump(fOp, fLab: Integer);

    VAR
      lInt: pIntList;
      lpLab: pLabelRec;

    BEGIN
      lpLab := LookUpILabel(fLab);
      WITH lpLab^ DO
        IF Defined THEN
          BEGIN
          GenWord(fOp, JMPL); GenWord(Loc, ABSI);
          END
        ELSE
          BEGIN
          New(lInt);
          WITH lInt^ DO
            BEGIN
            Int := Ic + 2; Next := RefList; RefList := lInt;
            END;
          GenWord(fOp, JMPL); GenWord(0, ABSI);
          END;
    END; {genjump}

  PROCEDURE GenJSR(FName: Alfa8);

    BEGIN
      GlobRef(FName, FName, Ic + 2);
      IF ShortCalls THEN
        BEGIN { JSR $+xxx }
        Gen($4EBA); Gen(0);
        END
      ELSE
        BEGIN { JSR xxx.L }
        Gen($4EB9); Gen(0); Gen(0);
        END;
    END; {genjsr}

  FUNCTION LoadInt(fHi, fLo, fSize: Integer): Register;

    VAR
      D: Register;
      Op: Integer;

    BEGIN
      D := GetReg(Dlow, Dhigh); LoadInt := D;
      IF (fLo <= 127) AND (fLo >= 0) AND (fHi = 0) THEN
        GenRR($7000 + fLo, D, 0) { MOVEQ #val,D }
      ELSE IF (fLo < 0) AND (fLo >= - 128) AND (fHi = - 1) THEN
        GenRR($7100 + fLo, D, 0) { MOVEQ #val,D }
      ELSE
        BEGIN
        IF fSize <= WordOp THEN
          Op := $303C { MOVE.W #,D }
        ELSE
          Op := $203C; { MOVE.L #,D }
        GenRR(Op, D, 0);
        IF fSize = LongOp THEN Gen(fHi);
        Gen(fLo);
        END;
    END; {loadint}

  PROCEDURE FixIndxOffset(VAR fCAttr: CAttr);

    VAR
      A: Register;

    BEGIN
      WITH fCAttr DO
        BEGIN
        IF (InOffset > 127) OR (InOffset < - 128) THEN
          BEGIN
          FreeReg(InxAReg); A := GetReg(Alow, Ahigh);
          GenRR($41E8, A, InxAReg); { LEA off(XA),A }
          Gen(InOffset);
          InOffset := 0; InxAReg := A;
          END;
        IF InOffset < 0 THEN InOffset := InOffset + 256;
        END;
    END; {fixindxoffset}

  PROCEDURE GenEffAdd(fOp: Integer; fCAttr: CAttr; fSize: Integer;
                      iMMFlag: Boolean; iMMHi, iMMLo: Integer);

    VAR
      A, Base: Register;
      D: Register;
      Op: Integer;
      lBigCRef: pBigCRef;

    PROCEDURE GenIMM;

      BEGIN
        IF iMMFlag THEN
          BEGIN
          IF fSize = LongOp THEN Gen(iMMHi);
          Gen(iMMLo);
          END;
      END; {genimm}

    BEGIN {geneffadd}
      WITH fCAttr DO
        CASE cKind OF
          EXPR: BEGIN
                IF ExReg >= A0 THEN fOp := fOp + 8;
                GenR(fOp, ExReg); FreeReg(ExReg); GenIMM;
                END;
          ADDR: BEGIN
                IF AOffset = 0 THEN
                  BEGIN
                  GenR(fOp + 16, AdReg); GenIMM;
                  END
                ELSE
                  BEGIN
                  GenR(fOp + 40, AdReg); GenIMM; Gen(AOffset);
                  END;
                FreeReg(AdReg);
                END;
          INDX: BEGIN
                FixIndxOffset(fCAttr);
                GenR(fOp + 48, InxAReg); GenIMM;
                Op := InxRReg * 4096 + InOffset;
                IF LongIndex THEN Op := Op + 2048;
                Gen(Op); FreeReg(InxAReg); FreeReg(InxRReg);
                END;
          VARB: BEGIN
                Base := GetBase(VLev); FreeReg(Base);
                GenR(fOp + 40, Base); GenIMM; Gen(VOffset);
                IF VLev < 0 THEN ComVRef( - VLev, Ic - 2);
                END;
          CNST: CASE CValu.CstKind OF                                          {!}{[@=10]}
                  SCALCNST: BEGIN
                            Gen(fOp + 60); GenIMM;
                            IF fSize = LongOp THEN Gen(CValu.IValu[0]);
                            Gen(CValu.IValu[1]);
                            END;
                  STRCNST, PAOCCNST, SETCNST:
                            BEGIN
                            Gen(fOp + 58); Gen(0);
                            New(lBigCRef);
                            WITH lBigCRef^ DO
                              BEGIN
                              Loc := Ic - 2; BigVal := CValu;
                              Next := NIL;
                              StartLoc := - 1; {literal doesn't have a home yet!}
                              Next := BigCList; BigCList := lBigCRef;
                              END;
                            END;
                END; {case}
          COND: CodError(2003);
          STCK: BEGIN
                Gen(fOp + 31); GenIMM;
                END;
          { i.e. (SP)+ not -(SP) }
          BOOL: CodError(2004);
          BITZ: CodError(2005);
        END; {case}
    END; {geneffadd}

  PROCEDURE IncOffset(VAR fCAttr: CAttr; fOffset: Integer);

    BEGIN
      IF fOffset <> 0 THEN
        WITH fCAttr DO
          CASE cKind OF
            ADDR: AOffset := AOffset + fOffset;
            INDX: InOffset := InOffset + fOffset;
            VARB: VOffset := VOffset + fOffset;
          END; {case}
    END; {IncOffset}

  PROCEDURE MakeSetConst(VAR fCAttr: CAttr);

    VAR
      lpInt: pIntList;
      lCAttr: CAttr;

    BEGIN
      lpInt := fCAttr.CValu.SetValu;
      lCAttr.cKind := CNST;
      lCAttr.CValu.CstKind := SCALCNST;
      IF lpInt <> NIL THEN
        BEGIN
        lCAttr.CValu.IValu[0] := lpInt^.Int;
        lCAttr.CValu.IValu[1] := lCAttr.CValu.IValu[0];
        lpInt := lpInt^.Next;
        END
      ELSE
        lCAttr.CValu.IValu[1] := 0;
      IF lpInt <> NIL THEN
        lCAttr.CValu.IValu[1] := lpInt^.Int
      ELSE
        lCAttr.CValu.IValu[0] := 0;
      fCAttr := lCAttr;
    END; {makesetconst}

  PROCEDURE PushAddress(fCAttr: CAttr);

    VAR
      DoIt: Boolean;

    BEGIN
      DoIt := True;
      WITH fCAttr DO
        CASE cKind OF
          ADDR: IF AOffset = 0 THEN
                  BEGIN
                  GenR($2F08, AdReg); { MOVE.L adreg,-(SP) }
                  DoIt := False; FreeReg(AdReg);
                  END;
        END; {case}
      IF DoIt THEN GenEffAddr($4840 { PEA } , fCAttr, LongOp, False, 0, 0);
    END; {pushaddress}

  {*************************************************************************

                                  ALoadAddress

          loads the address of an cattr into a particular a register.

          input parameters
                  fcattr - describes variable whose address will be loaded
                  areg - A register into which to load address

  **************************************************************************}

  PROCEDURE ALoadAddress(fCAttr: CAttr; Areg: Register);

    BEGIN
      GenEffAdd($41C0 + (Areg - 8) * 512, fCAttr, LongOp, False, 0, 0); { LEA }
    END; {ALoadAddress}

  FUNCTION LoadAddress(fCAttr: CAttr): Register;

    VAR
      A: Register;
      DoIt: Boolean;

    BEGIN
      WITH fCAttr DO
        BEGIN
        DoIt := True;
        IF cKind = ADDR THEN
          IF (AOffset <= 8) AND (AOffset >= - 8) THEN
            BEGIN
            DoIt := False; A := AdReg;
            IF AOffset <> 0 THEN
              IF AOffset > 0 THEN
                BEGIN
                CheckClobber(A);
                GenRR($5088, AOffset, A); { ADDQ.L #aoff,A }
                END
              ELSE
                BEGIN
                CheckClobber(A);
                GenRR($5188, - AOffset, A); { SUBQ.L #-aof,A }
                END;
            END;
        IF DoIt THEN
          BEGIN
          A := ReuseIfPossible(fCAttr, Alow, Ahigh);
          GenEffAdd($41C0 + (A - 8) * 512, fCAttr, LongOp, False, 0, 0); { LEA }
          END;
        END;
      LoadAddress := A;
    END; {loadaddress}

  PROCEDURE PushInt(fValue: Integer; fSize: Integer);

    VAR
      Op: Integer;

    BEGIN
      IF fValue = 0 THEN
        BEGIN
        IF fSize <= WordOp THEN
          Gen($4267) { CLR.W -(SP) }
        ELSE
          Gen($42A7); { CLR.L -(SP) }
        END
      ELSE
        BEGIN
        IF fSize = ByteOp THEN
          Gen($1F3C) { MOVE.B #xxx,-(SP) }
        ELSE IF fSize <= WordOp THEN
          Gen($3F3C) { MOVE.W #xxx,-(SP) }
        ELSE
          Gen($2F3C); { MOVE.L #xxx,-(SP) }
        IF fSize = LongOp THEN
          IF fValue < 0 THEN
            Gen( - 1)
          ELSE
            Gen(0);
        Gen(fValue);
        END;
    END; {pushint}

  PROCEDURE LoadCC(VAR fCAttr: CAttr);

    VAR
      D: Register;
      Op: Integer;

    BEGIN
      D := GetReg(Dlow, Dhigh);
      CASE fCAttr.CC OF                                                        {!}{[@=4]}
        LT: Op := 13;
        LE: Op := 15;
        GT: Op := 14;
        GE: Op := 12;
        EQ: Op := 7;
        NE: Op := 6;
        HI: Op := 2;
        LS: Op := 3;
      END; {case}
      GenR($50C0 + Op * 256, D); { SCC D }
      fCAttr.cKind := BOOL; fCAttr.ExReg := D;
    END; {LoadCC}

  (*
  PROCEDURE WriteAttr(fAttr: CAttr);

    BEGIN
      WITH fAttr DO
        CASE cKind OF
          EXPR: WriteLn('EXPR ', ExReg);
          BOOL: WriteLn('BOOL ', ExReg);
          BITZ: WriteLn('BITZ ', ExReg);
          ADDR: WriteLn('ADDR ', AdReg: 4, AOffset: 8);
          VARB: WriteLn('VARB ', VOffset: 8, VLev: 8);
          INDX: WriteLn('INDX ', InxAReg: 4, InxRReg: 4, InOffset: 8);
          CNST: WriteLn('CNST ');
          COND: WriteLn('COND ', Ord(CC): 4);
        END;
    END; { writeattr }
  *)

  PROCEDURE LoadAOrd(IntoReg: Integer; VAR fCAttr: CAttr; fSize: Integer);

    VAR
      DoIt: Boolean;
      D: Register;
      DestPart, Op: Integer;

    BEGIN
      WITH fCAttr DO
        BEGIN
        IF cKind = CNST THEN
          BEGIN
          IF CValu.CstKind = SETCNST THEN MakeSetConst(fCAttr);
          END
        ELSE
          BEGIN
          DoIt := False;
          IF cKind = COND THEN LoadCC(fCAttr);
          IF cKind = BOOL THEN
            BEGIN
            D := ExReg;
            DoIt := True;
            CheckClobber(D);
            IF fSize = ByteOp THEN
              GenR($4400, D) { NEG.B D }
            ELSE
              BEGIN
              GenR($240, D); { ANDI.W #1,D }
              Gen(1);
              END;
            END
          ELSE IF cKind = BITZ THEN
            BEGIN
            CheckClobber(D);
            D := ExReg;
            DoIt := True;
            GenR($240, D); { ANDI.W #1,D }
            Gen(1);
            END;
          IF DoIt THEN
            BEGIN
            IF fSize = LongOp THEN GenR($48C0, D); { EXT.L d }
            cKind := EXPR;
            END;
          END;
        IF cKind = EXPR THEN                                                   {!12-2-83}
          IF ExReg = IntoReg THEN Exit(LoadAOrd); {assume no cc needed!}
        CASE fSize OF                                                          {!}{[@=8]}
          ByteOp: Op := $1000;
          WordOp: Op := $3000;
          LongOp: Op := $2000;
          Quad: {CodError} ;
        END; {case}
        D := IntoReg;
        IF IntoReg <= D7 THEN
          DestPart := D * 512
        ELSE
          DestPart := (D - 8) * 512 + 64 { MOVEA } ;
        GenEffAdd(Op + DestPart, fCAttr, fSize, False, 0, 0);
        cKind := EXPR;
        ExReg := D;
        END;
    END; {loadaord}

  {**************************************************************************

                                  loadd

          loads value described by fcattr into a D register.  sometimes
          we need the condition codes to be set.  steve depended on the
          fact that he always used a register immediately after the value
          was computed into it.  this doesn't work for variables whose life
          in a register is longer.

          Input Parameters

          fcattr - describes value to be loaded
          fsize - size of value needed
          setcc - CC need to be set


          Output Parameters

          fcattr - modified to reflect new location of value
          return result - register loaded

  *************************************************************************}

  FUNCTION LoadD(VAR fCAttr: CAttr; fSize: Integer; SetCC: Boolean): Register;

    VAR
      DoIt: Boolean;
      D: Register;
      Op: Integer;

    BEGIN
      DoIt := True;
      WITH fCAttr DO
        BEGIN
        IF cKind = EXPR THEN
          BEGIN
          IF ((ExReg <= Dhigh) OR NOT SetCC) AND (ExReg <= D7) THEN
            BEGIN
            D := ExReg;
            DoIt := False;
            END;
          END
        ELSE IF cKind = CNST THEN
          BEGIN
          IF CValu.CstKind = SETCNST THEN MakeSetConst(fCAttr);
          D := LoadInt(CValu.IValu[0], CValu.IValu[1], fSize);
          DoIt := False;
          END
        ELSE
          BEGIN
          IF cKind = COND THEN LoadCC(fCAttr);
          IF cKind = BOOL THEN
            BEGIN
            D := ExReg;
            DoIt := False;
            CheckClobber(D);
            IF fSize = ByteOp THEN
              GenR($4400, D) { NEG.B D }
            ELSE
              BEGIN
              GenR($240, D); { ANDI.W #1,D }
              Gen(1);
              END;
            END
          ELSE IF cKind = BITZ THEN
            BEGIN
            CheckClobber(D);
            D := ExReg;
            DoIt := False;
            GenR($240, D); { ANDI.W #1,D }
            Gen(1);
            END;
          IF NOT DoIt THEN IF fSize = LongOp THEN GenR($48C0, D); { EXT.L d }
          END;
        IF DoIt THEN
          BEGIN
          CASE fSize OF
            ByteOp: Op := $1000;
            WordOp: Op := $3000;
            LongOp: Op := $2000;
            Quad: {CodError} ;
          END; {case}
          D := GetReg(Dlow, Dhigh);
          GenEffAdd(Op + D * 512, fCAttr, fSize, False, 0, 0);
          END;
        cKind := EXPR; ExReg := D; LoadD := D;
        END;
    END; {loadd}
                                                                               {!12-1-83}

  FUNCTION LoaddWithPrefReg(PrefReg: Register; VAR fCAttr: CAttr;
                            fSize: Integer): Register;

    VAR
      D: Register;

    BEGIN
      IF PrefReg <> - 1 THEN
        BEGIN
        LoadAOrd(PrefReg, fCAttr, fSize);
        D := fCAttr.ExReg;
        END
      ELSE
        D := LoadD(fCAttr, fSize, False);
      IF D <> PrefReg THEN
        BEGIN
        CheckClobber(D);
        fCAttr.ExReg := D;
        END;
      LoaddWithPrefReg := D;
    END; {LoaddWithPrefReg}

  FUNCTION IsQuickCnst(VAR CValu: Valu): Boolean;

    BEGIN
      WITH CValu DO
        IsQuickCnst := ((IValu[1] <= 127) AND (IValu[1] > 0) AND (IValu[0] =
                       0)) OR ((IValu[1] < 0) AND (IValu[1] >= - 128) AND
                       (IValu[0] = - 1));
    END; {isQuickCnst}

  PROCEDURE PushValue(fCAttr: CAttr; fSize: Integer);

    VAR
      QuickCnst, DoIt: Boolean;
      Op: Integer;
      CnstD, D: Register;
      A: Register;

    BEGIN
      IF fCAttr.cKind <> STCK THEN
        IF fSize < Quad THEN
          BEGIN
          DoIt := True;
          WITH fCAttr DO
            IF cKind = CNST THEN
              BEGIN
              QuickCnst := IsQuickCnst(CValu);
              IF (fSize = LongOp) AND QuickCnst THEN
                BEGIN
                CnstD := LoadInt(CValu.IValu[0], CValu.IValu[1], fSize);
                fCAttr.cKind := EXPR;
                fCAttr.ExReg := CnstD;
                PushValue(fCAttr, LongOp);
                DoIt := False;
                END
              ELSE
                BEGIN
                IF CValu.CstKind = SCALCNST THEN
                  IF (CValu.IValu[0] = 0) AND (CValu.IValu[1] = 0) THEN
                    BEGIN
                    PushInt(0, fSize);
                    DoIt := False;
                    END;
                END
              END
            ELSE IF (cKind = BOOL) OR (cKind = COND) OR (cKind = BITZ) THEN
              D := LoadD(fCAttr, fSize, False);
          IF DoIt THEN
            BEGIN
            IF fSize = ByteOp THEN
              Op := $1F00 { MOVE.B ?,-(SP) }
            ELSE IF fSize <= WordOp THEN
              Op := $3F00 { MOVE.W ?,-(SP) }
            ELSE
              Op := $2F00; { MOVE.L ?,-(SP) }
            GenEffAdd(Op, fCAttr, fSize, False, 0, 0);
            END;
          END
        ELSE { QUAD }
          BEGIN
          IncOffset(fCAttr, 8);
          A := LoadAddress(fCAttr);
          CheckClobber(A);
          GenR($2F20, A); { MOVE.L -(A),-(SP) }
          GenR($2F20, A); { MOVE.L -(A),-(SP) }
          FreeReg(A);
          END;
    END; {pushvalue}

  PROCEDURE Store(From_CAttr, To_CAttr: CAttr; fSize: Integer);

    VAR
      Op, InstSize, DestMode, DestReg, CnstD, i, DstComLev, CommonLev: Integer;
      FreeXreg, QuickCnst, MoveQuick, DstComFlag, CommonFlag, ClearFlag: Boolean;
      D: Register;
      Base: Register;
      Inst: ARRAY [1..3] OF Integer;

    BEGIN
      CASE fSize OF
        ByteOp: Op := $1000; { MOVE.B }
        WordOp: Op := $3000; { MOVE.W }
        LongOp: Op := $2000; { MOVE.L }
        Quad: { CodError }
      END; {case}
      InstSize := 0; FreeXreg := False; QuickCnst := False; MoveQuick := False;
      ClearFlag := False; DstComFlag := False; CommonFlag := False;
      WITH From_CAttr DO
        CASE cKind OF                                                          {!}{[@=6]}
          EXPR: Op := Op + ExReg;
          ADDR: IF AOffset = 0 THEN
                  Op := Op + 8 + AdReg
                ELSE
                  BEGIN
                  Op := Op + 32 + AdReg; InstSize := 1;
                  Inst[1] := AOffset;
                  END;
          CNST: IF (CValu.IValu[0] = 0) AND (CValu.IValu[1] = 0) THEN
                  BEGIN
                  ClearFlag := True;
                  CASE fSize OF                                                {!}{[@=8]}
                    ByteOp: Op := $4200; { CLR.B }
                    WordOp: Op := $4240; { CLR.W }
                    LongOp: Op := $4280; { CLR.L }
                    Quad: { CodError } ;
                  END; {case}
                  END
                ELSE
                  BEGIN
                  QuickCnst := IsQuickCnst(CValu);
                  Op := Op + 60;
                  IF fSize <= 2 THEN
                    BEGIN
                    Inst[1] := CValu.IValu[1];
                    InstSize := 1;
                    END
                  ELSE
                    BEGIN
                    Inst[1] := CValu.IValu[0];
                    Inst[2] := CValu.IValu[1];
                    InstSize := 2;
                    END;
                  END;
          INDX: BEGIN
                FixIndxOffset(From_CAttr);
                Op := Op + 40 + InxAReg;
                InstSize := 1;
                Inst[1] := InxRReg * 4096 + InOffset;
                IF LongIndex THEN Inst[1] := Inst[1] + 2048;
                END;
          VARB: BEGIN
                Base := GetBase(VLev); Op := Op + 32 + Base;
                IF VLev < 0 THEN
                  BEGIN
                  CommonFlag := True; CommonLev := - VLev;
                  END;
                InstSize := 1; Inst[1] := VOffset;
                cKind := ADDR; AdReg := Base; { So will free base }
                END;
          BOOL, COND, BITZ:
                BEGIN
                D := LoadD(From_CAttr, fSize, False); Op := Op + D;
                cKind := EXPR; ExReg := D; { So will free d }
                END;
          STCK: Op := Op + 31;
        END; {case}
      WITH To_CAttr DO
        CASE cKind OF
          EXPR: BEGIN
                IF ExReg <= D7 THEN
                  BEGIN
                  DestMode := 0 { D direct } ;
                  DestReg := ExReg;
                  MoveQuick := QuickCnst;
                  END
                ELSE
                  BEGIN
                  DestMode := 1 { A direct } ;
                  DestReg := ExReg - 8;
                  END;
                FreeReg(ExReg);
                END;
          ADDR: BEGIN
                IF AOffset = 0 THEN
                  DestMode := 2
                ELSE
                  BEGIN
                  DestMode := 5; InstSize := InstSize + 1;
                  Inst[InstSize] := AOffset;
                  END;
                DestReg := AdReg - 8; FreeReg(AdReg);
                END;
          INDX: BEGIN
                FixIndxOffset(To_CAttr); DestMode := 6; DestReg := InxAReg - 8;
                InstSize := InstSize + 1;
                Inst[InstSize] := InOffset + InxRReg * 4096;
                IF LongIndex THEN Inst[InstSize] := Inst[InstSize] + 2048;
                FreeXreg := True; FreeReg(InxAReg);
                END;
          VARB: BEGIN
                Base := GetBase(VLev); FreeReg(Base);
                IF VLev < 0 THEN
                  BEGIN
                  DstComFlag := True; DstComLev := - VLev;
                  END;
                DestMode := 5; DestReg := Base - 8; InstSize := InstSize + 1;
                Inst[InstSize] := VOffset;
                END;
          STCK: BEGIN
                DestMode := 4; DestReg := 7;
                END;
        END; {case}
      IF CommonFlag THEN ComVRef(CommonLev, Ic + 2);
      IF MoveQuick THEN
        BEGIN
        WITH From_CAttr.CValu DO
        { MOVEQ #val,D }
          IF IValu[0] = 0 THEN
            GenRR($7000 + IValu[1], DestReg, 0)
          ELSE
            GenRR($7100 + IValu[1], DestReg, 0);
        END
      ELSE
        BEGIN
        IF (fSize = LongOp) AND QuickCnst THEN
          BEGIN
          IF DstComFlag THEN ComVRef(DstComLev, Ic + InstSize * 2 - 2);
          WITH From_CAttr.CValu DO CnstD := LoadInt(IValu[0], IValu[1], fSize);
          GenRR($2000 + CnstD + DestMode * 64, DestReg, 0); { MOVE.L D,<ea> }
          FOR i := 3 TO InstSize DO Gen(Inst[i]);
          FreeReg(CnstD);
          END
        ELSE
          BEGIN
          IF DstComFlag THEN ComVRef(DstComLev, Ic + InstSize * 2);
          IF ClearFlag THEN
            BEGIN
            IF DestMode = 1 { Ai } THEN
              GenRR($91C8, DestReg, DestReg) { SUBA.L Ai,Ai }
            ELSE
              GenR(Op + DestMode * 8, DestReg);
            END
          ELSE
            GenRR(Op + DestMode * 64, DestReg, 0);
          FOR i := 1 TO InstSize DO Gen(Inst[i]);
          END;
        END;
      WITH From_CAttr DO
        CASE cKind OF
          EXPR: FreeReg(ExReg);
          ADDR: FreeReg(AdReg);
          INDX: BEGIN
                FreeReg(InxAReg); FreeReg(InxRReg);
                END;
        END; {case}
      WITH To_CAttr DO IF FreeXreg THEN FreeReg(InxRReg);
    END; {store}

  FUNCTION GenCompare(aCAttr, bCAttr: CAttr; fSize: Integer): Boolean;

    VAR
      IsNotA, iMMFlag, FreeExtra, FreeFlag: Boolean;
      lCAttr: CAttr;
      D, DExtra: Register;
      iMMValLo, iMMValHi, lOp: Integer;

    PROCEDURE DoCMPA(ANAttr: CAttr);

      BEGIN
        FreeFlag := True;
        D := ANAttr.ExReg;
        IsNotA := False;
        IF fSize = WordOp THEN
          lOp := $B0C0
        ELSE
          lOp := $B1C0;
        lOp := lOp + (D - 8) * 512; { CMPA.? <ea>,A }
      END;

    PROCEDURE DoMOVEAD(ANAttr: CAttr);

      BEGIN
        FreeFlag := True;
        FreeExtra := True;
        D := ANAttr.ExReg;
        DExtra := GetReg(Dlow, Dhigh);
        IsNotA := False;
        IF fSize = WordOp THEN
          lOp := $3000
        ELSE
          lOp := $2000;
        lOp := lOp + DExtra * 512; { MOVE.? A,D }
      END;

    BEGIN
      FreeExtra := False; IsNotA := True;
      GenCompare := False; iMMFlag := False; FreeFlag := False;
      IF aCAttr.cKind = COND THEN D := LoadD(aCAttr, fSize, False);
      IF bCAttr.cKind = COND THEN D := LoadD(bCAttr, fSize, False);
      IF (aCAttr.cKind = BOOL) OR (aCAttr.cKind = BITZ) THEN
        D := LoadD(aCAttr, fSize, False);
      IF (bCAttr.cKind = BOOL) OR (bCAttr.cKind = BITZ) THEN
        D := LoadD(bCAttr, fSize, False);
      IF aCAttr.cKind = CNST THEN
        BEGIN
        lCAttr := bCAttr; GenCompare := True;
        IF lCAttr.cKind = CNST THEN D := LoadD(lCAttr, fSize, False);
        IF (aCAttr.CValu.IValu[0] = 0) AND (aCAttr.CValu.IValu[1] = 0) THEN
          BEGIN
          IF (lCAttr.cKind = EXPR) AND (lCAttr.ExReg >= A0) THEN
            DoMOVEAD(lCAttr)
          ELSE
            lOp := $4A00 { TST }
          END
        ELSE
          BEGIN
          IF (lCAttr.cKind = EXPR) AND (lCAttr.ExReg >= A0) THEN
            BEGIN
            DoCMPA(lCAttr);
            lCAttr := aCAttr;
            END
          ELSE
            BEGIN
            lOp := $C00; { CMPI }
            iMMFlag := True;
            iMMValHi := aCAttr.CValu.IValu[0];
            iMMValLo := aCAttr.CValu.IValu[1];
            END;
          END
        END
      ELSE IF bCAttr.cKind = CNST THEN
        BEGIN
        lCAttr := aCAttr;
        IF (bCAttr.CValu.IValu[0] = 0) AND (bCAttr.CValu.IValu[1] = 0) THEN
          BEGIN
          IF (lCAttr.cKind = EXPR) AND (lCAttr.ExReg >= A0) THEN
            DoMOVEAD(lCAttr)
          ELSE
            lOp := $4A00 { TST }
          END
        ELSE
          BEGIN
          IF (lCAttr.cKind = EXPR) AND (lCAttr.ExReg >= A0) THEN
            BEGIN
            DoCMPA(lCAttr);
            lCAttr := bCAttr;
            END
          ELSE
            BEGIN
            lOp := $C00; { CMPI }
            iMMFlag := True;
            iMMValHi := bCAttr.CValu.IValu[0];
            iMMValLo := bCAttr.CValu.IValu[1];
            END;
          END
        END
      ELSE
        BEGIN
        IF (bCAttr.cKind = STCK) AND (aCAttr.cKind = STCK) THEN
          D := LoadD(bCAttr, fSize, False);
        IF bCAttr.cKind = EXPR THEN
          BEGIN
          lCAttr := aCAttr; GenCompare := True;
          IF (bCAttr.cKind = EXPR) AND (bCAttr.ExReg >= A0) THEN
            DoCMPA(bCAttr)
          ELSE
            D := LoadD(bCAttr, fSize, False);
          END
        ELSE
          BEGIN
          IF (aCAttr.cKind = EXPR) AND (aCAttr.ExReg >= A0) THEN
            DoCMPA(aCAttr)
          ELSE
            D := LoadD(aCAttr, fSize, False);
          lCAttr := bCAttr;
          END;
        IF IsNotA THEN lOp := - 20480 { B000 } + D * 512; { CMP.? <ea>,D }
        FreeFlag := True;
        END;
      IF IsNotA THEN
        BEGIN
        IF fSize = WordOp THEN
          lOp := lOp + 64
        ELSE IF fSize = LongOp THEN lOp := lOp + 128;
        END;
      GenEffAddr(lOp, lCAttr, fSize, iMMFlag, iMMValHi, iMMValLo);
      IF FreeFlag THEN FreeReg(D);
      IF FreeExtra THEN FreeReg(DExtra);
    END; {GenCompare}

  PROCEDURE GenCall;
    FORWARD;

  PROCEDURE Expression(fOp: Integer; PrefReg: Integer; TrapV: Boolean);
    FORWARD;

  PROCEDURE PushSet(fCAttr: CAttr; fBytes: Integer; PushSize: Boolean);

    VAR
      A: Register;
      D: Register;
      lOp, lWords, lSize: Integer;

    BEGIN
      IF fBytes <= 4 THEN
        BEGIN
        IF fCAttr.cKind = CNST THEN
          fCAttr.CValu.FrontAddress := True
        ELSE IF fBytes = 1 THEN
          BEGIN
          D := GetReg(Dlow, Dhigh);
          GenR($4240, D); {CLR.W D}
          GenEffAddr($1000 + D * 512, fCAttr, ByteOp, False, 0, 0); {MOVE.B ?,D}
          fCAttr.cKind := EXPR; fCAttr.ExReg := D;
          END;
        IF fBytes <= 2 THEN
          BEGIN { MOVE.W ?,-(SP) }
          lOp := $3F00; lSize := WordOp;
          END
        ELSE
          BEGIN { MOVE.L ?,-(SP) }
          lOp := $2F00; lSize := LongOp;
          END;
        GenEffAddr(lOp, fCAttr, lSize, False, 0, 0);
        END
      ELSE
        BEGIN
        IF fCAttr.cKind <> CNST THEN IncOffset(fCAttr, fBytes);
        A := LoadAddress(fCAttr); D := LoadInt(0, fBytes DIV 2, WordOp);
        CheckClobber(A);
        GenR($3F20, A); { MOVE.W -(A),-(SP) }
        GenR($5340, D); { SUBQ.W #1,D }
        Gen($6EFA); { BGT.S $-6 }
        FreeReg(A); FreeReg(D);
        END;
      IF Odd(fBytes) THEN fBytes := fBytes + 1;
      IF PushSize THEN PushInt(fBytes, WordOp);
    END; {pushset}

  PROCEDURE SetExpression(fOp: Integer; VAR FOnStack: Boolean);

    VAR
      SetSize, i, lOp, lSize, lOpSize, FinalSize, InitSize: Integer;
      D: Register;
      lInt, NewInt: pIntList;
      lCAttr: CAttr;
      LeftStack, RightStack: Boolean;
      InitWords, FinalWords: Integer;

    BEGIN
      FOnStack := False;
      CASE fOp OF                                                              {!}{[@=5]}
        001, { GLOBAL }
        002, { LOCAL }
        003, { INTER }
        004, { COMMON }
        005, { REGISTER }
        012, { UPARROW }
        015, { FIELD }
        016, { INDX1 }
        017, { INDX2 }
        018, { INDX4 }
        019, { INDX8 }
        020, { INDXBIG }
        021, { INDXPCK }
        022, { ADDRESS }
        043: { WITHREC }
             Expression(fOp, - 1, False);
        030: { SETCNST }
             BEGIN
             SetSize := NextByte; lInt := NIL;
             FOR i := 1 TO SetSize DO
               BEGIN
               IF Odd(i) THEN
                 BEGIN
                 New(NewInt); NewInt^.Int := NextByte;
                 NewInt^.Next := lInt; lInt := NewInt;
                 END
               ELSE
                 lInt^.Int := lInt^.Int + NextByte * 256;
               END;
             WITH gCAttr DO
               BEGIN
               cKind := CNST; CValu.CstKind := SETCNST;
               CValu.SetBytes := SetSize; CValu.SetValu := lInt;
               CValu.FrontAddress := False;
               END;
             END;
        031: { NULLSET }
             WITH gCAttr DO
               BEGIN
               cKind := CNST; CValu.CstKind := SETCNST;
               New(lInt); lInt^.Next := NIL; lInt^.Int := 0;
               CValu.SetBytes := 1; CValu.SetValu := lInt;
               CValu.FrontAddress := False;
               END;
        160, { UNION }
        161, { DIFF }
        162: { INTER }
             BEGIN
             SetSize := NextByte; SetExpression(NextByte, LeftStack);
             lCAttr := gCAttr; SetExpression(NextByte, RightStack);
             FOnStack := LeftStack OR RightStack OR (SetSize > 4);
             IF FOnStack THEN
               BEGIN
               IF NOT LeftStack THEN PushSet(lCAttr, SetSize, True);
               IF NOT RightStack THEN PushSet(gCAttr, SetSize, True);
               CASE fOp OF
                 160: GenJSR('%_UNION ');
                 161: IF RightStack AND NOT LeftStack THEN
                        GenJSR('%_RDIFF ')
                      ELSE
                        GenJSR('%_DIFF  ');
                 162: GenJSR('%_INTER ');
               END; {case}
               END
             ELSE
               BEGIN
               IF fOp = 160 THEN
                 lOp := - 32767 - 1 { OR }
               ELSE
                 lOp := $C000; { AND }
               IF SetSize = 1 THEN
                 BEGIN
                 lOpSize := 0; lSize := ByteOp;
                 END
               ELSE IF SetSize = 2 THEN
                 BEGIN
                 lOpSize := 64; lSize := WordOp;
                 END
               ELSE
                 BEGIN
                 lOpSize := 128; lSize := LongOp;
                 END;
               lOp := lOp + lOpSize;
               IF fOp = 161 THEN
                 BEGIN
                 D := LoadD(gCAttr, lSize, False);
                 CheckClobber(D);
                 gCAttr.ExReg := D;
                 { NOT d }
                 GenR($4600 + lOpSize, D);
                 END;
               IF lCAttr.cKind = EXPR THEN
                 BEGIN
                 D := lCAttr.ExReg; lCAttr := gCAttr;
                 END
               ELSE
                 D := LoadD(gCAttr, lSize, False);
               IF lCAttr.cKind = CNST THEN
                 BEGIN
                 lInt := lCAttr.CValu.SetValu;
                 lCAttr.CValu.CstKind := SCALCNST;
                 IF lInt <> NIL THEN
                   BEGIN
                   lCAttr.CValu.IValu[1] := lInt^.Int;
                   lCAttr.CValu.IValu[0] := lCAttr.CValu.IValu[1];
                   lInt := lInt^.Next;
                   END
                 ELSE
                   lCAttr.CValu.IValu[1] := 0;
                 IF lInt <> NIL THEN
                   lCAttr.CValu.IValu[1] := lInt^.Int
                 ELSE
                   lCAttr.CValu.IValu[0] := 0;
                 END;
               CheckClobber(D);
               GenEffAddr(lOp + D * 512, lCAttr, lSize, False, 0, 0);
               gCAttr.cKind := EXPR; gCAttr.ExReg := D;
               END;
             END;
        168: { SINGSET }
             BEGIN
             SetSize := NextByte; Expression(NextByte, - 1, False);
             PushValue(gCAttr, WordOp);
             GenJSR('%_SING  '); FOnStack := True;
             END;
        169: { SETRANGE }
             BEGIN
             SetSize := NextByte; Expression(NextByte, - 1, False);
             PushValue(gCAttr, WordOp);
             Expression(NextByte, - 1, False); PushValue(gCAttr, WordOp);
             GenJSR('%_RANGE '); FOnStack := True;
             END;
        170: { ADJSET }
             BEGIN
             { n --> 0    Push set }
             { 0 --> n    Adjust set that is already on the stack }
             { n --> m    Adjust set that may be on the stack }
             FinalSize := NextByte; InitSize := NextByte;
             IF FinalSize = 1 THEN FinalSize := 2;
             SetExpression(NextByte, FOnStack);
             IF (gCAttr.cKind = CNST) AND NOT FOnStack AND (FinalSize <> 0) THEN
               BEGIN
               InitWords := (InitSize + 1) DIV 2;
               FinalWords := (FinalSize + 1) DIV 2;
               IF InitWords > FinalWords THEN
                 FOR i := FinalWords + 1 TO InitWords DO
                   gCAttr.CValu.SetValu := gCAttr.CValu.SetValu^.Next
               ELSE
                 FOR i := InitWords + 1 TO FinalWords DO
                   BEGIN
                   New(lInt); lInt^.Int := 0;
                   lInt^.Next := gCAttr.CValu.SetValu;
                   gCAttr.CValu.SetValu := lInt;
                   END;
               gCAttr.CValu.SetBytes := FinalSize;
               END
             ELSE
               BEGIN
               IF NOT FOnStack THEN PushSet(gCAttr, InitSize, True);
               IF FinalSize <> 0 THEN
                 BEGIN
                 PushInt(FinalSize, WordOp); GenJSR('%_ADJ   ');
                 PushInt(FinalSize, WordOp);
                 { Need a different %_ADJ that doesn't pop size }
                 END;
               FOnStack := True;
               END;
             END;
      END; {case}
    END; {setexpression}

