Metropoli BBS
VIEWER: tree.pas MODE: TEXT (CP437)
{$ifdef tp}
{E+,N+}
{$endif}
{****************************************************************************

                     Copyright (c) 1993,96 by Florian Klämpfl

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

unit tree;

  interface

    uses
       objects,globals,symtable,cobjects,asmgen;

    type
       tconstset = array[0..31] of byte;
       
       pconstset = ^tconstset;

       ttreetyp = (addn,muln,subn,divn,
                   modn,assignn,loadn,rangen,
                   ltn,lten,gtn,gten,
                   equaln,unequaln,inn,orn,
                   xorn,shrn,shln,slashn,
                   andn,subscriptn,derefn,addrn,
                   ordconstn,typeconvn,calln,callparan,
                   realconstn,umminusn,asmn,vecn,
                   stringconstn,funcretn,selfn,
                   notn,inlinen,niln,errorn,
                   typen,hnewn,hdisposen,newn,
                   simpledisposen,setelen,setconstrn,blockn,
                   anwein,loopn,ifn,breakn,
                   continuen,repeatn,whilen,forn,
                   exitn,withn,casen,labeln,
                   goton,simplenewn);

       tconverttype = (tc_equal,tc_not_possible,tc_u8bit_2_s32bit,
                       tc_only_rangechecks32bit,tc_s8bit_2_s32bit,
                       tc_u16bit_2_s32bit,tc_s16bit_2_s32bit,
                       tc_s32bit_2_s16bit,tc_s32bit_2_u8bit,
                       tc_s32bit_2_u16bit,tc_string_to_string,
                       tc_cstring_charpointer,tc_cstring_chararray,
                       tc_array_to_pointer,tc_pointer_to_array,
                       tc_char_to_string,tc_u8bit_2_s16bit,
                       tc_u8bit_2_u16bit,tc_s8bit_2_s16bit,
                       tc_s16bit_2_s8bit,tc_s16bit_2_u8bit,
                       tc_u16bit_2_s8bit,tc_u16bit_2_u8bit,
                       tc_s8bit_2_u16bit,tc_s32bit_2_s8bit,
                       tc_int_2_real,tc_cchar_chararray);

       { gibt an, welche Nachfolger eines Knotens }
       { gelöscht werden müssen }
       tdisposetyp = (dt_nothing,dt_leftright,dt_left,
                      dt_mbleft,dt_string,dt_typeconv,dt_inlinen,
                      dt_mbleft_and_method,dt_constset,dt_loop,dt_case);

       plocation = ^tlocation;

       { Angabe über den Ort eines Operanden im Speicher }
       { LOC_FPU_STACK   auf dem FPU-Stack }
       { LOC_REGISTER    in Prozessorregister }
       { LOC_MEM         im Speicher }
       { LOC_REFERENZ    wie LOC_MEM, nur gleichzeitig lvalue }
       { LOC_JUMP        nur bool'sche Resultate, Sprung zu false- oder }
       {                 truelabel }
       { LOC_FLAGS       nur bool'sche Rsultate, Flags sind gesetzt }
       { LOC_CREGISTER   Register, das nicht verändert werden darf }

       tloc = (LOC_FPUSTACK,LOC_REGISTER,LOC_MEM,LOC_REFERENZ,LOC_JUMP,
               LOC_FLAGS,LOC_CREGISTER);

       tresflags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,
                    F_A,F_AE,F_B,F_BE);

       tlocation = record
          case loc : tloc of
             LOC_REGISTER : (register : tregister);
             LOC_MEM,LOC_REFERENZ : (referenz : treferenz);
             LOC_FPUSTACK : ();
             LOC_JUMP : ();
             LOC_FLAGS : (resflags : tresflags);
       end;

       pcaserecord = ^tcaserecord;

       tcaserecord = record

          { range }
          low,high : longint;

          { only used by gentreejmp }
          at : longint;

          { lable of instruction }
          anweisung : longint;

          { left and right tree node }
          less,greater : pcaserecord;
       end;

       ptree = ^ttree;

       ttree = record
          error : boolean;
          disposetyp : tdisposetyp;
          swaped : boolean; { wird auf true gesetzt, wenn linker und }
                            { rechter Operand vertauscht sind        }
          location : tlocation;
          registers32,registersfpu : integer;
          left,right : ptree;
          resulttype : pdef;
          inputfile : pinputstack;
          line : longint;
          case treetype : ttreetyp of
             callparan : (is_colon_para : boolean);
             loadn : (symtableentry : psym;symtable : psymtable);
             calln : (symtableprocentry : pprocsym;
                      symtableproc : psymtable;procdefinition : pprocdef;
                      methodpointer : ptree);
             ordconstn : (value : longint);
             realconstn : (valued : double;labnumber : longint);
             subscriptn : (vs : pvarsym);
             stringconstn : (values : pstring);
             typeconvn : (convtyp : tconverttype;explizit : boolean);
             inlinen : (inlinenumber : longint);
             setconstrn : (constset : pconstset);
             loopn : (t1,t2 : ptree;backward : boolean);
             asmn : (p_asm : pasmlist);
             casen : (nodes : pcaserecord;elseblock : ptree;ranges : boolean);
             labeln,goton : (labelnr : longint);
       end;

    procedure init_tree;
    function gennode(t : ttreetyp;l,r : ptree) : ptree;
    function genlabelnode(t : ttreetyp;nr : longint) : ptree;
    function genloadnode(v : pvarsym;st : psymtable) : ptree;
    function gensinglenode(t : ttreetyp;l : ptree) : ptree;
    function gensubscriptnode(varsym : pvarsym;l : ptree) : ptree;
    function genordinalconstnode(v : longint;def : pdef) : ptree;
    function gentypeconvnode(node : ptree;t : pdef) : ptree;
    function gencallparanode(expr,next : ptree) : ptree;
    function genrealconstnode(v : double) : ptree;
    function gencallnode(v : pprocsym;st : psymtable) : ptree;
    function genmethodcallnode(v : pprocsym;st : psymtable;mp : ptree) : ptree;
    function genstringconstnode(const s : string) : ptree;
    function genzeronode(t : ttreetyp) : ptree;
    function geninlinenode(number : longint;l : ptree) : ptree;
    function gentypedconstloadnode(sym : ptypedconstsym;st : psymtable) : ptree;
    function genaufzaehlnode(v : paufzaehlsym) : ptree;
    function genselfnode(_class : pdef) : ptree;
    function gensetconstruktnode(settype : pdef;p : pconstset) : ptree;
    function genloopnode(t : ttreetyp;l,r,n1: ptree;back : boolean) : ptree;
    function genasmnode(p_asm : pasmlist) : ptree;
    function gencasenode(l,r : ptree;nodes : pcaserecord) : ptree;

    function getcopy(p : ptree) : ptree;

    procedure disposetree(p : ptree);
    procedure putnode(p : ptree);
    function getnode : ptree;

    const
       flag_2_jmp : array[F_E..F_BE] of tasmop =
          (JE,JNE,JG,JL,JGE,JLE,JC,JNC,
           JA,JAE,JB,JBE);

       flag_2_set : array[F_E..F_BE] of tasmop =
          (SETE,SETNE,SETG,SETL,SETGE,SETLE,SETC,SETNC,
           SETA,SETAE,SETB,SETBE);

    {$I INNR.INC}

  implementation

    { eine Poolverwaltung für die Nodes, was die Geschwindigkeit sehr }
    { steigert }

    var
       wurzel : ptree;

    procedure init_tree;

      begin
         wurzel:=nil;
      end;

    function getnode : ptree;

      var
         hp : ptree;

      begin
         if wurzel=nil then new(hp)
         else
           begin
              hp:=wurzel;
              wurzel:=wurzel^.left;
           end;

         { neue Node hat sicher keinen Fehler }
         hp^.error:=false;

         { auch ist die Position bekannt }
         hp^.line:=inputstack^.line_no;
         hp^.inputfile:=inputstack;

         getnode:=hp;
      end;

    procedure putnode(p : ptree);

      begin
         p^.left:=wurzel;
         wurzel:=p;
      end;

    function getcopy(p : ptree) : ptree;

      var
         hp : ptree;

      begin
         hp:=getnode;
         hp^:=p^;
         case p^.disposetyp of
            dt_leftright : begin
                              if assigned(p^.left) then
                                hp^.left:=getcopy(p^.left);
                              if assigned(p^.right) then
                                hp^.right:=getcopy(p^.right);
                           end;
            dt_nothing : ;
            dt_left    : if assigned(p^.left) then
                           hp^.left:=getcopy(p^.left);
            dt_mbleft : if assigned(p^.left) then
                          hp^.left:=getcopy(p^.left);
            dt_mbleft_and_method : begin
                                      if assigned(p^.left) then
                                        hp^.left:=getcopy(p^.left);
                                      hp^.methodpointer:=getcopy(p^.methodpointer);
                                   end;
            dt_loop : begin
                         if assigned(p^.left) then
                           hp^.left:=getcopy(p^.left);
                         if assigned(p^.right) then
                           hp^.right:=getcopy(p^.right);
                         if assigned(p^.t1) then
                           hp^.t1:=getcopy(p^.t1);
                         if assigned(p^.t2) then
                           hp^.t2:=getcopy(p^.t2);
                      end;
            dt_string : hp^.values:=stringdup(p^.values^);
            dt_typeconv : hp^.left:=getcopy(p^.left);
            dt_inlinen : if assigned(p^.left) then
                           hp^.left:=getcopy(p^.left);
            else internalerror(11);
         end;
         getcopy:=hp;
      end;

    procedure deletecaselabels(p : pcaserecord);

      begin
         if assigned(p^.greater) then
           deletecaselabels(p^.greater);
         if assigned(p^.less) then
           deletecaselabels(p^.less);
         dispose(p);
      end;

    procedure disposetree(p : ptree);

      begin
         if not(assigned(p)) then
           exit;
         case p^.disposetyp of
            dt_leftright : begin
                              if assigned(p^.left) then
                                disposetree(p^.left);
                              if assigned(p^.right) then
                                disposetree(p^.right);
                           end;
            dt_case      : begin
                              if assigned(p^.left) then
                                disposetree(p^.left);
                              if assigned(p^.right) then
                                disposetree(p^.right);
                              if assigned(p^.nodes) then
                                deletecaselabels(p^.nodes);
                              if assigned(p^.elseblock) then
                                disposetree(p^.elseblock);
                           end;
            dt_nothing : ;
            dt_left    : if assigned(p^.left) then
                           disposetree(p^.left);
            dt_mbleft : if assigned(p^.left) then
                          disposetree(p^.left);
            dt_mbleft_and_method : begin
                                      if assigned(p^.left) then disposetree(p^.left);
                                        disposetree(p^.methodpointer);
                                   end;
            dt_string : stringdispose(p^.values);
            dt_typeconv : disposetree(p^.left);
            dt_inlinen : if assigned(p^.left) then
                           disposetree(p^.left);
            dt_loop : begin
                         if assigned(p^.left) then
                           disposetree(p^.left);
                         if assigned(p^.right) then
                           disposetree(p^.right);
                         if assigned(p^.t1) then
                           disposetree(p^.t1);
                         if assigned(p^.t2) then
                           disposetree(p^.t2);
                      end;
            else internalerror(12);
         end;
         putnode(p);
      end;

    function gencallparanode(expr,next : ptree) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_leftright;
         p^.treetype:=callparan;
         p^.left:=expr;
         p^.right:=next;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         p^.is_colon_para:=false;
         gencallparanode:=p;
      end;

    function gennode(t : ttreetyp;l,r : ptree) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_leftright;
         p^.treetype:=t;
         p^.left:=l;
         p^.right:=r;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         gennode:=p;
      end;

    function gencasenode(l,r : ptree;nodes : pcaserecord) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_case;
         p^.treetype:=casen;
         p^.left:=l;
         p^.right:=r;
         p^.nodes:=nodes;
         p^.registers32:=0;
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         gencasenode:=p;
      end;

    function genloopnode(t : ttreetyp;l,r,n1 : ptree;back : boolean) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_loop;
         p^.treetype:=t;
         p^.left:=l;
         p^.right:=r;
         p^.t1:=n1;
         p^.t2:=nil;
         p^.registers32:=0;
         p^.backward:=back;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         genloopnode:=p;
      end;

    function genordinalconstnode(v : longint;def : pdef) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_nothing;
         p^.treetype:=ordconstn;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=def;
         p^.value:=v;
         genordinalconstnode:=p;
      end;

    function genaufzaehlnode(v : paufzaehlsym) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_nothing;
         p^.treetype:=ordconstn;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=v^.definition;
         p^.value:=v^.value;
         genaufzaehlnode:=p;
      end;

    function genrealconstnode(v : double) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_nothing;
         p^.treetype:=realconstn;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=cs64realdef;
         p^.valued:=v;
         p^.labnumber:=-1;
         genrealconstnode:=p;
      end;

    function genstringconstnode(const s : string) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_string;
         p^.treetype:=stringconstn;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=cstringdef;
         p^.values:=stringdup(s);
         genstringconstnode:=p;
      end;

    function gensinglenode(t : ttreetyp;l : ptree) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_left;
         p^.treetype:=t;
         p^.left:=l;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         gensinglenode:=p;
      end;

    function genasmnode(p_asm : pasmlist) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_nothing;
         p^.treetype:=asmn;
         p^.registers32:=4;
         p^.p_asm:=p_asm;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=8;
         p^.resulttype:=nil;
         genasmnode:=p;
      end;

    function genloadnode(v : pvarsym;st : psymtable) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.treetype:=loadn;
         p^.resulttype:=v^.definition;
         p^.symtableentry:=v;
         p^.symtable:=st;
         p^.disposetyp:=dt_nothing;
         genloadnode:=p;
      end;

    function gentypedconstloadnode(sym : ptypedconstsym;st : psymtable) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.treetype:=loadn;
         p^.resulttype:=sym^.definition;
         p^.symtableentry:=pvarsym(sym);
         p^.symtable:=st;
         p^.disposetyp:=dt_nothing;
         gentypedconstloadnode:=p;
      end;

    function gentypeconvnode(node : ptree;t : pdef) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_typeconv;
         p^.treetype:=typeconvn;
         p^.left:=node;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=t;
         p^.explizit:=false;
         gentypeconvnode:=p;
      end;

    function gencallnode(v : pprocsym;st : psymtable) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.treetype:=calln;

         p^.symtableprocentry:=v;
         p^.symtableproc:=st;
         p^.disposetyp:=dt_mbleft;
         p^.methodpointer:=nil;
         p^.left:=nil;
         p^.right:=nil;
         p^.procdefinition:=nil;
         gencallnode:=p;
      end;

    function genmethodcallnode(v : pprocsym;st : psymtable;mp : ptree) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.treetype:=calln;

         p^.symtableprocentry:=v;
         p^.symtableproc:=st;
         p^.disposetyp:=dt_mbleft_and_method;
         p^.left:=nil;
         p^.right:=nil;
         p^.methodpointer:=mp;
         p^.procdefinition:=nil;
         genmethodcallnode:=p;
      end;

    function gensubscriptnode(varsym : pvarsym;l : ptree) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_left;
         p^.treetype:=subscriptn;
         p^.left:=l;
         p^.registers32:=0;
         p^.vs:=varsym;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         gensubscriptnode:=p;
      end;

   function genzeronode(t : ttreetyp) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_nothing;
         p^.treetype:=t;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         genzeronode:=p;
      end;

   function genlabelnode(t : ttreetyp;nr : longint) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_nothing;
         p^.treetype:=t;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         p^.labelnr:=nr;
         genlabelnode:=p;
      end;

    function genselfnode(_class : pdef) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_nothing;
         p^.treetype:=selfn;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=_class;
         genselfnode:=p;
      end;

    function geninlinenode(number : longint;l : ptree) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_inlinen;
         p^.treetype:=inlinen;
         p^.left:=l;
         p^.inlinenumber:=number;
         p^.registers32:=0;
{         p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         geninlinenode:=p;
      end;

   function gensetconstruktnode(settype : pdef;p : pconstset) : ptree;

{     var
        p : ptree; }

     begin
{         p:=getnode;
         p^.disposetyp:=dt_constset;
         p^.treetype:=constsetn;
         p^.registers32:=0;
         p^.registersfpu:=0;
         p^.resulttype:=settype;
         p^.setdata:=p;         }
     end;

   function equal_trees(t1,t2 : ptree) : boolean;

     begin
        if t1^.treetype=t2^.treetype then
          begin
             case t1^.treetype of
                addn,
                muln,
                equaln,
                orn,
                xorn,
                andn,
                unequaln:
                   begin
                      equal_trees:=(equal_trees(t1^.left,t2^.left) and
                                    equal_trees(t1^.right,t2^.right)) or
                                   (equal_trees(t1^.right,t2^.left) and
                                    equal_trees(t1^.left,t2^.right));
                   end;
                subn,
                divn,
                modn,
                assignn,
                ltn,
                lten,
                gtn,
                gten,
                inn,
                shrn,
                shln,
                slashn,
                rangen:
                   begin
                      equal_trees:=(equal_trees(t1^.left,t2^.left) and
                                    equal_trees(t1^.right,t2^.right));
                   end;
                umminusn,
                notn,
                derefn,
                addrn:
                   begin
                      equal_trees:=(equal_trees(t1^.left,t2^.left));
                   end;
                loadn:
                   begin
                      equal_trees:=(t1^.symtableentry=t2^.symtableentry)
                                   { unnötig }
                                     and (t1^.symtable=t2^.symtable);
                   end;
                {

                   subscriptn,
                   ordconstn,typeconvn,calln,callparan,
                   realconstn,asmn,vecn,
                   stringconstn,funcretn,selfn,
                   inlinen,niln,errorn,
                   typen,hnewn,hdisposen,newn,
                   disposen,setelen,setconstrn
                }
                else equal_trees:=false;
             end;
          end
        else
          equal_trees:=false;
     end;

end.
[ RETURN TO DIRECTORY ]