{
    $Id$
    Copyright (c) 1993-98 by Florian Klaempfl

    This units exports some routines to manage the parse tree

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

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

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

{$ifdef tp}
  {E+,N+}
{$endif}
unit tree;

  interface

    uses
       objects,globals,symtable,cobjects,verbose,aasm,files
{$ifdef i386}
       ,i386
{$endif}
{$ifdef m68k}
       ,m68k
{$endif}
{$ifdef alpha}
       ,alpha
{$endif}
       ;

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

       pconstset = ^tconstset;

       ttreetyp = (addn,            {Represents the + operator.}
                   muln,            {Represents the * operator.}
                   subn,            {Represents the - operator.}
                   divn,            {Represents the div operator.}
                   symdifn,         {Represents the >< operator.}
                   modn,            {Represents the mod operator.}
                   assignn,         {Represents an assignment.}
                   loadn,           {Represents the use of a variabele.}
                   rangen,          {Represents a range (i.e. 0..9).}
                   ltn,             {Represents the < operator.}
                   lten,            {Represents the <= operator.}
                   gtn,             {Represents the > operator.}
                   gten,            {Represents the >= operator.}
                   equaln,          {Represents the = operator.}
                   unequaln,        {Represents the <> operator.}
                   inn,             {Represents the in operator.}
                   orn,             {Represents the or operator.}
                   xorn,            {Represents the xor operator.}
                   shrn,            {Represents the shr operator.}
                   shln,            {Represents the shl operator.}
                   slashn,          {Represents the / operator.}
                   andn,            {Represents the and operator.}
                   subscriptn,      {??? Field in a record/object?}
                   derefn,          {Dereferences a pointer.}
                   addrn,           {Represents the @ operator.}
                   doubleaddrn,     {Represents the @@ operator.}
                   ordconstn,       {Represents an ordinal value.}
                   typeconvn,       {Represents type-conversion/typecast.}
                   calln,           {Represents a call node.}
                   callparan,       {Represents a parameter.}
                   realconstn,      {Represents a real value.}
                   fixconstn,       {Represents a fixed value.}
                   umminusn,        {Represents a sign change (i.e. -2).}
                   asmn,            {Represents an assembler node }
                   vecn,            {Represents array indexing.}
                   stringconstn,    {Represents a string constant.}
                   funcretn,        {Represents the function result var.}
                   selfn,           {Represents the self parameter.}
                   notn,            {Represents the not operator.}
                   inlinen,         {Internal procedures (i.e. writeln).}
                   niln,            {Represents the nil pointer.}
                   errorn,          {This part of the tree could not be
                                     parsed because of a compiler error.}
                   typen,           {A type name. Used for i.e. typeof(obj).}
                   hnewn,           {The new operation, constructor call.}
                   hdisposen,       {The dispose operation with destructor call.}
                   newn,            {The new operation, constructor call.}
                   simpledisposen,  {The dispose operation.}
                   setelen,         {A set element (i.e. [a,b]).}
                   setconstrn,      {A set constant (i.e. [1,2]).}
                   blockn,          {A block of statements.}
                   anwein,          {A linear list of nodes.}
                   loopn,           { used in genloopnode, must be converted }
                   ifn,             {An if statement.}
                   breakn,          {A break statement.}
                   continuen,       {A continue statement.}
                   repeatn,         {A repeat until block.}
                   whilen,          {A while do statement.}
                   forn,            {A for loop.}
                   exitn,           {An exit statement.}
                   withn,           {A with statement.}
                   casen,           {A case statement.}
                   labeln,          {A label.}
                   goton,           {A goto statement.}
                   simplenewn,      {The new operation.}
                   tryexceptn,      {A try except block.}
                   raisen,          {A raise statement.}
                   switchesn,       {??? Currently unused...}
                   tryfinallyn,     {A try finally statement.}
                   isn,             {Represents the is operator.}
                   asn,             {Represents the as typecast.}
                   caretn,          {Represents the ^ operator.}
                   failn,           {Represents the fail statement.}
                   { added for optimizations where we cannot suppress }
                   nothingn,
                   loadvmtn);       {???.}

       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_string_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_s32bit_2_u32bit,tc_s16bit_2_u32bit,
                      tc_s8bit_2_u32bit,tc_u16bit_2_u32bit,
                      tc_u8bit_2_u32bit,tc_u32bit_2_s32bit,
                      tc_u32bit_2_s8bit,tc_u32bit_2_u8bit,
                      tc_u32bit_2_s16bit,tc_u32bit_2_u16bit,
                      tc_int_2_real,tc_real_2_fix,
                      tc_fix_2_real,tc_int_2_fix,tc_real_2_real,
                      tc_chararray_2_string,tc_bool_2_u8bit,
                      tc_proc2procvar,
                      tc_cchar_charpointer);

       { allows to determine which elementes are to be replaced }
       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,
                      dt_with);

      { different assignment types }

      tassigntyp = (at_normal,at_plus,at_minus,at_star,at_slash);

      pcaserecord = ^tcaserecord;

      tcaserecord = record

          { range }
          _low,_high : longint;

          { only used by gentreejmp }
          _at : plabel;

          { label of instruction }
          statement : plabel;

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

       ptree = ^ttree;

       ttree = record
          error : boolean;
          disposetyp : tdisposetyp;
          { is true, if the right and left operand are swaped }
          swaped : boolean;

          { the location of the result of this node }
          location : tlocation;

          { the number of registers needed to evalute the node }
          registers32,registersfpu : longint;  { must be longint !!!! }
{$ifdef SUPPORT_MMX}
                  registersmmx : longint;
{$endif SUPPORT_MMX}
          left,right : ptree;
          resulttype : pdef;
          inputfile : pinputfile;
          {$ifdef TP}
          line:word;
          {$else}
          line : longint;
          {$endif}
          pragmas : Tcswitches;
{$ifdef extdebug}
        firstpasscount : longint;
{$endif extdebug}
          case treetype : ttreetyp of
             callparan : (is_colon_para : boolean;exact_match_found : boolean);
             assignn : (assigntyp : tassigntyp);
             loadn : (symtableentry : psym;symtable : psymtable;
                      is_absolute,is_first : boolean);
             calln : (symtableprocentry : pprocsym;
                      symtableproc : psymtable;procdefinition : pprocdef;
                      methodpointer : ptree;
                      unit_specific : boolean);
             ordconstn : (value : longint);
             realconstn : (valued : bestreal;labnumber : longint;realtyp : tait);
             fixconstn : (valuef: longint);
{$ifdef TEST_FUNCRET}
             funcretn : (funcretprocinfo : pointer;retdef : pdef);
{$endif TEST_FUNCRET}
             subscriptn : (vs : pvarsym);
             vecn : (memindex,memseg:boolean);
             stringconstn : (values : pstring;labstrnumber : longint);
             typeconvn : (convtyp : tconverttype;explizit : boolean);
             inlinen : (inlinenumber : longint);
             { procinlinen : (proc : pprocsym); }
             setconstrn : (constset : pconstset);
             loopn : (t1,t2 : ptree;backward : boolean);
             asmn : (p_asm : paasmoutput);
             casen : (nodes : pcaserecord;elseblock : ptree);
             labeln,goton : (labelnr : plabel);
             withn : (withsymtable : psymtable;tablecount : longint);
           end;

    procedure init_tree;
    function gennode(t : ttreetyp;l,r : ptree) : ptree;
    function genlabelnode(t : ttreetyp;nr : plabel) : 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 genfixconstnode(v : longint;def : pdef) : ptree;
    function gentypeconvnode(node : ptree;t : pdef) : ptree;
    function gencallparanode(expr,next : ptree) : ptree;
    function genrealconstnode(v : bestreal) : 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 genprocinlinenode(code : ptree;procsym : pprocsym) : ptree;
   }
    function gentypedconstloadnode(sym : ptypedconstsym;st : psymtable) : ptree;
    function genenumnode(v : penumsym) : ptree;
    function genselfnode(_class : pdef) : ptree;
    function gensetconstruktnode(s : pconstset;settype : psetdef) : ptree;
    function genloopnode(t : ttreetyp;l,r,n1: ptree;back : boolean) : ptree;
    function genasmnode(p_asm : paasmoutput) : ptree;
    function gencasenode(l,r : ptree;nodes : pcaserecord) : ptree;
    function genwithnode(symtable : psymtable;l,r : ptree;count : longint) : ptree;

    function getcopy(p : ptree) : ptree;

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

    procedure disposetree(p : ptree);
    procedure putnode(p : ptree);
    function getnode : ptree;
    procedure clearnodes;
    procedure set_location(var destloc,sourceloc : tlocation);
    procedure swap_location(var destloc,sourceloc : tlocation);
    procedure set_file_line(from,_to : ptree);

{$ifdef extdebug}
    const
       maxfirstpasscount : longint = 0;
{$endif extdebug}

{$I innr.inc}

  implementation

    const
       oldswitches : tcswitches = [];

{****************************************************************************
        this is a pool for the tree nodes to get more performance
 ****************************************************************************}

    var
       root : ptree;

    procedure init_tree;

      begin
         root:=nil;
      end;

    procedure clearnodes;

      var
         hp : ptree;

      begin
         hp:=root;
         while assigned(hp) do
           begin
              root:=hp^.left;
              dispose(hp);
              hp:=root;
           end;
      end;

    function getnode : ptree;

      var
         hp : ptree;

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

         { makes error tracking easier }
         fillchar(hp^,sizeof(ttree),#0);
         hp^.location.loc:=LOC_INVALID;

         { new node is error free }
         hp^.error:=false;

         { we know also the position }
         hp^.line:=current_module^.current_inputfile^.line_no;
         hp^.inputfile:=current_module^.current_inputfile;
         hp^.pragmas:=aktswitches;
         getnode:=hp;
      end;

    procedure putnode(p : ptree);

      begin
         { clean up the contents of a node }
         if p^.treetype=asmn then
           if assigned(p^.p_asm) then
             dispose(p^.p_asm,done);

         if p^.treetype=setconstrn then
          if assigned(p^.constset) then
            dispose(p^.constset);

         if (p^.location.loc=LOC_MEM) or (p^.location.loc=LOC_REFERENCE) and
           assigned(p^.location.reference.symbol) then
           stringdispose(p^.location.reference.symbol);

         if p^.disposetyp=dt_string then
           stringdispose(p^.values);
{$ifdef extdebug}
         if p^.firstpasscount>maxfirstpasscount then
            maxfirstpasscount:=p^.firstpasscount;
         dispose(p);
{$else extdebug}
         p^.left:=root;
         root:=p;
{$endif extdebug}
      end;

    function getcopy(p : ptree) : ptree;

      var
         hp : ptree;

      begin
         hp:=getnode;
         hp^:=p^;
         if assigned(p^.location.reference.symbol) then
           hp^.location.reference.symbol:=stringdup(p^.location.reference.symbol^);
         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_constset :
              begin
                 if assigned(p^.constset) then
                   begin
                      dispose(p^.constset);
                      p^.constset:=nil;
                   end;
                 if assigned(p^.left) then
                   disposetree(p^.left);
              end;
            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;
            dt_with :
              begin
                 if assigned(p^.left) then
                   disposetree(p^.left);
                 if assigned(p^.right) then
                   disposetree(p^.right);
                 if assigned(p^.withsymtable) then
                   dispose(p^.withsymtable,done);
              end;
            else internalerror(12);
         end;
         putnode(p);
      end;

    procedure set_file_line(from,_to : ptree);

      begin
         if from<>nil then
           begin
              _to^.line:=from^.line;
              _to^.inputfile:=from^.inputfile;
           end;
      end;

   function genwithnode(symtable : psymtable;l,r : ptree;count : longint) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_with;
         p^.treetype:=withn;
         p^.left:=l;
         p^.right:=r;
         p^.registers32:=0;
         { p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=nil;
         p^.withsymtable:=symtable;
         p^.tablecount:=count;
         set_file_line(l,p);
         genwithnode:=p;
      end;

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

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_nothing;
         p^.treetype:=fixconstn;
         p^.registers32:=0;
         { p^.registers16:=0;
         p^.registers8:=0; }
         p^.registersfpu:=0;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=def;
         p^.value:=v;
         genfixconstnode:=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; }
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.registersfpu:=0;
         p^.resulttype:=nil;
         p^.exact_match_found:=false;
         p^.is_colon_para:=false;
         set_file_line(expr,p);
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=nil;
         set_file_line(l,p);
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=nil;
         set_file_line(l,p);
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=def;
         p^.value:=v;
         genordinalconstnode:=p;
      end;

    function genenumnode(v : penumsym) : 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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=v^.definition;
         p^.value:=v^.value;
         genenumnode:=p;
      end;

    function genrealconstnode(v : bestreal) : 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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
{$ifdef i386}
         p^.resulttype:=c64floatdef;
         p^.valued:=v;
         { default value is double }
         p^.realtyp:=ait_real_64bit;
{$endif}
{$ifdef m68k}
         p^.resulttype:=new(pfloatdef,init(s32real));
         p^.valued:=v;
         { default value is double }
         p^.realtyp:=ait_real_32bit;
{$endif}
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=cstringdef;
         p^.values:=stringdup(s);
         p^.labstrnumber:=-1;
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=nil;
         gensinglenode:=p;
      end;

    function genasmnode(p_asm : paasmoutput) : 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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=8;
{$endif SUPPORT_MMX}
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.treetype:=loadn;
         p^.resulttype:=v^.definition;
         p^.symtableentry:=v;
         p^.symtable:=st;
         p^.is_first := False;
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         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^.convtyp:=tc_equal;
         p^.registersfpu:=0;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=t;
         p^.convtyp:=tc_equal;
         p^.explizit:=false;
         set_file_line(node,p);
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.treetype:=calln;
         p^.symtableprocentry:=v;
         p^.symtableproc:=st;
         p^.unit_specific:=false;
         p^.disposetyp := dt_leftright;
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=nil;
         genzeronode:=p;
      end;

   function genlabelnode(t : ttreetyp;nr : plabel) : 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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=nil;
         { for security }
         { nr^.is_used:=true;}
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         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;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=nil;
         geninlinenode:=p;
      end;


{    function genprocinlinenode(code : ptree;proc : pprocsym) : ptree;

      var
         p : ptree;

      begin
         p:=getnode;
         p^.disposetyp:=dt_inlinen;
         p^.treetype:=inlinen;
         p^.inlineproc:=proc;
         p^.left:=code;
         p^.registers32:=code^.registers32;
         p^.registersfpu:=code^.registersfpu;
$ifdef SUPPORT_MMX
         p^.registersmmx:=0;
$endif SUPPORT_MMX
         p^.resulttype:=proc^.definition^.returntype;
         genprocinlinenode:=p;
      end; }

   function gensetconstruktnode(s : pconstset;settype : psetdef) : ptree;

     var
        p : ptree;

     begin
        p:=getnode;
        p^.disposetyp:=dt_constset;
        p^.treetype:=setconstrn;
        p^.registers32:=0;
        p^.registersfpu:=0;
{$ifdef SUPPORT_MMX}
         p^.registersmmx:=0;
{$endif SUPPORT_MMX}
         p^.resulttype:=settype;
         p^.left:=nil;
         new(p^.constset);
         p^.constset^:=s^;
         gensetconstruktnode:=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)
                        { not necessary
                                     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;

    {This is needed if you want to be able to delete the string with the nodes !!}
    procedure set_location(var destloc,sourceloc : tlocation);

      begin
        if assigned(destloc.reference.symbol) then
          stringdispose(destloc.reference.symbol);
        destloc:= sourceloc;
        if sourceloc.loc in [LOC_MEM,LOC_REFERENCE] then
          begin
             if assigned(sourceloc.reference.symbol) then
               destloc.reference.symbol:=
                 stringdup(sourceloc.reference.symbol^);
          end
        else
          destloc.reference.symbol:=nil;
      end;

    procedure swap_location(var destloc,sourceloc : tlocation);

      var
         swapl : tlocation;

      begin
         swapl := destloc;
         destloc := sourceloc;
         sourceloc := swapl;
      end;
end.
{
  $Log$
  Revision 1.2  1998-04-07 22:45:05  florian
    * bug0092, bug0115 and bug0121 fixed
    + packed object/class/array

  Revision 1.1.1.1  1998/03/25 11:18:13  root
  * Restored version

  Revision 1.15  1998/03/24 21:48:36  florian
    * just a couple of fixes applied:
         - problem with fixed16 solved
         - internalerror 10005 problem fixed
         - patch for assembler reading
         - small optimizer fix
         - mem is now supported

  Revision 1.14  1998/03/10 16:27:46  pierre
    * better line info in stabs debug
    * symtabletype and lexlevel separated into two fields of tsymtable
    + ifdef MAKELIB for direct library output, not complete
    + ifdef CHAINPROCSYMS for overloaded seach across units, not fully
      working
    + ifdef TESTFUNCRET for setting func result in underfunction, not
      working

  Revision 1.13  1998/03/10 01:17:30  peter
    * all files have the same header
    * messages are fully implemented, EXTDEBUG uses Comment()
    + AG... files for the Assembler generation

  Revision 1.12  1998/03/02 01:49:37  peter
    * renamed target_DOS to target_GO32V1
    + new verbose system, merged old errors and verbose units into one new
      verbose.pas, so errors.pas is obsolete

  Revision 1.11  1998/02/27 09:26:18  daniel
  * Changed symtable handling so no junk symtable is put on the symtablestack.

  Revision 1.10  1998/02/13 10:35:54  daniel
  * Made Motorola version compilable.
  * Fixed optimizer

  Revision 1.9  1998/02/12 11:50:51  daniel
  Yes! Finally! After three retries, my patch!

  Changes:

  Complete rewrite of psub.pas.
  Added support for DLL's.
  Compiler requires less memory.
  Platform units for each platform.

  Revision 1.8  1998/02/04 14:39:31  florian
    * small clean up

  Revision 1.7  1998/01/13 23:11:16  florian
    + class methods

  Revision 1.6  1998/01/11 04:16:36  carl
  + correct floating point support for m68k

  Revision 1.5  1998/01/07 00:17:11  michael
  Restored released version (plus fixes) as current

  Revision 1.3  1997/12/04 12:02:15  pierre
     + added a counter of max firstpass's for a ptree
       for debugging only in ifdef extdebug

  Revision 1.2  1997/11/29 15:43:08  florian
  * some minor changes

  Revision 1.1.1.1  1997/11/27 08:33:03  michael
  FPC Compiler CVS start

  Pre-CVS log:

    CEC    Carl-Eric Codere
    FK     Florian Klaempfl
    PM     Pierre Muller
    +      feature added
    -      removed
    *      bug fixed or changed

    History:
        19th october 1996:
            + adapted to version 0.9.0
         6th september 1997:
            + added support for MC68000 (CEC)
         3rd october 1997:
            + added tc_bool_2_u8bit for in_ord_x (PM)
         3rd november1997:
            + added symdifn for sets (PM)
         13th november 1997:
            + added partial code for u32bit support (PM)
}

