Metropoli BBS
VIEWER: pass_1.pas MODE: TEXT (CP437)
{****************************************************************************

                      Copyright (c) 1996 by Florian Klämpfl

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

unit pass_1;

  interface

     uses
        objects,cobjects,systems,globals,tree,asmgen,symtable,tempad,
        types,strings,i386,hcodegen;

    function do_firstpass(var p : ptree) : boolean;

  implementation

    procedure error(const t : errorconst);

      begin
         if not(codegenerror) then
           globals.error(t);
         codegenerror:=true;
      end;

    procedure firstpass(var p : ptree);forward;

    { markiert einen l-value als nicht in ein Register kopierbar }
    procedure make_not_regable(p : ptree);

      begin
         case p^.treetype of
            typeconvn : make_not_regable(p^.left);
            loadn : if p^.symtableentry^.typ=varsym then
                      pvarsym(p^.symtableentry)^.regable:=false;
         end;
      end;

    { berechnet für einen binären Operator die benötigten }
    { Register                                            }

    procedure calcregisters(p : ptree;r32,fpu : word);

      begin
         p^.registers32:=p^.left^.registers32;
         if p^.right^.registers32>p^.registers32 then
           p^.registers32:=p^.right^.registers32;

         p^.registersfpu:=p^.left^.registersfpu;
         if p^.right^.registersfpu>p^.registersfpu then
           p^.registersfpu:=p^.right^.registersfpu;

         { Nur wenn links und rechts ein Unterschied < benötige Anzahl ist, }
         { wird ein zusätzliches Register benötigt, da es dann keinen       }
         { schwierigeren Ast gibt, welcher erst ausgewertet werden kann     }

         if (abs(p^.left^.registers32-p^.right^.registers32)<r32) then inc(p^.registers32,r32);
         if (abs(p^.left^.registersfpu-p^.right^.registersfpu)<fpu) then inc(p^.registersfpu,fpu);

         { Fehlermeldung wenn mehr als 8 FPU-Register benötigt werden }
         if p^.registersfpu>8 then error(too_complex_expr);
      end;

    function both_rm(p : ptree) : boolean;

      begin
         if ((p^.left^.location.loc=LOC_MEM) or
           (p^.left^.location.loc=LOC_REFERENZ))
           and ((p^.right^.location.loc=LOC_MEM) or
           (p^.right^.location.loc=LOC_REFERENZ)) then
           both_rm:=true else both_rm:=false;
      end;

    function isconvertable(def_from,def_to : pdef;var doconv : tconverttype;fromtreetype : ttreetyp) : boolean;

      { from_is_cstring muß true sein, wenn def_from die Definition einer }
      { Stringkonstanten ist, nötig wegen der Konvertierung von String-   }
      { konstante zu nullterminiertem String                              }

      { Hilfsliste: u8bit,s32bit,s64real,uvoid,
                    bool8bit,uchar,s8bit,s16bit,u16bit }

      const
         grunddefconverts : array[u8bit..u16bit,u8bit..u16bit] of tconverttype =
         ((tc_equal,tc_u8bit_2_s32bit,tc_int_2_real,tc_not_possible,
           tc_not_possible,tc_not_possible,tc_equal,tc_u8bit_2_s16bit,tc_u8bit_2_u16bit),

          (tc_s32bit_2_u8bit,tc_equal,tc_int_2_real,tc_not_possible,
           tc_not_possible,tc_not_possible,tc_s32bit_2_s8bit,tc_s32bit_2_s16bit,tc_s32bit_2_u16bit),

          (tc_not_possible,tc_not_possible,tc_equal,tc_not_possible,
           tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible),

          (tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible,
           tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible),

          (tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible,
           tc_equal,tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible),

          (tc_not_possible,tc_not_possible,tc_not_possible,tc_not_possible,
           tc_not_possible,tc_equal,tc_not_possible,tc_not_possible,tc_not_possible),

          (tc_equal,tc_s8bit_2_s32bit,tc_int_2_real,tc_not_possible,
           tc_not_possible,tc_not_possible,tc_equal,tc_s8bit_2_s16bit,tc_s8bit_2_u16bit),

          (tc_s16bit_2_u8bit,tc_s16bit_2_s32bit,tc_int_2_real,tc_not_possible,
           tc_not_possible,tc_not_possible,tc_s16bit_2_s8bit,tc_equal,tc_equal),

          (tc_u16bit_2_u8bit,tc_u16bit_2_s32bit,tc_int_2_real,tc_not_possible,
           tc_not_possible,tc_not_possible,tc_u16bit_2_s8bit,tc_equal,tc_equal));

      var
         b : boolean;

      begin
         b:=false;
         if (def_from^.deftype=grunddef) and (def_to^.deftype=grunddef) then
           begin
              doconv:=grunddefconverts[pgrunddef(def_from)^.typ,pgrunddef(def_to)^.typ];
              if doconv<>tc_not_possible then
                b:=true;
           end
         else if (def_from^.deftype=pointerdef) and (def_to^.deftype=arraydef) and
            (parraydef(def_to)^.lowrange=0) and
            is_equal(ppointerdef(def_from)^.definition,
              parraydef(def_to)^.definition) then
           begin
              doconv:=tc_pointer_to_array;
              b:=true;
           end
         else if (def_from^.deftype=arraydef) and (def_to^.deftype=pointerdef) and
            (parraydef(def_from)^.lowrange=0) and
            is_equal(parraydef(def_from)^.definition,
              ppointerdef(def_to)^.definition) then
           begin
              doconv:=tc_array_to_pointer;
              b:=true;
           end
         { Kindklassenzeiger kann an Elternklassenzeigertyp zugewiesen werden }
         else if (def_from^.deftype=pointerdef) and (def_to^.deftype=pointerdef) and
            (ppointerdef(def_from)^.definition^.deftype=classdef) and
            (ppointerdef(def_to)^.definition^.deftype=classdef) and
            pclassdef(ppointerdef(def_from)^.definition)^.isrelated(
              pclassdef(ppointerdef(def_to)^.definition)) then
           begin
              doconv:=tc_equal;
              b:=true;
           end
         { Prozedurvariable kann an void-Pointer zugewiesen werden }
         else if (def_from^.deftype=procvardef) and
                 (def_to^.deftype=pointerdef) and
                 (ppointerdef(def_to)^.definition^.deftype=grunddef) and
                 (pgrunddef(ppointerdef(def_to)^.definition)^.typ=uvoid) then
           begin
              doconv:=tc_equal;
              b:=true;
           end
         else
           if (def_from^.deftype=stringdef) and (def_to^.deftype=stringdef) then
             begin
                doconv:=tc_string_to_string;
                b:=true;
             end
         else
           { Char nach String: }
           if (def_from^.deftype=grunddef) and
              (pgrunddef(def_from)^.typ=uchar) and
              (def_to^.deftype=stringdef) then
             begin
                doconv:=tc_char_to_string;
                b:=true;
             end
         else
           { Stringkonstante zu nullterm. Stringkonstante }
           if (fromtreetype=stringconstn) and
                (
                  (def_to^.deftype=pointerdef) and
                  (ppointerdef(def_to)^.definition^.deftype=grunddef) and
                  (pgrunddef(ppointerdef(def_to)^.definition)^.typ=uchar)
                )
             then
             begin
                doconv:=tc_cstring_charpointer;
                b:=true;
             end
         else
           if (fromtreetype=stringconstn) and
                (
                  (def_to^.deftype=arraydef) and (parraydef(def_to)^.lowrange=0) and
                  (parraydef(def_to)^.definition^.deftype=grunddef) and
                  (pgrunddef(parraydef(def_to)^.definition)^.typ=uchar)
                )
             then
             begin
                doconv:=tc_cstring_chararray;
                b:=true;
             end
         else
           if (fromtreetype=ordconstn) and (def_from^.deftype=grunddef) and
              (pgrunddef(def_from)^.typ=uchar) and
                (
                  (def_to^.deftype=arraydef) and (parraydef(def_to)^.lowrange=0) and
                  (parraydef(def_to)^.definition^.deftype=grunddef) and
                  (pgrunddef(parraydef(def_to)^.definition)^.typ=uchar)
                )
             then
             begin
                doconv:=tc_cchar_chararray;
                b:=true;
             end;
         isconvertable:=b;
      end;

    procedure firsterror(var p : ptree);far;

      begin
         p^.error:=true;
         codegenerror:=true;
      end;

    procedure firstload(var p : ptree);far;

      begin
         p^.location.loc:=LOC_REFERENZ;
         p^.registers32:=0;
         p^.registersfpu:=0;
         clear_referenz(p^.location.referenz);
         case p^.symtableentry^.typ of
            varsym :
                begin
                   p^.resulttype:=pvarsym(p^.symtableentry)^.definition;
                   if ((p^.symtable^.symtabletype and $c000)<>0) and
                      (lexlevel>(p^.symtable^.symtabletype and $3fff)) then
                     begin
                        { sollte sich die Variable in einem anderen Stackframe       }
                        { befinden, so brauchen wir ein Register zum Dereferenzieren }
                        if (p^.symtable^.symtabletype and $3fff)<>0 then
                          begin
                             p^.registers32:=1;
                             { außerdem kann sie nicht mehr in ein Register
                               geladen werden }
                             pvarsym(p^.symtableentry)^.regable:=false;
                          end;
                     end;
                   if (pvarsym(p^.symtableentry)^.varspez=vs_const) then
                     p^.location.loc:=LOC_MEM;
                   { Bei einem Call by Referenz brauchen wir ein Register }
                   if (pvarsym(p^.symtableentry)^.varspez=vs_var) or
                      ((pvarsym(p^.symtableentry)^.varspez=vs_const) and
                       (
                         (pvarsym(p^.symtableentry)^.definition^.deftype=stringdef) or
                         (pvarsym(p^.symtableentry)^.definition^.deftype=arraydef) or
                         (pvarsym(p^.symtableentry)^.definition^.deftype=recorddef) or
                         (pvarsym(p^.symtableentry)^.definition^.deftype=classdef) or
                         (pvarsym(p^.symtableentry)^.definition^.deftype=setdef)
                       )
                      ) then
                     p^.registers32:=1;
                   if p^.symtable^.symtabletype=withsymtable then
                     p^.registers32:=1;

                   { Referenzen für eine Variable zählen }
                   if t_times<1 then
                    inc(pvarsym(p^.symtableentry)^.refs)
                   else
                    inc(pvarsym(p^.symtableentry)^.refs,t_times);
                end;
            typedconstsym :
                p^.resulttype:=ptypedconstsym(p^.symtableentry)^.definition;
            procsym :
                begin
                   if assigned(pprocsym(p^.symtableentry)^.definition^.nextoverloaded) then
                     error(no_overloaded_procvars);
                   p^.resulttype:=pprocsym(p^.symtableentry)^.definition;
                end;
            else internalerror(3);
         end;
      end;

    { müßten eigentlich lokal sein, belasten aber den Stack zu stark }
    var
       s1,s2 : string;

    procedure firstadd(var p : ptree);far;

      var
         lt,rt : ttreetyp;
         t : ptree;
         rv,lv : longint;
         rvd,lvd : double;
         rd,ld : pdef;
         concatstrings : boolean;

      label
         no_overload;

      begin
         { erst die beiden Äste bearbeiten }
         firstpass(p^.left);
         firstpass(p^.right);

         if codegenerror then
           exit;

         { overloaded operator ? }
         if (p^.left^.resulttype^.deftype=recorddef) or
            (p^.left^.resulttype^.deftype=classdef) or
            (p^.left^.resulttype^.deftype=recorddef) or
            (p^.left^.resulttype^.deftype=classdef) then
           begin
              {!!!!!!!!! handle paras }
              case p^.treetype of
                 { the nil as symtable signs firstcalln that this is
                   an overloaded operator }
                 addn : t:=gencallnode(overloaded_operators[0],nil);
                 else goto no_overload;
              end;
              firstpass(p);
              exit;
           end;
      no_overload:
         { compact consts }
         lt:=p^.left^.treetype;
         rt:=p^.right^.treetype;

         { convert int consts to real consts, if the }
         { other operand is a real const             }
         if is_constintnode(p^.left) and
           (rt=realconstn) then
           begin
              t:=genrealconstnode(p^.left^.value);
              disposetree(p^.left);
              p^.left:=t;
              lt:=realconstn;
           end;
         if is_constintnode(p^.right) and
            (lt=realconstn) then
           begin
              t:=genrealconstnode(p^.right^.value);
              disposetree(p^.right);
              p^.right:=t;
              rt:=realconstn;
           end;

         if is_constintnode(p^.left) and
           is_constintnode(p^.right) then
           begin
              lv:=p^.left^.value;
              rv:=p^.right^.value;
              case p^.treetype of
                 addn : t:=genordinalconstnode(lv+rv,s32bitdef);
                 subn : t:=genordinalconstnode(lv-rv,s32bitdef);
                 muln : t:=genordinalconstnode(lv*rv,s32bitdef);
                 xorn : t:=genordinalconstnode(lv xor rv,s32bitdef);
                 orn : t:=genordinalconstnode(lv or rv,s32bitdef);
                 andn : t:=genordinalconstnode(lv and rv,s32bitdef);
                 ltn : t:=genordinalconstnode(ord(lv<rv),booldef);
                 lten : t:=genordinalconstnode(ord(lv<=rv),booldef);
                 gtn : t:=genordinalconstnode(ord(lv>rv),booldef);
                 gten : t:=genordinalconstnode(ord(lv>=rv),booldef);
                 equaln : t:=genordinalconstnode(ord(lv=rv),booldef);
                 unequaln : t:=genordinalconstnode(ord(lv<>rv),booldef);
                 else
                   error(type_mismatch);
              end;
              disposetree(p);
              p:=t;
              exit;
           end
         else
           { Realkonstanten: }
           if (lt=realconstn) and (rt=realconstn) then
           begin
              lvd:=p^.left^.valued;
              rvd:=p^.right^.valued;
              case p^.treetype of
                 addn : t:=genrealconstnode(lvd+rvd);
                 subn : t:=genrealconstnode(lvd-rvd);
                 muln : t:=genrealconstnode(lvd*rvd);
                 slashn : t:=genrealconstnode(lvd/rvd);
                 ltn : t:=genordinalconstnode(ord(lvd<rvd),booldef);
                 lten : t:=genordinalconstnode(ord(lvd<=rvd),booldef);
                 gtn : t:=genordinalconstnode(ord(lvd>rvd),booldef);
                 gten : t:=genordinalconstnode(ord(lvd>=rvd),booldef);
                 equaln : t:=genordinalconstnode(ord(lvd=rvd),booldef);
                 unequaln : t:=genordinalconstnode(ord(lvd<>rvd),booldef);
                 else
                   error(type_mismatch);
              end;
              disposetree(p);
              p:=t;
              firstpass(p);
              exit;
           end;
         concatstrings:=false;
         if (lt=ordconstn) and (rt=ordconstn) and
           (p^.left^.resulttype^.deftype=grunddef) and
           (pgrunddef(p^.left^.resulttype)^.typ=uchar) and
           (p^.right^.resulttype^.deftype=grunddef) and
           (pgrunddef(p^.right^.resulttype)^.typ=uchar) then
           begin
              s1:=char(byte(p^.left^.value));
              s2:=char(byte(p^.right^.value));
              concatstrings:=true;
           end
         else if (lt=stringconstn) and (rt=ordconstn) and
           (p^.right^.resulttype^.deftype=grunddef) and
           (pgrunddef(p^.right^.resulttype)^.typ=uchar) then
           begin
              s1:=pstring(p^.left^.value)^;
              s2:=char(byte(p^.right^.value));
              concatstrings:=true;
           end
         else if (lt=ordconstn) and (rt=stringconstn) and
           (p^.left^.resulttype^.deftype=grunddef) and
           (pgrunddef(p^.left^.resulttype)^.typ=uchar) then
           begin
              s1:=char(byte(p^.left^.value));
              s2:=pstring(p^.right^.value)^;
              concatstrings:=true;
           end
         else if (lt=stringconstn) and (rt=stringconstn) then
           begin
              s1:=pstring(p^.left^.value)^;
              s2:=pstring(p^.right^.value)^;
              concatstrings:=true;
           end;

         if concatstrings then
           begin
              case p^.treetype of
                 addn : t:=genstringconstnode(s1+s2);
                 ltn : t:=genordinalconstnode(ord(s1<s2),booldef);
                 lten : t:=genordinalconstnode(ord(s1<=s2),booldef);
                 gtn : t:=genordinalconstnode(ord(s1>s2),booldef);
                 gten : t:=genordinalconstnode(ord(s1>=s2),booldef);
                 equaln : t:=genordinalconstnode(ord(s1=s2),booldef);
                 unequaln : t:=genordinalconstnode(ord(s1<>s2),booldef);
              end;
              disposetree(p);
              p:=t;
              exit;
           end;
         rd:=p^.right^.resulttype;
         ld:=p^.left^.resulttype;

         { wenn beides Boolean: }
         if ((ld^.deftype=grunddef) and
            (pgrunddef(ld)^.typ=bool8bit)) and
            ((rd^.deftype=grunddef) and
            (pgrunddef(rd)^.typ=bool8bit)) then
           begin
              if (p^.treetype=andn) or (p^.treetype=orn) then
                begin
                   calcregisters(p,0,0);
                   p^.location.loc:=LOC_JUMP;
                end
              else if (p^.treetype=unequaln) or (p^.treetype=equaln) then
                begin
                   calcregisters(p,1,0);
                   p^.location.loc:=LOC_FLAGS;
                   p^.resulttype:=booldef;
                end
              else error(type_mismatch);
           end
         { wenn beides vom Char dann keine Konvertiereung einfügen }
         { höchstens es handelt sich um einen +-Operator           }
         else if ((rd^.deftype=grunddef) and (pgrunddef(rd)^.typ=uchar)) and
            ((ld^.deftype=grunddef) and (pgrunddef(ld)^.typ=uchar)) then
            begin
               if p^.treetype=addn then
                 begin
                    p^.right:=gentypeconvnode(p^.right,cstringdef);
                    p^.left:=gentypeconvnode(p^.left,cstringdef);
                    firstpass(p^.left);
                    firstpass(p^.right);
                    calcregisters(p,0,0);
                    p^.location.loc:=LOC_MEM;
                 end
               else
                calcregisters(p,1,0);
            end
         { wenn links String und rechts Char, dann Char konvertieren }
         else if ((rd^.deftype=stringdef) and
                 ((ld^.deftype=grunddef) and (pgrunddef(ld)^.typ=uchar))) or
                 ((ld^.deftype=stringdef) and
                 ((rd^.deftype=grunddef) and (pgrunddef(rd)^.typ=uchar))) then
           begin
              if ((rd^.deftype=grunddef) and (pgrunddef(rd)^.typ=uchar)) then
                p^.right:=gentypeconvnode(p^.right,cstringdef)
                else p^.left:=gentypeconvnode(p^.left,cstringdef);
              firstpass(p^.left);
              firstpass(p^.right);
              calcregisters(p,0,0);
              p^.location.loc:=LOC_MEM;
           end
         else
           if ((rd^.deftype=setdef) and (ld^.deftype=setdef)) then
             begin
                if not(is_equal(psetdef(rd)^.setof,psetdef(ld)^.setof)) then
                  error(set_element_are_not_comp);
                firstpass(p^.left);
                firstpass(p^.right);
                calcregisters(p,0,0);
                p^.location.loc:=LOC_MEM;
             end
         else
           if ((rd^.deftype=stringdef) and (ld^.deftype=stringdef)) then
           { nichts tun, ist aber OK }
         { sollte eine Realzahl dabei sein, beide nach s64bitreal konvertieren }
         else
            if ((rd^.deftype=grunddef) and (pgrunddef(rd)^.typ=s64real)) or
            ((ld^.deftype=grunddef) and (pgrunddef(ld)^.typ=s64real)) then
           begin
              p^.right:=gentypeconvnode(p^.right,cs64realdef);
              p^.left:=gentypeconvnode(p^.left,cs64realdef);
              firstpass(p^.left);
              firstpass(p^.right);
              calcregisters(p,0,1);
              p^.location.loc:=LOC_FPUSTACK;
           end
         { Pointervergleiche und Subtraktion: }
         else if (rd^.deftype=pointerdef) and (ld^.deftype=pointerdef) and
           is_equal(rd,ld) then
           begin
              calcregisters(p,1,0);
              p^.location.loc:=LOC_REGISTER;
              case p^.treetype of
                 equaln,unequaln : ;
                 ltn,lten,gtn,gten : begin
                                        if aktexprlevel<1 then
                                          error(type_mismatch);
                                     end;
                 subn : begin
                           if aktexprlevel<1 then
                             error(type_mismatch);
                           p^.resulttype:=s32bitdef;
                           exit;
                        end;
                 else error(type_mismatch);
              end;
           end
         else if (rd^.deftype=procvardef) and (ld^.deftype=procvardef) and
           is_equal(rd,ld) then
           begin
              calcregisters(p,1,0);
              p^.location.loc:=LOC_REGISTER;
              case p^.treetype of
                 equaln,unequaln : ;
                 else error(type_mismatch);
              end;
           end
         else if (rd^.deftype=pointerdef) then
           begin
              p^.location.loc:=LOC_REGISTER;
              p^.left:=gentypeconvnode(p^.left,s32bitdef);
              firstpass(p^.left);
              calcregisters(p,1,0);
              if p^.treetype=addn then
                begin
                   if aktexprlevel<1 then
                     error(type_mismatch);
                end
              else error(type_mismatch);
           end
         else if (ld^.deftype=aufzaehldef) and (rd^.deftype=aufzaehldef)
            and (is_equal(ld,rd)) then
           begin
              calcregisters(p,1,0);
              case p^.treetype of
                 equaln,unequaln,
                 ltn,lten,gtn,gten : ;
                 else error(type_mismatch);
              end;
           end
         else if (ld^.deftype=pointerdef) then
           begin
              p^.location.loc:=LOC_REGISTER;
              p^.right:=gentypeconvnode(p^.right,s32bitdef);
              firstpass(p^.right);
              calcregisters(p,1,0);
              case p^.treetype of
                 addn,subn : if aktexprlevel<1 then
                               error(type_mismatch);
                 else error(type_mismatch);
              end;
           end
         { sonst immer nach 32 Bit-Int konvertieren }
         else
           begin
              p^.right:=gentypeconvnode(p^.right,s32bitdef);
              p^.left:=gentypeconvnode(p^.left,s32bitdef);
              firstpass(p^.left);
              firstpass(p^.right);
              calcregisters(p,1,0);
              p^.location.loc:=LOC_REGISTER;
           end;

         if codegenerror then
           exit;

         { Resultatyp feststellen; bei Vergleich Boolean }
         case p^.treetype of
            ltn,lten,gtn,gten,equaln,unequaln : begin
                                                   p^.resulttype:=booldef;
                                                   p^.location.loc:=LOC_FLAGS;
                                                end;
            addn : begin
                      { Stringaddition hat eine String von 255 Zeichen }
                      { Länge als Ergebnis                             }
                      if (p^.left^.resulttype^.deftype=stringdef) then
                        p^.resulttype:=cstringdef
                      else p^.resulttype:=p^.left^.resulttype;
                   end;
            else p^.resulttype:=p^.left^.resulttype;
         end;
      end;

    procedure firstmoddiv(var p : ptree);far;

      var
         t : ptree;
         power : longint;

      begin
         firstpass(p^.left);
         firstpass(p^.right);

         if codegenerror then
           exit;

         if is_constintnode(p^.left) and is_constintnode(p^.right) then
           begin
              case p^.treetype of
                 modn : t:=genordinalconstnode(p^.left^.value mod p^.right^.value,s32bitdef);
                 divn : t:=genordinalconstnode(p^.left^.value div p^.right^.value,s32bitdef);
              end;
              disposetree(p);
              p:=t;
              exit;
           end;

         p^.right:=gentypeconvnode(p^.right,s32bitdef);
         p^.left:=gentypeconvnode(p^.left,s32bitdef);
         firstpass(p^.left);
         firstpass(p^.right);

         if codegenerror then
           exit;

         p^.registers32:=p^.left^.registers32;

         if p^.registers32<p^.right^.registers32 then
           p^.registers32:=p^.right^.registers32;
         if p^.registers32<2 then p^.registers32:=2;

         p^.resulttype:=s32bitdef;
         p^.location.loc:=LOC_REGISTER;
      end;

    procedure firstshlshr(var p : ptree);far;

      var
         t : ptree;

      begin
         firstpass(p^.left);
         firstpass(p^.right);

         if codegenerror then
           exit;

         if is_constintnode(p^.left) and is_constintnode(p^.right) then
           begin
              case p^.treetype of
                 shrn : t:=genordinalconstnode(p^.left^.value shr p^.right^.value,s32bitdef);
                 shln : t:=genordinalconstnode(p^.left^.value shl p^.right^.value,s32bitdef);
              end;
              disposetree(p);
              p:=t;
              exit;
           end;
         p^.right:=gentypeconvnode(p^.right,s32bitdef);
         p^.left:=gentypeconvnode(p^.left,s32bitdef);
         firstpass(p^.left);
         firstpass(p^.right);

         if codegenerror then
           exit;

         calcregisters(p,2,0);
         {
         p^.registers32:=p^.left^.registers32;

         if p^.registers32<p^.right^.registers32 then
           p^.registers32:=p^.right^.registers32;
         if p^.registers32<1 then p^.registers32:=1;
         }
         p^.resulttype:=s32bitdef;
         p^.location.loc:=LOC_REGISTER;
      end;

    procedure firstrealconst(var p : ptree);far;

      begin
         p^.location.loc:=LOC_MEM;
      end;

    procedure firstordconst(var p : ptree);far;

      begin
         p^.location.loc:=LOC_MEM;
      end;

    procedure firstniln(var p : ptree);far;

      begin
         p^.resulttype:=voidpointerdef;
         p^.location.loc:=LOC_MEM;
      end;

    procedure firststringconst(var p : ptree);far;

      begin
         p^.resulttype:=new(pstringdef,init(length(p^.values^)));
         p^.location.loc:=LOC_MEM;
      end;

    procedure firstumminus(var p : ptree);far;

      var
         t : ptree;

      begin
         firstpass(p^.left);

         if codegenerror then
           exit;
         if is_constintnode(p^.left) then
           begin
              t:=genordinalconstnode(-p^.left^.value,s32bitdef);
              disposetree(p);
              p:=t;
              exit;
           end;
         if (p^.left^.resulttype^.deftype=grunddef) then
           begin
              if pgrunddef(p^.left^.resulttype)^.typ=s64real then
                begin
                   p^.location.loc:=LOC_FPUSTACK;
                end
              else
                begin
                   p^.left:=gentypeconvnode(p^.left,s32bitdef);
                   firstpass(p^.left);
                   if codegenerror then
                     exit;
                   if (p^.left^.location.loc<>LOC_REGISTER) and
                     (p^.registers32<1) then
                   p^.registers32:=1;
                   p^.location.loc:=LOC_REGISTER;
                end;
           end
         else
           error(type_mismatch);
         p^.registers32:=p^.left^.registers32;
         p^.resulttype:=p^.left^.resulttype;
      end;

    procedure firstaddr(var p : ptree);far;

      var
         hp  : ptree;
         hp2 : pdefcoll;

      begin
         make_not_regable(p^.left);
         if not(assigned(p^.resulttype)) then
           begin
              { falls Adresse von einer Callnode bestimmt werden soll, }
              { die Callnode in eine Loadnode umwandeln }
              if p^.left^.treetype=calln then
                begin
                   hp:=genloadnode(pvarsym(p^.left^.symtableprocentry),p^.left^.symtableproc);

                   { Resultat ist eine Prozedurvariable }
                   p^.resulttype:=new(pprocvardef,init);
                   pprocvardef(p^.resulttype)^.options:=
                     p^.left^.symtableprocentry^.definition^.options;
                   pprocvardef(p^.resulttype)^.retdef:=
                     p^.left^.symtableprocentry^.definition^.retdef;
                   hp2:=p^.left^.symtableprocentry^.definition^.para1;
                   while assigned(hp2) do
                     begin
                        pprocvardef(p^.resulttype)^.concatdef(hp2^.data,hp2^.paratyp);
                        hp2:=hp2^.next;
                     end;

                   disposetree(p^.left);
                   p^.left:=hp;
                end
              else
                begin
                   if aktexprlevel<2 then
                     p^.resulttype:=voidpointerdef
                   else p^.resulttype:=new(ppointerdef,init(p^.left^.resulttype));
                end;
           end;

         firstpass(p^.left);
         if codegenerror then
           exit;

         if (p^.left^.location.loc<>LOC_REFERENZ) then
           error(error_in_expression);

         p^.registers32:=p^.left^.registers32;
         if p^.registers32<1 then
           p^.registers32:=1;
         p^.location.loc:=LOC_REGISTER;
      end;

    procedure firstnot(var p : ptree);far;

      var
         t : ptree;

      begin
         firstpass(p^.left);

         if codegenerror then
           exit;

         if (p^.left^.treetype=ordconstn) then
           begin
              t:=genordinalconstnode(not(p^.left^.value),p^.left^.resulttype);
              disposetree(p);
              p:=t;
              exit;
           end;
         p^.resulttype:=p^.left^.resulttype;
         p^.location.loc:=p^.left^.location.loc;
         if (p^.resulttype^.deftype=grunddef) and
            (pgrunddef(p^.resulttype)^.typ=bool8bit) then
              begin
                 p^.registers32:=p^.left^.registers32;
                 if (p^.location.loc=LOC_REFERENZ) and
                    (p^.registers32<1) then
                   p^.registers32:=1;
              end
           else
             begin
                p^.left:=gentypeconvnode(p^.left,s32bitdef);
                firstpass(p^.left);

                if codegenerror then
                  exit;

                p^.resulttype:=p^.left^.resulttype;
                p^.registers32:=p^.left^.registers32;
                if (p^.left^.location.loc<>LOC_REGISTER) and
                   (p^.registers32<1) then
                  p^.registers32:=1;
                p^.location.loc:=LOC_REGISTER;
             end;
      end;

    procedure firstnothing(var p : ptree);far;

      begin
      end;

    procedure firstassignment(var p : ptree);far;

      begin
         firstpass(p^.left);
         firstpass(p^.right);

         if codegenerror then
           exit;

         { sollte rechts und links ein String stehen, muß nicht konvertiert }
         { werden, da STRCOPY mit den richtigen Parametern aufgerufen wird  }
         if not((p^.right^.resulttype^.deftype=stringdef)
            and (p^.left^.resulttype^.deftype=stringdef)) then
           begin
              p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);

              { nochmal firstpass wegen der Typkonvertierung aufrufen }
              firstpass(p^.right);

              if codegenerror then
                exit;

           end;
         if (aktexprlevel<4) then p^.resulttype:=voiddef
           else p^.resulttype:=p^.right^.resulttype;
         {
           p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
           p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
         }
         p^.registers32:=p^.left^.registers32+p^.right^.registers32;
         p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
      end;

    procedure firstlr(var p : ptree);far;

      begin
         firstpass(p^.left);
         firstpass(p^.right);
      end;

    procedure firstderef(var p : ptree);far;

      begin
         firstpass(p^.left);
         if codegenerror then
           exit;

         p^.registers32:=p^.left^.registers32;
         if p^.registers32<1 then
           p^.registers32:=1;

         if p^.left^.resulttype^.deftype<>pointerdef then
           error(invalid_qualifizier);

         p^.resulttype:=ppointerdef(p^.left^.resulttype)^.definition;
         p^.location.loc:=LOC_REFERENZ;
      end;

    procedure firstrange(var p : ptree);far;

      var
         ct : tconverttype;

      begin
         firstpass(p^.left);
         firstpass(p^.right);
         if codegenerror then
           exit;
         { nur ordinale Konstanten zulassen }
         if not((p^.left^.treetype=ordconstn) and
                 (p^.right^.treetype=ordconstn)) then
           error(error_in_expression);
         { Obergrenze muß größer oder gleich Untergrenze sein }
         if (p^.left^.value>p^.right^.value) then
           error(upper_l_lower);
         { beide Typen müssen kompatibel sein }
         if not(isconvertable(p^.left^.resulttype,p^.right^.resulttype,
           ct,ordconstn { nur Dummy} )) and
           not(is_equal(p^.left^.resulttype,p^.right^.resulttype)) then
           error(type_mismatch);
      end;

    procedure firstvecn(var p : ptree);far;

      var
         harr : pdef;
         ct : tconverttype;


      begin
         firstpass(p^.left);
         firstpass(p^.right);
         if codegenerror then
           exit;

         { nur bei Arraysindex testen }
         if (p^.left^.resulttype^.deftype=arraydef) then
           begin
              if not(isconvertable(p^.right^.resulttype,
                parraydef(p^.left^.resulttype)^.rangedef,
                ct,ordconstn { only dummy} )) and
              not(is_equal(p^.right^.resulttype,
                parraydef(p^.left^.resulttype)^.rangedef)) then
                error(type_mismatch);
           end;
         { maybe type conversation }
         if p^.right^.resulttype^.deftype<>aufzaehldef then
           p^.right:=gentypeconvnode(p^.right,s32bitdef);

         { nochmal firstpass }
         firstpass(p^.right);

         if codegenerror then
           exit;

         { Returntyp berechnen }
         if p^.left^.resulttype^.deftype=arraydef then
           p^.resulttype:=parraydef(p^.left^.resulttype)^.definition
         else if (p^.left^.resulttype^.deftype=pointerdef) then
           begin
              { Pointer in Array umwandeln }
              harr:=new(parraydef,init(0,$7fffffff,s32bitdef));
              parraydef(harr)^.definition:=ppointerdef(p^.left^.resulttype)^.definition;
              p^.left:=gentypeconvnode(p^.left,harr);
              firstpass(p^.left);

              if codegenerror then
                exit;
              p^.resulttype:=parraydef(harr)^.definition
           end
         else
         { indizierter Zugriff auf String }
           p^.resulttype:=cchardef;

         { the register calculation is easy if a const index is used }
         if p^.right^.treetype=ordconstn then
           p^.registers32:=p^.left^.registers32
         else
           begin
              p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);

              { not correct, but what works better ? }
              if p^.left^.registers32>0 then
                p^.registers32:=max(p^.registers32,2)
              else
              { mindestens ein Register }
                p^.registers32:=max(p^.registers32,1);
           end;
         { es wird derselbe Speichertyp wie links zurückgegeben }
         p^.location.loc:=p^.left^.location.loc;
      end;

    type
       tfirstconvproc = procedure(p : ptree);

    procedure first_bigger_smaller(p : ptree);far;

      begin
         if (p^.left^.location.loc<>LOC_REGISTER) and (p^.registers32=0) then
           p^.registers32:=1;
         p^.location.loc:=LOC_REGISTER;
      end;

    procedure first_cstring_charpointer(p : ptree);far;

      begin
         p^.registers32:=1;
         p^.location.loc:=LOC_REGISTER;
      end;

    procedure first_cstring_chararray(p : ptree);far;

      begin
         p^.location.loc:=LOC_MEM;
      end;

    procedure first_string_string(p : ptree);far;

      begin
         p^.location.loc:=LOC_MEM;
      end;

    procedure first_char_to_string(p : ptree);far;

      begin
         p^.location.loc:=LOC_MEM;
      end;

    procedure first_nothing(p : ptree);far;

      begin
      end;

    procedure first_array_to_pointer(p : ptree);far;

      begin
         if p^.registers32<1 then
           p^.registers32:=1;
         p^.location.loc:=LOC_REGISTER;
      end;

    procedure first_int_real(p : ptree);far;

      begin
         if p^.left^.treetype=ordconstn then
           begin
              { Konstanten direkt umwandeln }
              p^.treetype:=realconstn;
              p^.labnumber:=-1;
              p^.valued:=p^.left^.value;
              p^.disposetyp:=dt_nothing;
              disposetree(p^.left);
              p^.location.loc:=LOC_MEM;
           end
         else
           begin
              inc(p^.registersfpu);
              p^.location.loc:=LOC_FPUSTACK;
           end;
      end;

    procedure first_pointer_to_array(p : ptree);far;

      begin
         if p^.registers32<1 then
           p^.registers32:=1;
         p^.location.loc:=LOC_REFERENZ;
      end;

    { Achtung:  *** kein ***  rekursiver Aufruf von firstpass }

    procedure firsttypeconv(var p : ptree);far;

      var
         hp : ptree;

      const
         firstconvert : array[tc_u8bit_2_s32bit..tc_int_2_real] of
           tfirstconvproc = (first_bigger_smaller,first_nothing,first_bigger_smaller,
                             first_bigger_smaller,first_bigger_smaller,
                             first_bigger_smaller,first_bigger_smaller,
                             first_bigger_smaller,first_string_string,
                             first_cstring_charpointer,first_cstring_chararray,
                             first_array_to_pointer,first_pointer_to_array,
                             first_char_to_string,first_bigger_smaller,
                             first_bigger_smaller,first_bigger_smaller,
                             first_bigger_smaller,first_bigger_smaller,
                             first_bigger_smaller,first_bigger_smaller,
                             first_bigger_smaller,first_bigger_smaller,
                             first_int_real);

      begin
         { bei expliziten Typkonvertierungen firstpass ausführen }
         if p^.explizit then
           firstpass(p^.left);

         if codegenerror then
           exit;

         { Typekonvertierungen auf sich selbst entfernen }
         if is_equal(p^.left^.resulttype,p^.resulttype) then
           begin
              hp:=p;
              p:=p^.left;
              p^.resulttype:=hp^.resulttype;
              putnode(hp);
              exit;
           end;
         p^.registers32:=p^.left^.registers32;
         p^.registersfpu:=p^.left^.registersfpu;
         p^.location:=p^.left^.location;
         if not(isconvertable(p^.left^.resulttype,p^.resulttype,p^.convtyp,p^.left^.treetype)) then
           begin
              if p^.explizit then
                begin
                   { normal tc_equal-Konvertierung durchführen }
                   p^.convtyp:=tc_equal;
                   { wenn Aufzähltyp nach Ordinal konvertiert werden soll }
                   { dann Aufzähltyp=s32bit                               }
                   if (p^.left^.resulttype^.deftype=aufzaehldef) and
                      is_ordinal(p^.resulttype) then
                     begin
                        if p^.left^.treetype=ordconstn then
                          begin
                             hp:=genordinalconstnode(p^.left^.value,p^.resulttype);
                             disposetree(p);
                             p:=hp;
                             exit;
                          end
                        else
                          begin
                             if not isconvertable(s32bitdef,p^.resulttype,p^.convtyp,ordconstn { nur Dummy} ) then
                               error(ill_type_cast);
                          end;

                     end
                   {  entsprechend Ordinal nach Aufzähl: }
                   else if (p^.resulttype^.deftype=aufzaehldef) and
                      is_ordinal(p^.left^.resulttype) then
                     begin
                        if p^.left^.treetype=ordconstn then
                          begin
                             hp:=genordinalconstnode(p^.left^.value,p^.resulttype);
                             disposetree(p);
                             p:=hp;
                             exit;
                          end
                        else
                          begin
                             if not isconvertable(p^.left^.resulttype,s32bitdef,p^.convtyp,ordconstn { nur Dummy} ) then
                               error(ill_type_cast);
                          end;
                     end
                   { nur wenn gleiche Größe }
                   else if (p^.left^.resulttype^.deftype<>formaldef) and
                     (p^.left^.resulttype^.size<>p^.resulttype^.size) then
                     error(ill_type_cast);
                   { und nach strukturierten Typen nur,     }
                   { wenn die Quelle nicht ein Register ist }
                   case p^.resulttype^.deftype of
                      recorddef,stringdef,arraydef,classdef :
                        if (p^.left^.location.loc=LOC_REGISTER) or
                           (p^.left^.location.loc=LOC_CREGISTER) then
                          error(ill_type_cast);
                   end;
                end
              else
                error(type_mismatch);
           end
         else
           begin
              p^.explizit:=false;
              { ordinale Konstanten direkt konvertieren }
              if (p^.left^.treetype=ordconstn) and is_ordinal(p^.resulttype) then
                begin
                   hp:=genordinalconstnode(p^.left^.value,p^.resulttype);
                   disposetree(p);
                   p:=hp;
                   exit;
                end;
              if p^.convtyp<>tc_equal then
                firstconvert[p^.convtyp](p);
           end;
      end;

    { *************** Funktionshandling **************** }

    procedure firstcallparan(var p : ptree;defcoll : pdefcoll);

      begin
         if assigned(p^.right) then
           begin
              if defcoll=nil then
                firstcallparan(p^.right,nil)
                else firstcallparan(p^.right,defcoll^.next);
              p^.registers32:=p^.right^.registers32;
           end;
         if defcoll=nil then
           begin
              firstpass(p^.left);

              if codegenerror then
                exit;

              p^.resulttype:=p^.left^.resulttype;
           end
         { falls aufzurufendes Unterprogramm schon bekannt, dann }
         { Typkonvertierungen einfügen                           }
         else
           begin
              if not((p^.left^.resulttype^.deftype=stringdef) and
                     (defcoll^.data^.deftype=stringdef)) and
                     (defcoll^.data^.deftype<>formaldef) then
                begin
                   if (defcoll^.paratyp=vs_var) and
                     not(is_equal(p^.left^.resulttype,defcoll^.data)) then
                     begin
                        error(call_by_ref_without_typeconv);
                        exit;
                     end;
                   p^.left:=gentypeconvnode(p^.left,defcoll^.data);
                   firstpass(p^.left);

                   if codegenerror then
                     exit;

                end;
              { Variablen, die call by referenz übergeben werden, }
              { können nicht in ein Register kopiert werden       }
              if defcoll^.paratyp=vs_var then
                make_not_regable(p^.left);

              p^.resulttype:=defcoll^.data;
           end;
         if p^.left^.registers32>p^.registers32 then
           p^.registers32:=p^.left^.registers32;
      end;

    procedure firstcalln(var p : ptree);far;

      type
         pprocdefcoll = ^tprocdefcoll;

         tprocdefcoll = record
            data : pprocdef;
            nextpara : pdefcoll;
            next : pprocdefcoll;
         end;

      var
         hp,procs,hp2 : pprocdefcoll;
         pd : pprocdef;
         pt : ptree;
         exactmatch : boolean;
         paralength,l : longint;
         pdc : pdefcoll;

         { nur ein Dummy }
         hcvt : tconverttype;

      { types.is_euqal darf keine formaldef's behandeln !}

      function is_equal(def1,def2 : pdef) : boolean;

        begin
           { alle Typen können an formaldef übergeben werden }
           is_equal:=(def1^.deftype=formaldef) or
             types.is_equal(def1,def2);
        end;

      begin
         { Register freigeben! }
         { falls procdefinition<>nil, dann wurde schon firstpass }
         { aufgerufen                                            }
         { scheint nicht so gut wegen der Register }
         { if assigned(p^.procdefinition) then
           exit; }

         { handelt es sich um eine Prozedurvariable ? }
         if not(assigned(p^.right)) then
           begin
              if assigned(p^.left) then
                begin
                   firstcallparan(p^.left,nil);
                   if codegenerror then
                     exit;
                end;
              { Länge der Parameterliste feststellen }
              pt:=p^.left;
              paralength:=0;
              while assigned(pt) do
                begin
                   inc(paralength);
                   pt:=pt^.right;
                end;

              { alle in Frage kommenden Prozeduren in eine }
              { verkettete Liste einfügen                  }
              pd:=p^.symtableprocentry^.definition;
              procs:=nil;
              while assigned(pd) do
                begin
                   { Laenge der deklarierten Parameterliste feststellen: }
                   pdc:=pd^.para1;
                   l:=0;
                   while assigned(pdc) do
                     begin
                        inc(l);
                        pdc:=pdc^.next;
                     end;
                   { nur wenn die Parameterlänge paßt, dann Einfügen }
                   if l=paralength then
                     begin
                        new(hp);
                        hp^.data:=pd;
                        hp^.next:=procs;
                        hp^.nextpara:=pd^.para1;
                        procs:=hp;
                     end;
                   pd:=pd^.nextoverloaded;
                end;

              { nun alle Parameter nacheinander vergleichen }
              pt:=p^.left;
              while assigned(pt) do
                begin

                   { paßt der Parameter irgendwo exakt? }
                   exactmatch:=false;
                   hp:=procs;
                   while assigned(hp) do
                     begin
                        if is_equal(hp^.nextpara^.data,pt^.resulttype) then
                          exactmatch:=true;
                        hp:=hp^.next;
                     end;
                   { ja, dann alle anderen Prozeduren entfernen }
                   if exactmatch then
                     begin
                        { erst am Anfang }
                        while (assigned(procs)) and not(is_equal(procs^.nextpara^.data,pt^.resulttype)) do
                          begin
                             hp:=procs^.next;
                             dispose(procs);
                             procs:=hp;
                          end;
                        { und jetzt aus der Mitte }
                        hp:=procs;
                        while (assigned(hp)) and assigned(hp^.next) do
                          begin
                             if not(is_equal(hp^.next^.nextpara^.data,pt^.resulttype)) then
                               begin
                                  hp2:=hp^.next^.next;
                                  dispose(hp^.next);
                                  hp^.next:=hp2;
                               end
                             else
                               hp:=hp^.next;
                          end;
                     end
                   { sollte nirgendwo ein Parameter exakt passen, }
                   { so alle Prozeduren entfernen, bei denen      }
                   { der Parameter auch nach einer impliziten     }
                   { Typkonvertierung nicht passt                 }
                   else
                     begin
                        { erst am Anfang }
                        while (assigned(procs)) and
                          not(isconvertable(pt^.resulttype,procs^.nextpara^.data,hcvt,pt^.left^.treetype)) do
                          begin
                             hp:=procs^.next;
                             dispose(procs);
                             procs:=hp;
                          end;
                        { und jetzt aus der Mitte }
                        hp:=procs;
                        while (assigned(hp)) and assigned(hp^.next) do
                          begin
                             if not(isconvertable(pt^.resulttype,hp^.next^.nextpara^.data,
                               hcvt,pt^.left^.treetype)) then
                               begin
                                  hp2:=hp^.next^.next;
                                  dispose(hp^.next);
                                  hp^.next:=hp2;
                               end
                             else
                               hp:=hp^.next;
                          end;
                     end;
                   { nun bei denn Prozeduren den nextpara-Zeiger auf den }
                   { naechsten Parameter setzten                         }
                   hp:=procs;
                   while assigned(hp) do
                     begin
                        hp^.nextpara:=hp^.nextpara^.next;
                        hp:=hp^.next;
                     end;
                   pt:=pt^.right;
                end;

              if procs=nil then
                begin
                   error(no_para_match);
                   exit;
                end;

              if assigned(procs^.next) then
                error(too_much_matches);
              p^.procdefinition:=procs^.data;
              p^.resulttype:=procs^.data^.retdef;
              p^.location.loc:=LOC_MEM;
              { nochmal die Parameter beackern, um die Typkonvertiereungen }
              { einbauen zu koennen                                        }
              if assigned(p^.left) then
                firstcallparan(p^.left,p^.procdefinition^.para1);

              { interne Proceduren bearbeiten }
              if (p^.procdefinition^.options and pointernproc)<>0 then
                begin
                   pt:=geninlinenode(pprocdef(p^.procdefinition)^.extnumber,p^.left^.left);
                   if assigned(p^.left^.right) then
                     disposetree(p^.left^.right);
                   putnode(p^.left);
                   putnode(p);
                   firstpass(pt);

                   if codegenerror then
                     exit;

                   p:=pt;
                   exit;
                end;
           end
         else
           begin
              { Prozedurvariable }
              { die Typen der Parameter berechnen }
              if assigned(p^.left) then
                begin
                   firstcallparan(p^.left,nil);
                   if codegenerror then
                     exit;
                end;
              firstpass(p^.right);
              { Parameter überprüfen }
              pdc:=pprocvardef(p^.right^.resulttype)^.para1;
              pt:=p^.left;
              while assigned(pdc) and assigned(pt) do
                begin
                   pt:=pt^.right;
                   pdc:=pdc^.next;
                end;
              if assigned(pt) or assigned(pdc) then
                error(no_para_match);
              { Typkonvertierungen einbauen }
              if assigned(p^.left) then
                begin
                   firstcallparan(p^.left,pprocvardef(p^.right^.resulttype)^.para1);
                   if codegenerror then
                     exit;
                end;
              p^.resulttype:=pprocvardef(p^.right^.resulttype)^.retdef;
           end;
         { und falls noetig ein Register fuer den Returnwert bereitstellen }
         if (p^.resulttype<>pdef(voiddef)) then
           begin
              { Konstruktor meldet sich über die Flags }
              if (p^.procdefinition^.options and poconstructor)<>0 then
                p^.location.loc:=LOC_FLAGS
              else
                begin
                   p^.location.loc:=LOC_REGISTER;
                   if ((p^.resulttype^.deftype=procvardef) or
                      (p^.resulttype^.deftype=aufzaehldef) or
                      (p^.resulttype^.deftype=pointerdef)) then
                      p^.registers32:=1
                   else if (p^.resulttype^.deftype=grunddef) then
                     begin
                        if pgrunddef(p^.resulttype)^.typ=s64real then
                          begin
                             p^.registersfpu:=1;
                             p^.location.loc:=LOC_FPUSTACK;
                          end
                        else p^.registers32:=1
                     end;
                end;
           end;
         { noch falls nötig Classpointer berechen }
         { aber nur wenn dieser kein "Hilfsknoten" ist }

         if (p^.methodpointer<>nil) then
           begin
              case p^.methodpointer^.treetype of
                typen,hnewn : ;
                else
                  begin
                     firstpass(p^.methodpointer);
                     p^.registersfpu:=max(p^.methodpointer^.registersfpu,p^.registersfpu);
                     p^.registers32:=max(p^.methodpointer^.registers32,p^.registers32);
                  end;
              end;
           end;
         { Die benutzten Register der Prozedurvariable berücksichtigen }
         if assigned(p^.right) then
           begin
              p^.registersfpu:=max(p^.right^.registersfpu,p^.registersfpu);
              p^.registers32:=max(p^.right^.registers32,p^.registers32);
           end;
      end;

    procedure firstfuncret(var p : ptree);far;

      begin
         p^.resulttype:=procinfo.retdef;
         p^.location.loc:=LOC_REFERENZ;
         if (procinfo.retdef^.deftype=arraydef) or
            (procinfo.retdef^.deftype=stringdef) or
            (procinfo.retdef^.deftype=recorddef) or
            (procinfo.retdef^.deftype=classdef) or
            (procinfo.retdef^.deftype=setdef) then
            p^.registers32:=1;
      end;

    { interne Inlineprozeduren }

    procedure firstinline(var p : ptree);far;

      var
         hp : ptree;
         isreal : boolean;

      begin
         { bei writeln; enthält p^.left keine gültige Adresse }
         if assigned(p^.left) then
           begin
              p^.registers32:=p^.left^.registers32;
              p^.registersfpu:=p^.left^.registersfpu;
              p^.location:=p^.left^.location;
           end;
         case p^.inlinenumber of
            in_lo_word,in_hi_word : begin
                       if p^.registers32<1 then
                         p^.registers32:=1;
                       p^.resulttype:=u8bitdef;
                       p^.location.loc:=LOC_REGISTER;
                    end;
            in_lo_long,in_hi_long : begin
                       if p^.registers32<1 then
                         p^.registers32:=1;
                       p^.resulttype:=u16bitdef;
                       p^.location.loc:=LOC_REGISTER;
                    end;
            in_sizeof_x : begin
                             if p^.registers32<1 then
                               p^.registers32:=1;
                             p^.resulttype:=s32bitdef;
                             p^.location.loc:=LOC_REGISTER;
                          end;
            in_typeof_x : begin
                             if p^.registers32<1 then
                               p^.registers32:=1;
                             p^.resulttype:=voidpointerdef;
                             p^.location.loc:=LOC_REGISTER;
                          end;
            in_ord_char : begin
                       p^.resulttype:=u8bitdef;
                       { Konstanten direkt umwandeln }
                       if p^.left^.treetype=ordconstn then
                         begin
                            hp:=p^.left;
                            putnode(p);
                            hp^.resulttype:=s32bitdef;
                            p:=hp;
                         end;
                    end;
            in_chr_byte : begin
                       p^.resulttype:=cchardef;
                    end;
            in_length_string : begin
                       p^.resulttype:=u8bitdef;
                       { String nach Stringkonvertierungen brauchen wir hier nicht }
                       if (p^.left^.treetype=typeconvn) and
                          (p^.left^.left^.resulttype^.deftype=stringdef) then
                         begin
                            hp:=p^.left^.left;
                            putnode(p^.left);
                            p^.left:=hp;
                         end;
                    end;
            in_assigned_x : begin
                               p^.resulttype:=booldef;
                               p^.location.loc:=LOC_FLAGS;
                            end;
            in_dec_dword,
            in_dec_word,
            in_dec_byte,
            in_inc_dword,
            in_inc_word,
            in_inc_byte : begin
                             p^.resulttype:=voiddef;
                             if p^.left^.location.loc<>LOC_REFERENZ then
                               error(error_in_expression);
                          end;
            in_read_x,
            in_readln_x,
            in_write_x,
            in_writeln_x : begin
                              p^.resulttype:=voiddef;
                              if assigned(p^.left) then
                                begin
                                   firstcallparan(p^.left,nil);
                                   { Typkonvertierungen für write(ln) einfügen }
                                   if (p^.inlinenumber=in_write_x) or (p^.inlinenumber=in_writeln_x) then
                                     begin
                                        hp:=p^.left;
                                        while assigned(hp) do
                                          begin
                                             if hp^.left^.resulttype^.deftype=grunddef then
                                               case pgrunddef(hp^.left^.resulttype)^.typ of
                                                  u8bit,s8bit,
                                                  u16bit,s16bit :
                                                        hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
                                               end;
                                             hp:=hp^.right;
                                          end;
                                     end;
                                   { nochmals alle Parameter bearbeiten }
                                   firstcallparan(p^.left,nil);
                                end;
                           end;
            in_str_x_string : begin
                                 p^.resulttype:=voiddef;
                                 if assigned(p^.left) then
                                   begin
                                      firstcallparan(p^.left,nil);
                                      hp:=p^.left;
                                      if hp^.resulttype^.deftype=grunddef then
                                        begin
                                           isreal:=false;
                                           { ersten Parameter konvertieren }
                                           { und natürlich Gültigkeit prüfen }
                                           case pgrunddef(hp^.left^.resulttype)^.typ of
                                              s64real : isreal:=true;

                                              u8bit,s8bit,
                                              u16bit,s16bit :
                                                 hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
                                              else error(no_para_match);
                                           end;
                                           { nächster Parameter }
                                           hp:=hp^.right;
                                           { Formatieroptionen ?}
                                           if hp^.left^.is_colon_para then
                                             hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
                                           hp:=hp^.right;

                                           if hp^.left^.is_colon_para then
                                             begin
                                                if isreal then
                                                  hp^.left:=gentypeconvnode(hp^.left,s32bitdef)
                                                else error(ill_colon_qualifier);
                                                hp:=hp^.right;
                                             end;

                                           { gültiger String ? }
                                           if (hp^.left^.resulttype^.deftype<>stringdef) or
                                             (hp^.left^.location.loc<>LOC_REFERENZ) then
                                             error(error_in_expression);
                                           { !!!!! Länge von String überprüfen }

                                           { nochmals alle Parameter bearbeiten }
                                           firstcallparan(p^.left,nil);
                                        end
                                      else error(error_in_expression);
                                   end
                                 else error(error_in_expression);
                              end;
            else internalerror(8);
         end;
      end;

    procedure firstsubscriptn(var p : ptree);far;

      begin
         firstpass(p^.left);

         if codegenerror then
           exit;

         if (p^.left^.location.loc<>LOC_MEM) and
            (p^.left^.location.loc<>LOC_REFERENZ) then
           error(error_in_expression);
         p^.resulttype:=p^.vs^.definition;
         p^.location:=p^.left^.location;
         p^.registers32:=p^.left^.registers32;
      end;

    procedure firstselfn(var p : ptree);far;

      begin
         p^.location.loc:=LOC_REFERENZ;
      end;

    procedure firsttypen(var p : ptree);far;

      begin
         error(typeid_here_not_allowed);
      end;

    procedure firsthnewn(var p : ptree);far;

      begin
      end;

    procedure firsthdisposen(var p : ptree);far;

      begin
         { Standardeinleitung }
         firstpass(p^.left);

         if codegenerror then
           exit;

         p^.registers32:=p^.left^.registers32;
         p^.registersfpu:=p^.left^.registersfpu;
         if p^.registers32<1 then
           p^.registers32:=1;
         {
         if p^.left^.location.loc<>LOC_REFERENZ then
           error(error_in_expression);
         }
         p^.location.loc:=LOC_REFERENZ;
         p^.resulttype:=ppointerdef(p^.left^.resulttype)^.definition;
      end;

    procedure firstnewn(var p : ptree);far;

      begin
         { Standardeinleitung }
         firstpass(p^.left);
         {
           unnötig da nichts Weltbewegendes danach geschieht }
         if codegenerror then
           exit;
         p^.registers32:=p^.left^.registers32;
         p^.registersfpu:=p^.left^.registersfpu;
         { Resultattyp ist schon gesetzt }
         p^.location.loc:=LOC_REGISTER;
      end;

    procedure firstsimplenewdispose(var p : ptree);far;

      begin
         { no special "effects" }
         firstpass(p^.left);

         { check the type }
         if p^.left^.resulttype^.deftype<>pointerdef then
           error(pointer_expect);
         if (p^.left^.location.loc<>LOC_REFERENZ) and
            (p^.left^.location.loc<>LOC_CREGISTER) then
           error(error_in_expression);

         p^.registers32:=p^.left^.registers32;
         p^.registersfpu:=p^.left^.registersfpu;
         p^.resulttype:=voiddef;
      end;

    procedure firstsetcons(var p : ptree);far;

      var
         hp : ptree;

      begin
         p^.location.loc:=LOC_MEM;
         hp:=p^.left;
         p^.registers32:=0;
         p^.registersfpu:=0;
         while hp<>nil do
           begin
              firstpass(hp^.left);

              if codegenerror then
                exit;

              p^.registers32:=max(p^.registers32,p^.left^.registers32);
              p^.registersfpu:=max(p^.registersfpu,p^.left^.registersfpu);;
              hp:=hp^.right;
           end;
         { Resulttattyp ist schon gesetzt }
      end;

    procedure firstin(var p : ptree);far;

      begin
         p^.location.loc:=LOC_FLAGS;
         p^.resulttype:=booldef;

         firstpass(p^.right);
         if codegenerror then
           exit;

         if p^.right^.resulttype^.deftype<>setdef then
           error(set_expected);

         firstpass(p^.left);
         if codegenerror then
           exit;

         p^.left:=gentypeconvnode(p^.left,psetdef(p^.right^.resulttype)^.setof);

         firstpass(p^.left);
         if codegenerror then
           exit;

         p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
         p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
      end;

    { !!!!!!!!!!!! unused }
    procedure firstexpr(var p : ptree);far;

      begin
         firstpass(p^.left);
         if codegenerror then
           exit;
         p^.registers32:=p^.left^.registers32;
         if (aktexprlevel<1) and (p^.left^.resulttype<>pdef(voiddef)) then
           error(error_in_expression);
      end;

    procedure firstblock(var p : ptree);far;

      var
         hp : ptree;
         count : longint;

      begin
         p^.registers32:=0;
         count:=0;
         hp:=p^.left;
         while assigned(hp) do
           begin
              if cs_maxoptimieren in aktswitches then
                begin
                   { Codeumstellungen }

                   { Funktionsresultate an exit anhängen }
                   if assigned(hp^.left) and
                      (hp^.left^.right^.treetype=exitn) and
                      (hp^.right^.treetype=assignn) and
                      (hp^.right^.left^.treetype=funcretn) then
                      begin
                         if assigned(hp^.left^.right^.left) then
                           warning(inefficient_code)
                         else
                           begin
                              hp^.left^.right^.left:=getcopy(hp^.right^.right);
                              disposetree(hp^.right);
                              hp^.right:=nil;
                           end;
                      end
                   { warning if unreachable code occurs and elimate this }
                   else if ((hp^.right^.treetype=exitn) or
                       (hp^.right^.treetype=breakn) or
                       (hp^.right^.treetype=continuen) or
                       (hp^.right^.treetype=goton)) and
                       assigned(hp^.left) and
                       (hp^.left^.treetype<>labeln) then
                         begin
                            { use correct line number }
                            inputstack:=hp^.left^.inputfile;
                            inputstack^.line_no:=hp^.left^.line;

                            disposetree(hp^.left);
                            hp^.left:=nil;
                            warning(unreachable_code);

                            { old lines }
                            inputstack:=hp^.right^.inputfile;
                            inputstack^.line_no:=hp^.right^.line;
                         end;
                end;
              if assigned(hp^.right) then
                begin
                   cleartempgen;
                   firstpass(hp^.right);
                   if codegenerror then
                     exit;

                   hp^.registers32:=hp^.right^.registers32;
                end
              else
                hp^.registers32:=0;

              if hp^.registers32>p^.registers32 then
                p^.registers32:=hp^.registers32;

              inc(count);
              hp:=hp^.left;
           end;
         { p^.registers32:=round(p^.registers32/count); }
      end;

    procedure first_while_repeat(var p : ptree);far;

      var
         old_t_times : longint;

      begin
         old_t_times:=t_times;

         { Registergewichtung bestimmen }
         if not(cs_littlesize in aktswitches ) then
           t_times:=t_times*8;

         cleartempgen;
         firstpass(p^.left);
         if codegenerror then
           exit;
         if not((p^.left^.resulttype^.deftype=grunddef) and
            (pgrunddef(p^.left^.resulttype)^.typ=bool8bit)) then
            begin
               error(type_mismatch);
               exit;
            end;

         p^.registers32:=p^.left^.registers32;

         { Schleifenanweisung }
         if assigned(p^.right) then
           begin
              cleartempgen;
              firstpass(p^.right);
              if codegenerror then
                exit;

              if p^.registers32<p^.right^.registers32 then
                p^.registers32:=p^.right^.registers32;
           end;

         t_times:=old_t_times;
      end;

    procedure firstif(var p : ptree);far;

      var
         old_t_times : longint;

      begin
         old_t_times:=t_times;

         cleartempgen;
         firstpass(p^.left);
         if codegenerror then
           exit;
         if not((p^.left^.resulttype^.deftype=grunddef) and
            (pgrunddef(p^.left^.resulttype)^.typ=bool8bit)) then
            begin
               error(type_mismatch);
               exit;
            end;

         p^.registers32:=p^.left^.registers32;
         { Registergewichtung bestimmen }
         if not(cs_littlesize in aktswitches ) then
           t_times:=t_times div 2;
         if t_times=0 then
           t_times:=1;

         { if-Bedingung erfüllt }
         if assigned(p^.right) then
           begin
              cleartempgen;
              firstpass(p^.right);
              if codegenerror then
                exit;

              if p^.registers32<p^.right^.registers32 then
                p^.registers32:=p^.right^.registers32;
           end;

         { else-Zweig }
         if assigned(p^.t1) then
           begin
              cleartempgen;
              firstpass(p^.t1);
              if codegenerror then
                exit;

              if p^.registers32<p^.t1^.registers32 then
                p^.registers32:=p^.t1^.registers32;
           end;
         t_times:=old_t_times;
      end;

    procedure firstexitn(var p : ptree);far;

      begin
         if assigned(p^.left) then
           begin
              firstpass(p^.left);
              p^.registers32:=p^.left^.registers32;
              p^.registersfpu:=p^.left^.registersfpu;
           end
         else
           begin
              p^.registers32:=0;
              p^.registersfpu:=0;
           end;
      end;

    procedure firstfor(var p : ptree);far;

      var
         old_t_times : longint;

      begin
         { Registergewichtung bestimmen
           (nicht genau), }
         old_t_times:=t_times;
         if not(cs_littlesize in aktswitches ) then
           t_times:=t_times*8;

         { Fehler im Anweisungsblock sind egal }
         cleartempgen;
         firstpass(p^.t1);
         p^.registers32:=p^.t1^.registers32;
         p^.registersfpu:=p^.t1^.registersfpu;

         if p^.left^.treetype<>assignn then
           error(error_in_expression);

         { Laufvariable retten }
         p^.t2:=getcopy(p^.left^.left);

         { Laufvar. auf Gültigkeit prüfen: }
         if (p^.t2^.treetype<>loadn) then
           error(invalid_for_var);

         if (not(is_ordinal(p^.t2^.resulttype))) then
           error(ordinal_expect);

         cleartempgen;
         firstpass(p^.left);
         if p^.left^.registers32>p^.registers32 then
           p^.registers32:=p^.left^.registers32;
         if p^.left^.registersfpu>p^.registersfpu then
           p^.registersfpu:=p^.left^.registersfpu;

         cleartempgen;
         firstpass(p^.t2);
         if p^.t2^.registers32>p^.registers32 then
           p^.registers32:=p^.t2^.registers32;
         if p^.t2^.registersfpu>p^.registersfpu then
           p^.registersfpu:=p^.t2^.registersfpu;

         cleartempgen;
         firstpass(p^.right);
         if p^.right^.treetype<>ordconstn then
           begin
              p^.right:=gentypeconvnode(p^.right,p^.t2^.resulttype);
              cleartempgen;
              firstpass(p^.right);
           end;

         if p^.right^.registers32>p^.registers32 then
           p^.registers32:=p^.right^.registers32;
         if p^.right^.registersfpu>p^.registersfpu then
           p^.registersfpu:=p^.right^.registersfpu;
         t_times:=old_t_times;
      end;

    procedure firstasm(var p : ptree);far;

      begin
         { it's a f... to determine the used registers }
         p^.registers32:=0;
         p^.registersfpu:=0;

         procinfo.uses_asm:=true;
      end;

    procedure firstgoto(var p : ptree);far;

      begin
         p^.registers32:=0;
         p^.registersfpu:=0;
         p^.resulttype:=voiddef;
      end;

    procedure firstlabel(var p : ptree);far;

      begin
         cleartempgen;
         firstpass(p^.left);
         p^.registers32:=p^.left^.registers32;
         p^.registersfpu:=p^.left^.registersfpu;
         p^.resulttype:=voiddef;
      end;

    procedure firstcase(var p : ptree);far;

      var
         old_t_times : longint;
         hp : ptree;

      begin
         { evalutes the case expression }
         cleartempgen;
         firstpass(p^.left);
         if codegenerror then
           exit;
         p^.registers32:=p^.left^.registers32;
         p^.registersfpu:=p^.left^.registersfpu;

         { walk through all instructions }

         {   estimates the repeat of each instruction }
         old_t_times:=t_times;
         if not(cs_littlesize in aktswitches ) then
           begin
              t_times:=t_times div case_count_labels(p^.nodes);
              if t_times<1 then
                t_times:=1;
           end;
         {   first case }
         hp:=p^.right;
         while assigned(hp) do
           begin
              cleartempgen;
              firstpass(hp^.right);

              { searchs max registers }
              if hp^.right^.registers32>p^.registers32 then
                p^.registers32:=hp^.right^.registers32;
              if hp^.right^.registersfpu>p^.registersfpu then
                p^.registersfpu:=hp^.right^.registersfpu;
              hp:=hp^.left;
           end;

         { may be handle else tree }
         if assigned(p^.elseblock) then
           begin
              cleartempgen;
              firstpass(p^.elseblock);
              if codegenerror then
                exit;
              if p^.registers32<p^.elseblock^.registers32 then
                p^.registers32:=p^.elseblock^.registers32;

              if p^.registersfpu<p^.elseblock^.registersfpu then
                p^.registersfpu:=p^.elseblock^.registersfpu;
           end;
         t_times:=old_t_times;

         { there is one register required for the case expression }
         if p^.registers32<1 then p^.registers32:=1;
      end;

    type
       firstpassproc = procedure(var p : ptree);

    procedure firstpass(var p : ptree);

      const
         procedures : array[addn..simplenewn] of firstpassproc =
            (firstadd,firstadd,firstadd,firstmoddiv,
             firstmoddiv,firstassignment,firstload,firstrange,
             firstadd,firstadd,firstadd,firstadd,
             firstadd,firstadd,firstin,firstadd,
             firstadd,firstshlshr,firstshlshr,firstadd,
             firstadd,firstsubscriptn,firstderef,firstaddr,
             firstordconst,firsttypeconv,firstcalln,firstnothing,
             firstrealconst,firstumminus,firstasm,firstvecn,
             firststringconst,firstfuncret,firstselfn,
             firstnot,firstinline,firstniln,firsterror,
             firsttypen,firsthnewn,firsthdisposen,firstnewn,
             firstsimplenewdispose,firstnothing,firstsetcons,firstblock,
             firstnothing,firstnothing,firstif,firstnothing,
             firstnothing,first_while_repeat,first_while_repeat,firstfor,
             firstexitn,firstnothing,firstcase,firstlabel,
             firstgoto,firstsimplenewdispose);

      var
         oldcodegenerror : boolean;

      begin
         oldcodegenerror:=codegenerror;
         codegenerror:=false;
         inputstack:=p^.inputfile;
         inputstack^.line_no:=p^.line;

         if not(p^.error) then
           begin
              procedures[p^.treetype](p);
              p^.error:=codegenerror;
              codegenerror:=codegenerror or oldcodegenerror;
           end
         else codegenerror:=true;
      end;

    function do_firstpass(var p : ptree) : boolean;

      var
         { there some calls of do_firstpass in the parser }
         oldis : pinputstack;
         oldnr : longint;

      begin
         oldis:=inputstack;
         oldnr:=inputstack^.line_no;
         codegenerror:=false;
         firstpass(p);
         do_firstpass:=codegenerror;
         inputstack:=oldis;
         inputstack^.line_no:=oldnr;
      end;

end.
[ RETURN TO DIRECTORY ]