Browse Source

+ more changes for the new version

florian 27 years ago
parent
commit
151e5a82cf
7 changed files with 3150 additions and 135 deletions
  1. 322 3
      compiler/new/cgbase.pas
  2. 511 36
      compiler/new/cgobj.pas
  3. 302 0
      compiler/new/pass_1.pas
  4. 271 0
      compiler/new/pp.pas
  5. 1466 0
      compiler/new/psub.pas
  6. 5 2
      compiler/new/systems.pas
  7. 273 94
      compiler/new/tree.pas

+ 322 - 3
compiler/new/cgbase.pas

@@ -25,9 +25,140 @@ unit cgbase;
   interface
 
     uses
-       globtype,cobjects,symtable,aasm
+       globtype,cobjects,aasm,symtable,verbose,tree
 {$I cpuunit.inc}
        ;
+
+    const
+       pi_uses_asm  = $1;       { set, if the procedure uses asm }
+       pi_is_global = $2;       { set, if the procedure is exported by an unit }
+       pi_do_call   = $4;       { set, if the procedure does a call }
+       pi_operator  = $8;       { set, if the procedure is an operator   }
+       pi_C_import  = $10;      { set, if the procedure is an external C function }
+       pi_uses_exceptions = $20;{ set, if the procedure has a try statement => }
+                                { no register variables                        }
+
+    type
+       pprocinfo = ^tprocinfo;
+       tprocinfo = record
+          { pointer to parent in nested procedures }
+          parent : pprocinfo;
+          { current class, if we are in a method }
+          _class : pobjectdef;
+          { return type }
+          retdef : pdef;
+          { return type }
+          sym : pprocsym;
+          { symbol of the function }
+          funcretsym : pfuncretsym;
+          { the definition of the proc itself }
+          { why was this a pdef only ?? PM    }
+          def : pprocdef;
+          { frame pointer offset }
+          framepointer_offset : longint;
+          { self pointer offset }
+          ESI_offset : longint;
+          { result value offset }
+          retoffset : longint;
+
+          { firsttemp position }
+          firsttemp : longint;
+
+          funcret_is_valid : boolean;
+
+          { parameter offset }
+          call_offset : longint;
+
+          { some collected informations about the procedure }
+          { see pi_xxxx above                               }
+          flags : longint;
+
+          { register used as frame pointer }
+          framepointer : tregister;
+
+          { true, if the procedure is exported by an unit }
+          globalsymbol : boolean;
+
+          { true, if the procedure should be exported (only OS/2) }
+          exported : boolean;
+
+          { code for the current procedure }
+          aktproccode,aktentrycode,
+          aktexitcode,aktlocaldata : paasmoutput;
+          { local data is used for smartlink }
+       end;
+
+       { some kind of temp. types needs to be destructed }
+       { for example ansistring, this is done using this }
+       { list                                            }
+       ptemptodestroy = ^ttemptodestroy;
+       ttemptodestroy = object(tlinkedlist_item)
+          typ : pdef;
+          address : treference;
+          constructor init(const a : treference;p : pdef);
+       end;
+
+    var
+       { info about the current sub routine }
+       procinfo : tprocinfo;
+
+       { labels for BREAK and CONTINUE }
+       aktbreaklabel,aktcontinuelabel : plabel;
+
+       { label when the result is true or false }
+       truelabel,falselabel : plabel;
+
+       { label to leave the sub routine }
+       aktexitlabel : plabel;
+
+       { also an exit label, only used we need to clear only the stack }
+       aktexit2label : plabel;
+
+       { only used in constructor for fail or if getmem fails }
+       quickexitlabel : plabel;
+
+       { Boolean, wenn eine loadn kein Assembler erzeugt hat }
+       simple_loadn : boolean;
+
+       { tries to hold the amount of times which the current tree is processed  }
+       t_times : longint;
+
+       { true, if an error while code generation occurs }
+       codegenerror : boolean;
+
+       { this is for open arrays and strings        }
+       { but be careful, this data is in the        }
+       { generated code destroyed quick, and also   }
+       { the next call of secondload destroys this  }
+       { data                                       }
+       { So be careful using the informations       }
+       { provided by this variables                 }
+       highframepointer : tregister;
+       highoffset : longint;
+
+       make_const_global : boolean;
+       temptoremove : plinkedlist;
+
+    { message calls with codegenerror support }
+    procedure cgmessage(const t : tmsgconst);
+    procedure cgmessage1(const t : tmsgconst;const s : string);
+    procedure cgmessage2(const t : tmsgconst;const s1,s2 : string);
+    procedure cgmessage3(const t : tmsgconst;const s1,s2,s3 : string);
+
+    { initialize respectively terminates the code generator }
+    { for a new module or procedure                         }
+    procedure codegen_doneprocedure;
+    procedure codegen_donemodule;
+    procedure codegen_newmodule;
+    procedure codegen_newprocedure;
+
+    { counts the labels }
+    function case_count_labels(root : pcaserecord) : longint;
+    { searches the highest label }
+    function case_get_max(root : pcaserecord) : longint;
+    { searches the lowest label }
+    function case_get_min(root : pcaserecord) : longint;
+
     { clears a location record }
     procedure clear_location(var loc : tlocation);
     { copies a location, takes care of the symbol }
@@ -37,6 +168,192 @@ unit cgbase;
 
   implementation
 
+     uses
+        comphook;
+
+{*****************************************************************************
+            override the message calls to set codegenerror
+*****************************************************************************}
+
+    procedure cgmessage(const t : tmsgconst);
+      var
+         olderrorcount : longint;
+      begin
+         if not(codegenerror) then
+           begin
+              olderrorcount:=status.errorcount;
+              verbose.Message(t);
+              codegenerror:=olderrorcount<>status.errorcount;
+           end;
+      end;
+
+    procedure cgmessage1(const t : tmsgconst;const s : string);
+      var
+         olderrorcount : longint;
+      begin
+         if not(codegenerror) then
+           begin
+              olderrorcount:=status.errorcount;
+              verbose.Message1(t,s);
+              codegenerror:=olderrorcount<>status.errorcount;
+           end;
+      end;
+
+    procedure cgmessage2(const t : tmsgconst;const s1,s2 : string);
+      var
+         olderrorcount : longint;
+      begin
+         if not(codegenerror) then
+           begin
+              olderrorcount:=status.errorcount;
+              verbose.Message2(t,s1,s2);
+              codegenerror:=olderrorcount<>status.errorcount;
+           end;
+      end;
+
+    procedure cgmessage3(const t : tmsgconst;const s1,s2,s3 : string);
+      var
+         olderrorcount : longint;
+      begin
+         if not(codegenerror) then
+           begin
+              olderrorcount:=status.errorcount;
+              verbose.Message3(t,s1,s2,s3);
+              codegenerror:=olderrorcount<>status.errorcount;
+           end;
+      end;
+
+
+{*****************************************************************************
+         initialize/terminate the codegen for procedure and modules
+*****************************************************************************}
+
+    procedure codegen_newprocedure;
+      begin
+         aktbreaklabel:=nil;
+         aktcontinuelabel:=nil;
+         { aktexitlabel:=0; is store in oldaktexitlabel
+           so it must not be reset to zero before this storage !}
+         { the type of this lists isn't important }
+         { because the code of this lists is      }
+         { copied to the code segment             }
+         procinfo.aktentrycode:=new(paasmoutput,init);
+         procinfo.aktexitcode:=new(paasmoutput,init);
+         procinfo.aktproccode:=new(paasmoutput,init);
+         procinfo.aktlocaldata:=new(paasmoutput,init);
+      end;
+
+
+
+    procedure codegen_doneprocedure;
+      begin
+         dispose(procinfo.aktentrycode,done);
+         dispose(procinfo.aktexitcode,done);
+         dispose(procinfo.aktproccode,done);
+         dispose(procinfo.aktlocaldata,done);
+      end;
+
+
+
+    procedure codegen_newmodule;
+      begin
+         exprasmlist:=new(paasmoutput,init);
+         datasegment:=new(paasmoutput,init);
+         codesegment:=new(paasmoutput,init);
+         bsssegment:=new(paasmoutput,init);
+         debuglist:=new(paasmoutput,init);
+         externals:=new(paasmoutput,init);
+         internals:=new(paasmoutput,init);
+         consts:=new(paasmoutput,init);
+         rttilist:=new(paasmoutput,init);
+         importssection:=nil;
+         exportssection:=nil;
+         resourcesection:=nil;
+      end;
+
+
+
+    procedure codegen_donemodule;
+      begin
+         dispose(exprasmlist,done);
+         dispose(codesegment,done);
+         dispose(bsssegment,done);
+         dispose(datasegment,done);
+         dispose(debuglist,done);
+         dispose(externals,done);
+         dispose(internals,done);
+         dispose(consts,done);
+         dispose(rttilist,done);
+         if assigned(importssection) then
+          dispose(importssection,done);
+         if assigned(exportssection) then
+          dispose(exportssection,done);
+         if assigned(resourcesection) then
+          dispose(resourcesection,done);
+      end;
+
+
+{*****************************************************************************
+                              Case Helpers
+*****************************************************************************}
+
+    function case_count_labels(root : pcaserecord) : longint;
+      var
+         _l : longint;
+
+      procedure count(p : pcaserecord);
+        begin
+           inc(_l);
+           if assigned(p^.less) then
+             count(p^.less);
+           if assigned(p^.greater) then
+             count(p^.greater);
+        end;
+
+      begin
+         _l:=0;
+         count(root);
+         case_count_labels:=_l;
+      end;
+
+
+    function case_get_max(root : pcaserecord) : longint;
+      var
+         hp : pcaserecord;
+      begin
+         hp:=root;
+         while assigned(hp^.greater) do
+           hp:=hp^.greater;
+         case_get_max:=hp^._high;
+      end;
+
+
+    function case_get_min(root : pcaserecord) : longint;
+      var
+         hp : pcaserecord;
+      begin
+         hp:=root;
+         while assigned(hp^.less) do
+           hp:=hp^.less;
+         case_get_min:=hp^._low;
+      end;
+
+
+{*****************************************************************************
+                              TTempToDestroy
+*****************************************************************************}
+
+    constructor ttemptodestroy.init(const a : treference;p : pdef);
+      begin
+         inherited init;
+         address:=a;
+         typ:=p;
+      end;
+
+{*****************************************************************************
+            some helper routines to handle locations
+*****************************************************************************}
+
     procedure clear_location(var loc : tlocation);
 
       begin
@@ -78,7 +395,9 @@ unit cgbase;
 end.
 {
   $Log$
-  Revision 1.1  1998-12-15 22:18:55  florian
-    * some code added
+  Revision 1.2  1998-12-26 15:20:28  florian
+    + more changes for the new version
 
+  Revision 1.1  1998/12/15 22:18:55  florian
+    * some code added
 }

+ 511 - 36
compiler/new/cgobj.pas

@@ -25,31 +25,57 @@ unit cgobj;
   interface
 
     uses
-       aasm;
+       cobjects,aasm,symtable
+{$I cpuunit.inc}
+       ;
 
     type
+       qword = comp;
+
        pcg = ^tcg;
        tcg = object
           procedure a_call_name_ext(list : paasmoutput;const s : string;
-            offset : longint;m : texternaltyp);
-
-          procedure g_entrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
+            offset : longint;m : texternal_typ);
+
+          {************************************************}
+          { code generation for subroutine entry/exit code }
+
+          { helper routines }
+          procedure g_initialize_data(p : psym);
+          procedure g_incr_data(p : psym);
+          procedure g_finalize_data(p : psym);
+{$ifndef VALUEPARA}
+          procedure g_copyopenarrays(p : psym);
+{$else}
+          procedure g_copyvalueparas(p : psym);
+{$endif}
+
+          procedure g_entrycode(list : paasmoutput;const proc_names:tstringcontainer;make_global:boolean;
                               stackframe:longint;
                               var parasize:longint;var nostackframe:boolean;
                               inlined : boolean);
 
+          { string helper routines }
+          procedure g_decransiref(const ref : treference);
+
+          procedure g_removetemps(list : paasmoutput;p : plinkedlist);
+
+          {**********************************}
           { these methods must be overriden: }
           procedure a_push_reg(list : paasmoutput;r : tregister);virtual;
           procedure a_call_name(list : paasmoutput;const s : string;
             offset : longint);virtual;
 
-          procedure a_load_const8_ref(list : paasmoutput;b : byte;ref : treference);virtual;
-          procedure a_load_const16_ref(list : paasmoutput;w : word;ref : treference);virtual;
-          procedure a_load_const32_ref(list : paasmoutput;l : longint;ref : treference);virtual;
-          procedure a_load_const64_ref(list : paasmoutput;{ q : qword; }ref : treference);virtual;
+          procedure a_load_const8_ref(list : paasmoutput;b : byte;const ref : treference);virtual;
+          procedure a_load_const16_ref(list : paasmoutput;w : word;const ref : treference);virtual;
+          procedure a_load_const32_ref(list : paasmoutput;l : longint;const ref : treference);virtual;
+          procedure a_load_const64_ref(list : paasmoutput;q : qword;const ref : treference);virtual;
+
 
           procedure g_stackframe_entry(list : paasmoutput;localsize : longint);
+          procedure g_maybe_loadself(list : paasmoutput);virtual;
 
+          {********************************************************}
           { these methods can be overriden for extra functionality }
 
           { the following methods do nothing: }
@@ -57,7 +83,7 @@ unit cgobj;
           procedure g_interrupt_stackframe_exit(list : paasmoutput);virtual;
 
           procedure g_profilecode(list : paasmoutput);virtual;
-          procedure g_stackcheck(list : paasmoutput);virtual;
+          procedure g_stackcheck(list : paasmoutput;stackframesize : longint);virtual;
 
           { passing parameters, per default the parameter is pushed }
           { nr gives the number of the parameter (enumerated from   }
@@ -65,10 +91,29 @@ unit cgobj;
           { register, if the cpu supports register calling          }
           { conventions                                             }
           procedure a_param_reg(list : paasmoutput;r : tregister;nr : longint);virtual;
+          procedure a_param_const8(list : paasmoutput;b : byte;nr : longint);virtual;
+          procedure a_param_const16(list : paasmoutput;w : word;nr : longint);virtual;
+          procedure a_param_const32(list : paasmoutput;l : longint;nr : longint);virtual;
+          procedure a_param_const64(list : paasmoutput;q : qword;nr : longint);virtual;
        end;
 
+    var
+       cg : pcg; { this is the main code generator class }
+
   implementation
 
+    uses
+       globals,globtype,options,files,gdb,systems,
+       ppu,cgbase,temp_gen,verbose,types
+{$ifdef i386}
+       ,tgeni386
+{$endif i386}
+       ;
+
+{*****************************************************************************
+                  per default, this methods nothing, can overriden
+*****************************************************************************}
+
     procedure tcg.g_interrupt_stackframe_entry(list : paasmoutput);
 
       begin
@@ -79,27 +124,405 @@ unit cgobj;
       begin
       end;
 
+    procedure tcg.g_profilecode(list : paasmoutput);
+
+      begin
+      end;
+
     procedure tcg.a_param_reg(list : paasmoutput;r : tregister;nr : longint);
 
       begin
          a_push_reg(list,r);
       end;
 
-    procedure tcg.g_stackcheck(list : paasmoutput);
+    procedure tcg.a_param_const8(list : paasmoutput;b : byte;nr : longint);
 
       begin
-         a_param_reg(list,stackframe,1);
-         a_call_name(list,'FPC_STACKCHECK',0,EXT_NEAR);
+         {!!!!!!!! a_push_const8(list,b); }
+      end;
+
+    procedure tcg.a_param_const16(list : paasmoutput;w : word;nr : longint);
+
+      begin
+         {!!!!!!!! a_push_const16(list,w); }
+      end;
+
+    procedure tcg.a_param_const32(list : paasmoutput;l : longint;nr : longint);
+
+      begin
+         {!!!!!!!! a_push_const32(list,l); }
+      end;
+
+    procedure tcg.a_param_const64(list : paasmoutput;q : qword;nr : longint);
+
+      begin
+         {!!!!!!!! a_push_const64(list,q); }
+      end;
+
+    procedure tcg.g_stackcheck(list : paasmoutput;stackframesize : longint);
+
+      begin
+         a_param_const32(list,stackframesize,1);
+         a_call_name_ext(list,'FPC_STACKCHECK',0,EXT_NEAR);
       end;
 
     procedure tcg.a_call_name_ext(list : paasmoutput;const s : string;
-      offset : longint;m : texternaltyp);
+      offset : longint;m : texternal_typ);
 
       begin
          a_call_name(list,s,offset);
          concat_external(s,m);
       end;
 
+{*****************************************************************************
+                         String helper routines
+*****************************************************************************}
+
+    procedure tcg.g_removetemps(list : paasmoutput;p : plinkedlist);
+
+      var
+         hp : ptemptodestroy;
+         pushedregs : tpushed;
+
+      begin
+         hp:=ptemptodestroy(p^.first);
+         if not(assigned(hp)) then
+           exit;
+         pushusedregisters(pushedregs,$ff);
+         while assigned(hp) do
+           begin
+              if is_ansistring(hp^.typ) then
+                begin
+                   g_decransiref(hp^.address);
+                   ungetiftemp(hp^.address);
+                end;
+              hp:=ptemptodestroy(hp^.next);
+           end;
+         popusedregisters(pushedregs);
+      end;
+
+    procedure tcg.g_decransiref(const ref : treference);
+
+      begin
+         {!!!!!!!!!}
+         { emitpushreferenceaddr(exprasmlist,ref);
+         emitcall('FPC_ANSISTR_DECR_REF',true); }
+      end;
+
+{*****************************************************************************
+                  Code generation for subroutine entry- and exit code
+ *****************************************************************************}
+
+    { generates the code for initialisation of local data }
+    procedure tcg.g_initialize_data(p : psym);
+
+      var
+         r : preference;
+         hr : treference;
+
+      begin
+{$ifdef dummy}
+         if (p^.typ=varsym) and
+            assigned(pvarsym(p)^.definition) and
+            pvarsym(p)^.definition^.needs_inittable and
+            not((pvarsym(p)^.definition^.deftype=objectdef) and
+              pobjectdef(pvarsym(p)^.definition)^.isclass) then
+           begin
+              if is_ansistring(pvarsym(p)^.definition) or
+                is_widestring(pvarsym(p)^.definition) then
+                begin
+                   new(r);
+                   reset_reference(r^);
+                   if p^.owner^.symtabletype=localsymtable then
+                     begin
+                        r^.base:=procinfo.framepointer;
+                        r^.offset:=-pvarsym(p)^.address;
+                     end
+                   else
+                     r^.symbol:=stringdup(pvarsym(p)^.mangledname);
+                   curlist^.concat(new(pai386,op_const_ref(A_MOV,S_L,0,r)));
+                end
+              else
+                begin
+                   reset_reference(hr);
+                   hr.symbol:=stringdup(lab2str(pvarsym(p)^.definition^.get_inittable_label));
+                   emitpushreferenceaddr(curlist,hr);
+                   clear_reference(hr);
+                   if p^.owner^.symtabletype=localsymtable then
+                     begin
+                        hr.base:=procinfo.framepointer;
+                        hr.offset:=-pvarsym(p)^.address;
+                     end
+                   else
+                     begin
+                        hr.symbol:=stringdup(pvarsym(p)^.mangledname);
+                     end;
+                   emitpushreferenceaddr(curlist,hr);
+                   clear_reference(hr);
+                   curlist^.concat(new(pai386,
+                     op_csymbol(A_CALL,S_NO,newcsymbol('FPC_INITIALIZE',0))));
+                   if not(cs_compilesystem in aktmoduleswitches) then
+                     concat_external('FPC_INITIALIZE',EXT_NEAR);
+                end;
+           end;
+{$endif dummy}
+      end;
+
+    { generates the code for incrementing the reference count of parameters }
+    procedure tcg.g_incr_data(p : psym);
+
+      var
+         hr : treference;
+
+      begin
+{$ifdef dummy}
+         if (p^.typ=varsym) and
+            pvarsym(p)^.definition^.needs_inittable and
+            ((pvarsym(p)^.varspez=vs_value) {or
+             (pvarsym(p)^.varspez=vs_const) and
+             not(dont_copy_const_param(pvarsym(p)^.definition))}) and
+            not((pvarsym(p)^.definition^.deftype=objectdef) and
+              pobjectdef(pvarsym(p)^.definition)^.isclass) then
+           begin
+              reset_reference(hr);
+              hr.symbol:=stringdup(lab2str(pvarsym(p)^.definition^.get_inittable_label));
+              emitpushreferenceaddr(curlist,hr);
+              clear_reference(hr);
+              hr.base:=procinfo.framepointer;
+              hr.offset:=pvarsym(p)^.address+procinfo.call_offset;
+
+              emitpushreferenceaddr(curlist,hr);
+              clear_reference(hr);
+
+              curlist^.concat(new(pai386,
+                op_csymbol(A_CALL,S_NO,newcsymbol('FPC_ADDREF',0))));
+              if not (cs_compilesystem in aktmoduleswitches) then
+                concat_external('FPC_ADDREF',EXT_NEAR);
+           end;
+{$endif}
+      end;
+
+    { generates the code for finalisation of local data }
+    procedure tcg.g_finalize_data(p : psym);
+
+      var
+         hr : treference;
+
+      begin
+{$ifdef dummy}
+         if (p^.typ=varsym) and
+            assigned(pvarsym(p)^.definition) and
+            pvarsym(p)^.definition^.needs_inittable and
+            not((pvarsym(p)^.definition^.deftype=objectdef) and
+              pobjectdef(pvarsym(p)^.definition)^.isclass) then
+           begin
+              { not all kind of parameters need to be finalized  }
+              if (p^.owner^.symtabletype=parasymtable) and
+                ((pvarsym(p)^.varspez=vs_var)  or
+                 (pvarsym(p)^.varspez=vs_const) { and
+                 (dont_copy_const_param(pvarsym(p)^.definition)) } ) then
+                exit;
+              reset_reference(hr);
+              hr.symbol:=stringdup(lab2str(pvarsym(p)^.definition^.get_inittable_label));
+              emitpushreferenceaddr(curlist,hr);
+              clear_reference(hr);
+              case p^.owner^.symtabletype of
+                 localsymtable:
+                   begin
+                      hr.base:=procinfo.framepointer;
+                      hr.offset:=-pvarsym(p)^.address;
+                   end;
+                 parasymtable:
+                   begin
+                      hr.base:=procinfo.framepointer;
+                      hr.offset:=pvarsym(p)^.address+procinfo.call_offset;
+                   end;
+                 else
+                   hr.symbol:=stringdup(pvarsym(p)^.mangledname);
+              end;
+              emitpushreferenceaddr(curlist,hr);
+              clear_reference(hr);
+              curlist^.concat(new(pai386,
+                op_csymbol(A_CALL,S_NO,newcsymbol('FPC_FINALIZE',0))));
+              if not (cs_compilesystem in aktmoduleswitches) then
+              concat_external('FPC_FINALIZE',EXT_NEAR);
+           end;
+{$endif dummy}
+      end;
+
+
+    { generates the code to make local copies of the value parameters }
+  {$ifndef VALUEPARA}
+    procedure tcg.g_copyopenarrays(p : psym);
+  {$else}
+    procedure tcg.g_copyvalueparas(p : psym);
+  {$endif}
+      var
+  {$ifdef VALUEPARA}
+        href1,href2 : treference;
+  {$endif}
+        r    : preference;
+        len  : longint;
+        opsize : topsize;
+        oldexprasmlist : paasmoutput;
+      begin
+{$ifdef dummy}
+         if (p^.typ=varsym) and
+  {$ifdef VALUEPARA}
+            (pvarsym(p)^.varspez=vs_value) and
+            (push_addr_param(pvarsym(p)^.definition)) then
+  {$else}
+            (pvarsym(p)^.varspez=vs_value) then
+  {$endif}
+          begin
+            oldexprasmlist:=exprasmlist;
+            exprasmlist:=curlist;
+  {$ifdef VALUEPARA}
+  {$ifdef GDB}
+            if (cs_debuginfo in aktmoduleswitches) and
+               (exprasmlist^.first=exprasmlist^.last) then
+              exprasmlist^.concat(new(pai_force_line,init));
+  {$endif GDB}
+  {$endif}
+            if is_open_array(pvarsym(p)^.definition) then
+             begin
+                { get stack space }
+                new(r);
+                reset_reference(r^);
+                r^.base:=procinfo.framepointer;
+                r^.offset:=pvarsym(p)^.address+4+procinfo.call_offset;
+                curlist^.concat(new(pai386,
+                  op_ref_reg(A_MOV,S_L,r,R_EDI)));
+
+                curlist^.concat(new(pai386,
+                  op_reg(A_INC,S_L,R_EDI)));
+
+                curlist^.concat(new(pai386,
+                  op_const_reg(A_IMUL,S_L,
+                  parraydef(pvarsym(p)^.definition)^.definition^.size,R_EDI)));
+
+                curlist^.concat(new(pai386,
+                  op_reg_reg(A_SUB,S_L,R_EDI,R_ESP)));
+                { load destination }
+                curlist^.concat(new(pai386,
+                  op_reg_reg(A_MOV,S_L,R_ESP,R_EDI)));
+
+                { don't destroy the registers! }
+                curlist^.concat(new(pai386,
+                  op_reg(A_PUSH,S_L,R_ECX)));
+                curlist^.concat(new(pai386,
+                  op_reg(A_PUSH,S_L,R_ESI)));
+
+                { load count }
+                new(r);
+                reset_reference(r^);
+                r^.base:=procinfo.framepointer;
+                r^.offset:=pvarsym(p)^.address+4+procinfo.call_offset;
+                curlist^.concat(new(pai386,
+                  op_ref_reg(A_MOV,S_L,r,R_ECX)));
+
+                { load source }
+                new(r);
+                reset_reference(r^);
+                r^.base:=procinfo.framepointer;
+                r^.offset:=pvarsym(p)^.address+procinfo.call_offset;
+                curlist^.concat(new(pai386,
+                  op_ref_reg(A_MOV,S_L,r,R_ESI)));
+
+                { scheduled .... }
+                curlist^.concat(new(pai386,
+                  op_reg(A_INC,S_L,R_ECX)));
+
+                { calculate size }
+                len:=parraydef(pvarsym(p)^.definition)^.definition^.size;
+                if (len and 3)=0 then
+                 begin
+                   opsize:=S_L;
+                   len:=len shr 2;
+                 end
+                else
+                 if (len and 1)=0 then
+                  begin
+                    opsize:=S_W;
+                    len:=len shr 1;
+                  end;
+
+                curlist^.concat(new(pai386,
+                  op_const_reg(A_IMUL,S_L,len,R_ECX)));
+                curlist^.concat(new(pai386,
+                  op_none(A_REP,S_NO)));
+                curlist^.concat(new(pai386,
+                  op_none(A_MOVS,opsize)));
+
+                curlist^.concat(new(pai386,
+                  op_reg(A_POP,S_L,R_ESI)));
+                curlist^.concat(new(pai386,
+                  op_reg(A_POP,S_L,R_ECX)));
+
+                { patch the new address }
+                new(r);
+                reset_reference(r^);
+                r^.base:=procinfo.framepointer;
+                r^.offset:=pvarsym(p)^.address+procinfo.call_offset;
+                curlist^.concat(new(pai386,
+                  op_reg_ref(A_MOV,S_L,R_ESP,r)));
+             end
+  {$ifdef VALUEPARA}
+            else
+             if is_shortstring(pvarsym(p)^.definition) then
+              begin
+                reset_reference(href1);
+                href1.base:=procinfo.framepointer;
+                href1.offset:=pvarsym(p)^.address+procinfo.call_offset;
+                reset_reference(href2);
+                href2.base:=procinfo.framepointer;
+                href2.offset:=-pvarsym(p)^.localaddress;
+                copyshortstring(href2,href1,pstringdef(pvarsym(p)^.definition)^.len,true);
+              end
+             else
+              begin
+                reset_reference(href1);
+                href1.base:=procinfo.framepointer;
+                href1.offset:=pvarsym(p)^.address+procinfo.call_offset;
+                reset_reference(href2);
+                href2.base:=procinfo.framepointer;
+                href2.offset:=-pvarsym(p)^.localaddress;
+                concatcopy(href1,href2,pvarsym(p)^.definition^.size,true,true);
+              end;
+  {$else}
+            ;
+  {$endif}
+            exprasmlist:=oldexprasmlist;
+          end;
+{$endif dummy}
+      end;
+
+    { wrappers for the methods, because TP doesn't know procedures }
+    { of objects                                                   }
+
+    procedure _copyopenarrays(s : psym);{$ifndef FPC}far;{$endif}
+
+      begin
+         cg^.g_copyopenarrays(s);
+      end;
+
+    procedure _finalize_data(s : psym);{$ifndef FPC}far;{$endif}
+
+      begin
+         cg^.g_finalize_data(s);
+      end;
+
+    procedure _incr_data(s : psym);{$ifndef FPC}far;{$endif}
+
+      begin
+         cg^.g_incr_data(s);
+      end;
+    procedure _initialize_data(s : psym);{$ifndef FPC}far;{$endif}
+
+      begin
+         cg^.g_initialize_data(s);
+      end;
+
     { generates the entry code for a procedure }
     procedure tcg.g_entrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
        stackframe:longint;var parasize:longint;var nostackframe:boolean;
@@ -107,12 +530,13 @@ unit cgobj;
 
       var
          hs : string;
-         hp : Pused_unit;
+         hp : pused_unit;
          unitinits,initcode : taasmoutput;
 {$ifdef GDB}
          stab_function_name : Pai_stab_function_name;
 {$endif GDB}
-         hr : preference;
+         hr : treference;
+         r : tregister;
 
       begin
          { Align }
@@ -125,20 +549,18 @@ unit cgobj;
                 if not(cs_littlesize in aktglobalswitches) then
                   list^.insert(new(pai_align,init(4)));
           end;
-          curlist:=list;
           if (not inlined) and ((aktprocsym^.definition^.options and poproginit)<>0) then
             begin
 
               { needs the target a console flags ? }
               if tf_needs_isconsole in target_info.flags then
                 begin
-                   new(hr);
-                   reset_reference(hr^);
-                   hr^.symbol:=stringdup('U_'+target_info.system_unit+'_ISCONSOLE');
+                   hr.symbol:=stringdup('U_'+target_info.system_unit+'_ISCONSOLE');
                    if apptype=at_cui then
-                     a_load_const8_ref(list,1,hr);
+                     a_load_const8_ref(list,1,hr)
                    else
                      a_load_const8_ref(list,0,hr);
+                   stringdispose(hr.symbol);
                 end;
 
               { Call the unit init procedures }
@@ -190,7 +612,7 @@ unit cgobj;
                    if (r in registers_saved_on_cdecl) then
                      if (r in general_registers) then
                        begin
-                          if (r in usedregisters) then
+                          if not(r in unused) then
                             a_push_reg(list,r)
                        end
                      else
@@ -218,13 +640,13 @@ unit cgobj;
                nostackframe:=false;
 
                if (aktprocsym^.definition^.options and pointerrupt)<>0 then
-                 generate_interrupt_stackframe_entry;
+                 g_interrupt_stackframe_entry(list);
 
                g_stackframe_entry(list,stackframe);
 
                if (cs_check_stack in aktlocalswitches) and
-                 (target_info.flags in tf_supports_stack_check) then
-                 g_stackcheck(@initcode);
+                 (tf_supports_stack_checking in target_info.flags) then
+                 g_stackcheck(@initcode,stackframe);
             end;
 
          if cs_profile in aktmoduleswitches then
@@ -234,27 +656,26 @@ unit cgobj;
          if is_ansistring(procinfo.retdef) or
            is_widestring(procinfo.retdef) then
            begin
-              new(hr);
-              reset_reference(hr^);
-              hr^.offset:=procinfo.retoffset;
-              hr^.base:=procinfo.framepointer;
-              curlist^.concat(new(pai386,op_const_ref(A_MOV,S_L,0,hr)));
+              reset_reference(hr);
+              hr.offset:=procinfo.retoffset;
+              hr.base:=procinfo.framepointer;
+              a_load_const32_ref(list,0,hr);
            end;
 
          { generate copies of call by value parameters }
          if (aktprocsym^.definition^.options and poassembler=0) then
            begin
   {$ifndef VALUEPARA}
-              aktprocsym^.definition^.parast^.foreach(copyopenarrays);
+              aktprocsym^.definition^.parast^.foreach(_copyopenarrays);
   {$else}
-              aktprocsym^.definition^.parast^.foreach(copyvalueparas);
+              aktprocsym^.definition^.parast^.foreach(_copyvalueparas);
   {$endif}
            end;
 
          { initialisizes local data }
-         aktprocsym^.definition^.localst^.foreach(initialize_data);
+         aktprocsym^.definition^.localst^.foreach(_initialize_data);
          { add a reference to all call by value/const parameters }
-         aktprocsym^.definition^.parast^.foreach(incr_data);
+         aktprocsym^.definition^.parast^.foreach(_incr_data);
 
          if (cs_profile in aktmoduleswitches) or
            (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
@@ -300,14 +721,68 @@ unit cgobj;
               aktprocsym^.isstabwritten:=true;
             end;
   {$endif GDB}
-
-        curlist:=nil;
     end;
 
+{*****************************************************************************
+                       some abstract definitions
+ ****************************************************************************}
+
+    procedure tcg.a_push_reg(list : paasmoutput;r : tregister);
+
+      begin
+         abstract;
+      end;
+
+    procedure tcg.a_call_name(list : paasmoutput;const s : string;
+      offset : longint);
+
+      begin
+         abstract;
+      end;
+
+    procedure tcg.a_load_const8_ref(list : paasmoutput;b : byte;const ref : treference);
+
+      begin
+         abstract;
+      end;
+
+    procedure tcg.a_load_const16_ref(list : paasmoutput;w : word;const ref : treference);
+
+      begin
+         abstract;
+      end;
+
+    procedure tcg.a_load_const32_ref(list : paasmoutput;l : longint;const ref : treference);
+
+      begin
+         abstract;
+      end;
+
+    procedure tcg.a_load_const64_ref(list : paasmoutput;q : qword;const ref : treference);
+
+      begin
+         abstract;
+      end;
+
+    procedure tcg.g_stackframe_entry(list : paasmoutput;localsize : longint);
+
+      begin
+         abstract;
+      end;
+
+    procedure tcg.g_maybe_loadself(list : paasmoutput);
+
+      begin
+         abstract;
+      end;
+
 end.
 {
   $Log$
-  Revision 1.2  1998-12-15 22:18:55  florian
+  Revision 1.3  1998-12-26 15:20:30  florian
+    + more changes for the new version
+
+  Revision 1.2  1998/12/15 22:18:55  florian
     * some code added
 
   Revision 1.1  1998/12/15 16:32:58  florian

+ 302 - 0
compiler/new/pass_1.pas

@@ -0,0 +1,302 @@
+{
+    $Id$
+    Copyright (c) 1996-98 by Florian Klaempfl
+
+    This unit implements the first pass of the code generator
+
+    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}
+  {$F+}
+{$endif tp}
+unit pass_1;
+interface
+
+    uses
+       tree;
+
+    procedure firstpass(p : pnode);
+    function  do_firstpass(var p : ptree) : boolean;
+    function  do_firstpassnode(var p : pnode) : boolean;
+
+implementation
+
+    uses
+      globtype,systems,
+      cobjects,verbose,globals,
+      aasm,symtable,types,
+      cgbase
+      { not yet converted:
+      htypechk,tcadd,tccal,tccnv,tccon,tcflw,
+      tcinl,tcld,tcmat,tcmem,tcset
+      }
+{$ifdef i386}
+      ,i386,tgeni386
+{$endif}
+{$ifdef m68k}
+      ,m68k,tgen68k
+{$endif}
+      ;
+
+{*****************************************************************************
+                              FirstPass
+*****************************************************************************}
+
+{$ifdef dummy}
+    type
+       firstpassproc = procedure(var p : ptree);
+
+    procedure firstnothing(var p : ptree);
+      begin
+         p^.resulttype:=voiddef;
+      end;
+
+
+    procedure firsterror(var p : ptree);
+      begin
+         p^.error:=true;
+         codegenerror:=true;
+         p^.resulttype:=generrordef;
+      end;
+
+
+    procedure firststatement(var p : ptree);
+      begin
+         { left is the next statement in the list }
+         p^.resulttype:=voiddef;
+         { no temps over several statements }
+         cleartempgen;
+         { right is the statement itself calln assignn or a complex one }
+         firstpass(p^.right);
+         if (not (cs_extsyntax in aktmoduleswitches)) and
+            assigned(p^.right^.resulttype) and
+            (p^.right^.resulttype<>pdef(voiddef)) then
+           CGMessage(cg_e_illegal_expression);
+         if codegenerror then
+           exit;
+         p^.registers32:=p^.right^.registers32;
+         p^.registersfpu:=p^.right^.registersfpu;
+{$ifdef SUPPORT_MMX}
+         p^.registersmmx:=p^.right^.registersmmx;
+{$endif SUPPORT_MMX}
+         { left is the next in the list }
+         firstpass(p^.left);
+         if codegenerror then
+           exit;
+         if p^.right^.registers32>p^.registers32 then
+           p^.registers32:=p^.right^.registers32;
+         if p^.right^.registersfpu>p^.registersfpu then
+           p^.registersfpu:=p^.right^.registersfpu;
+{$ifdef SUPPORT_MMX}
+         if p^.right^.registersmmx>p^.registersmmx then
+           p^.registersmmx:=p^.right^.registersmmx;
+{$endif}
+      end;
+
+
+    procedure firstblock(var p : ptree);
+      var
+         hp : ptree;
+         count : longint;
+      begin
+         count:=0;
+         hp:=p^.left;
+         while assigned(hp) do
+           begin
+              if cs_regalloc in aktglobalswitches then
+                begin
+                   { Codeumstellungen }
+
+                   { Funktionsresultate an exit anh„ngen }
+                   { this is wrong for string or other complex
+                     result types !!! }
+                   if ret_in_acc(procinfo.retdef) and
+                      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
+                           CGMessage(cg_n_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 in
+                     [exitn,breakn,continuen,goton]) and
+                     assigned(hp^.left) and
+                     (hp^.left^.treetype<>labeln) then
+                     begin
+                        { use correct line number }
+                        aktfilepos:=hp^.left^.fileinfo;
+                        disposetree(hp^.left);
+                        hp^.left:=nil;
+                        CGMessage(cg_w_unreachable_code);
+                        { old lines }
+                        aktfilepos:=hp^.right^.fileinfo;
+                     end;
+                end;
+              if assigned(hp^.right) then
+                begin
+                   cleartempgen;
+                   firstpass(hp^.right);
+                   if (not (cs_extsyntax in aktmoduleswitches)) and
+                      assigned(hp^.right^.resulttype) and
+                      (hp^.right^.resulttype<>pdef(voiddef)) then
+                     CGMessage(cg_e_illegal_expression);
+                   if codegenerror then
+                     exit;
+                   hp^.registers32:=hp^.right^.registers32;
+                   hp^.registersfpu:=hp^.right^.registersfpu;
+{$ifdef SUPPORT_MMX}
+                   hp^.registersmmx:=hp^.right^.registersmmx;
+{$endif SUPPORT_MMX}
+                end
+              else
+                hp^.registers32:=0;
+
+              if hp^.registers32>p^.registers32 then
+                p^.registers32:=hp^.registers32;
+              if hp^.registersfpu>p^.registersfpu then
+                p^.registersfpu:=hp^.registersfpu;
+{$ifdef SUPPORT_MMX}
+              if hp^.registersmmx>p^.registersmmx then
+                p^.registersmmx:=hp^.registersmmx;
+{$endif}
+              inc(count);
+              hp:=hp^.left;
+           end;
+      end;
+
+    procedure firstasm(var p : ptree);
+
+      begin
+        procinfo.flags:=procinfo.flags or pi_uses_asm;
+      end;
+
+{$endif dummy}
+
+    procedure firstpass(p : pnode);
+
+      var
+         oldcodegenerror  : boolean;
+         oldlocalswitches : tlocalswitches;
+         oldpos           : tfileposinfo;
+{$ifdef extdebug}
+         str1,str2 : string;
+         oldp      : ptree;
+         not_first : boolean;
+{$endif extdebug}
+      begin
+{$ifdef extdebug}
+         inc(total_of_firstpass);
+         if (p^.firstpasscount>0) and only_one_pass then
+           exit;
+{$endif extdebug}
+         oldcodegenerror:=codegenerror;
+         oldpos:=aktfilepos;
+         oldlocalswitches:=aktlocalswitches;
+{$ifdef extdebug}
+         if p^.firstpasscount>0 then
+           begin
+              move(p^,str1[1],sizeof(ttree));
+       {$ifndef TP}
+         {$ifopt H+}
+           SetLength(str1,sizeof(ttree));
+         {$else}
+              str1[0]:=char(sizeof(ttree));
+         {$endif}
+       {$else}
+              str1[0]:=char(sizeof(ttree));
+       {$endif}
+              new(oldp);
+              oldp^:=p^;
+              not_first:=true;
+              inc(firstpass_several);
+           end
+         else
+           not_first:=false;
+{$endif extdebug}
+
+         if not p^.error then
+           begin
+              codegenerror:=false;
+              aktfilepos:=p^.fileinfo;
+              aktlocalswitches:=p^.localswitches;
+              p^.pass_1;
+              aktlocalswitches:=oldlocalswitches;
+              aktfilepos:=oldpos;
+              p^.error:=codegenerror;
+              codegenerror:=codegenerror or oldcodegenerror;
+           end
+         else
+           codegenerror:=true;
+{$ifdef extdebug}
+         if not_first then
+           begin
+              { dirty trick to compare two ttree's (PM) }
+              move(p^,str2[1],sizeof(ttree));
+       {$ifndef TP}
+         {$ifopt H+}
+           SetLength(str2,sizeof(ttree));
+         {$else}
+              str2[0]:=char(sizeof(ttree));
+         {$endif}
+       {$else}
+              str2[0]:=char(sizeof(ttree));
+       {$endif}
+              if str1<>str2 then
+                begin
+                   comment(v_debug,'tree changed after first counting pass '
+                     +tostr(longint(p^.treetype)));
+                   compare_trees(oldp,p);
+                end;
+              dispose(oldp);
+           end;
+         if count_ref then
+           inc(p^.firstpasscount);
+{$endif extdebug}
+      end;
+
+
+    function do_firstpass(var p : ptree) : boolean;
+
+      begin
+         codegenerror:=false;
+         do_firstpass:=codegenerror;
+      end;
+
+    function do_firstpassnode(var p : pnode) : boolean;
+
+      begin
+         codegenerror:=false;
+         firstpass(p);
+         do_firstpassnode:=codegenerror;
+      end;
+
+
+end.
+{
+  $Log$
+  Revision 1.1  1998-12-26 15:20:31  florian
+    + more changes for the new version
+
+}

+ 271 - 0
compiler/new/pp.pas

@@ -0,0 +1,271 @@
+{
+    $Id$
+    Copyright (c) 1993-98 by Florian Klaempfl
+
+    Commandline compiler for Free Pascal
+
+    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.
+
+ ****************************************************************************}
+
+{
+  possible compiler switches (* marks a currently required switch):
+  -----------------------------------------------------------------
+  USE_RHIDE           generates errors and warning in an format recognized
+                      by rhide
+  TP                  to compile the compiler with Turbo or Borland Pascal
+  GDB*                support of the GNU Debugger
+  I386                generate a compiler for the Intel i386+
+  M68K                generate a compiler for the M68000
+  USEOVERLAY          compiles a TP version which uses overlays
+  EXTDEBUG            some extra debug code is executed
+  SUPPORT_MMX         only i386: releases the compiler switch
+                      MMX which allows the compiler to generate
+                      MMX instructions
+  EXTERN_MSG          Don't compile the msgfiles in the compiler, always
+                      use external messagefiles, default for TP
+  NOAG386INT          no Intel Assembler output
+  NOAG386NSM          no NASM output
+  -----------------------------------------------------------------
+
+  Required switches for a i386 compiler be compiled by Free Pascal Compiler:
+  GDB;I386
+
+  Required switches for a i386 compiler be compiled by Turbo Pascal:
+  GDB;I386;TP
+
+  Required switches for a 68000 compiler be compiled by Turbo Pascal:
+  GDB;M68k;TP
+}
+
+{$ifdef FPC}
+   {$ifndef GDB}
+      { people can try to compile without GDB }
+      { $error The compiler switch GDB must be defined}
+   {$endif GDB}
+   { but I386 or M68K must be defined }
+   { and only one of the two }
+   {$ifndef I386}
+      {$ifndef M68K}
+        {$fatal One of the switches I386 or M68K must be defined}
+      {$endif M68K}
+   {$endif I386}
+   {$ifdef I386}
+      {$ifdef M68K}
+        {$fatal ONLY one of the switches I386 or M68K must be defined}
+      {$endif M68K}
+   {$endif I386}
+   {$ifdef support_mmx}
+     {$ifndef i386}
+       {$fatal I386 switch must be on for MMX support}
+     {$endif i386}
+   {$endif support_mmx}
+{$endif}
+
+{$ifdef TP}
+  {$IFNDEF DPMI}
+    {$M 24000,0,655360}
+  {$ELSE}
+    {$M 65000}
+  {$ENDIF DPMI}
+  {$E+,N+,F+,S-,R-}
+{$endif TP}
+
+
+program pp;
+
+{$IFDEF TP}
+  {$UNDEF PROFILE}
+  {$IFDEF DPMI}
+    {$UNDEF USEOVERLAY}
+  {$ENDIF}
+{$ENDIF}
+{$ifdef FPC}
+  {$UNDEF USEOVERLAY}
+{$ENDIF}
+
+uses
+{$ifdef useoverlay}
+  {$ifopt o+}
+    Overlay,ppovin,
+  {$else}
+    {$error You must compile with the $O+ switch}
+  {$endif}
+{$endif useoverlay}
+{$ifdef profile}
+  profile,
+{$endif profile}
+{$ifdef FPC}
+{$ifdef heaptrc}
+  ppheap,
+{$endif heaptrc}
+{$ifdef linux}
+  catch,
+{$endif}
+{$endif FPC}
+  globals,compiler
+  ;
+
+{$ifdef useoverlay}
+  {$O files}
+  {$O globals}
+  {$O hcodegen}
+  {$O pass_1}
+  {$O pass_2}
+  {$O tree}
+  {$O types}
+  {$O objects}
+  {$O options}
+  {$O cobjects}
+  {$O globals}
+  {$O systems}
+  {$O parser}
+  {$O pbase}
+  {$O pdecl}
+  {$O pexports}
+  {$O pexpr}
+  {$O pmodules}
+  {$O pstatmnt}
+  {$O psub}
+  {$O psystem}
+  {$O ptconst}
+  {$O script}
+  {$O switches}
+  {$O temp_gen}
+  {$O comphook}
+  {$O dos}
+  {$O scanner}
+  {$O symtable}
+  {$O objects}
+  {$O aasm}
+  {$O link}
+  {$O assemble}
+  {$O messages}
+  {$O gendef}
+  {$O import}
+{$ifdef i386}
+  {$O os2_targ}
+  {$O win_targ}
+{$endif i386}
+  {$O asmutils}
+  {$ifdef gdb}
+        {$O gdb}
+  {$endif gdb}
+  {$ifdef i386}
+        {$O opts386}
+        {$O i386}
+        {$O cgai386}
+        {$O tgeni386}
+        {$O cg386add}
+        {$O cg386cal}
+        {$O cg386cnv}
+        {$O cg386con}
+        {$O cg386flw}
+        {$O cg386ld}
+        {$O cg386inl}
+        {$O cg386mat}
+        {$O cg386set}
+        {$ifndef NOOPT}
+          {$O aopt386}
+        {$endif}
+        {$IfNDef Nora386dir}
+          {$O ra386dir}
+        {$endif}
+        {$IfNDef Nora386int}
+          {$O ra386int}
+        {$endif}
+        {$IfNDef Nora386att}
+          {$O ra386att}
+        {$endif}
+        {$ifndef NoAg386Int}
+          {$O ag386int}
+        {$endif}
+        {$ifndef NoAg386Att}
+          {$O ag386att}
+        {$endif}
+        {$ifndef NoAg386Nsm}
+          {$O ag386nsm}
+        {$endif}
+  {$endif}
+  {$ifdef m68k}
+        {$O opts68k}
+        {$O m68k}
+        {$O cga68k}
+        {$O tgen68k}
+        {$O cg68kadd}
+        {$O cg68kcal}
+        {$O cg68kcnv}
+        {$O cg68kcon}
+        {$O cg68kflw}
+        {$O cg68kld}
+        {$O cg68kinl}
+        {$O cg68kmat}
+        {$O cg68kset}
+        {$IfNDef Nora68kMot}
+          {$O ra68kmot}
+        {$endif}
+        {$IfNDef Noag68kGas}
+          {$O ag68kgas}
+        {$endif}
+        {$IfNDef Noag68kMot}
+          {$O ag68kmot}
+        {$endif}
+        {$IfNDef Noag68kMit}
+          {$O ag68kmit}
+        {$endif}
+  {$endif}
+{$endif useoverlay}
+
+var
+  oldexit : pointer;
+procedure myexit;{$ifndef FPC}far;{$endif}
+begin
+  exitproc:=oldexit;
+{ Show Runtime error if there was an error }
+  if (erroraddr<>nil) then
+   begin
+     case exitcode of
+      202 : begin
+              erroraddr:=nil;
+              Writeln('Error: Stack Overflow');
+            end;
+      203 : begin
+              erroraddr:=nil;
+              Writeln('Error: Out of memory');
+            end;
+     end;
+     Writeln('Compilation aborted at line ',aktfilepos.line);
+   end;
+end;
+
+begin
+  oldexit:=exitproc;
+  exitproc:=@myexit;
+{$ifdef fpc}
+  heapblocks:=true;
+{$endif}
+{$ifdef UseOverlay}
+  InitOverlay;
+{$endif}
+
+{ Call the compiler with empty command, so it will take the parameters }
+  Halt(Compile(''));
+end.
+{
+  $Log$
+  Revision 1.1  1998-12-26 15:20:31  florian
+    + more changes for the new version
+
+}

+ 1466 - 0
compiler/new/psub.pas

@@ -0,0 +1,1466 @@
+{
+    $Id$
+    Copyright (c) 1998 by Florian Klaempfl, Daniel Mantione
+
+    Does the parsing of the procedures/functions
+
+    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.
+
+ ****************************************************************************
+}
+unit psub;
+interface
+
+uses cobjects,symtable;
+
+const
+  pd_global    = $1;    { directive must be global }
+  pd_body      = $2;    { directive needs a body }
+  pd_implemen  = $4;    { directive can be used implementation section }
+  pd_interface = $8;    { directive can be used interface section }
+  pd_object    = $10;   { directive can be used object declaration }
+  pd_procvar   = $20;   { directive can be used procvar declaration }
+
+procedure compile_proc_body(const proc_names:Tstringcontainer;
+                            make_global,parent_has_class:boolean);
+procedure parse_proc_head(options : word);
+procedure parse_proc_dec;
+procedure parse_var_proc_directives(var sym : ptypesym);
+procedure read_proc;
+
+
+implementation
+
+uses
+  globtype,systems,tokens,
+  strings,globals,verbose,comphook,files,
+  scanner,aasm,tree,types,
+  import,gendef,
+  hcodegen,temp_gen,pass_1,pass_2
+{$ifdef GDB}
+  ,gdb
+{$endif GDB}
+{$ifdef i386}
+  ,i386,tgeni386
+  {$ifndef NoOpt}
+  ,aopt386
+  {$endif}
+{$endif}
+{$ifdef m68k}
+  ,m68k,tgen68k,cga68k
+{$endif}
+  { parser specific stuff }
+  ,pbase,pdecl,pexpr,pstatmnt
+  ;
+
+var
+  realname:string;  { contains the real name of a procedure as it's typed }
+
+
+procedure formal_parameter_list;
+{
+  handle_procvar needs the same changes
+}
+var
+  sc      : Pstringcontainer;
+  s       : string;
+  filepos : tfileposinfo;
+  p       : Pdef;
+  vs      : Pvarsym;
+{$ifdef VALUEPARA}
+  l       : longint;
+{$endif}
+  hs1,hs2 : string;
+  varspez : Tvarspez;
+begin
+  consume(LKLAMMER);
+  inc(testcurobject);
+  repeat
+    case token of
+     _VAR : begin
+              consume(_VAR);
+              varspez:=vs_var;
+            end;
+   _CONST : begin
+              consume(_CONST);
+              varspez:=vs_const;
+            end;
+    else
+      varspez:=vs_value;
+    end;
+
+  { read identifiers }
+
+    sc:=idlist;
+  { read type declaration, force reading for value and const paras }
+
+    if (token=COLON) or (varspez=vs_value) then
+     begin
+       consume(COLON);
+     { check for an open array }
+       if token=_ARRAY then
+        begin
+          consume(_ARRAY);
+          consume(_OF);
+        { define range and type of range }
+          p:=new(Parraydef,init(0,-1,s32bitdef));
+        { array of const ? }
+          if (token=_CONST) and (m_objpas in aktmodeswitches) then
+           begin
+             consume(_CONST);
+             srsym:=nil;
+             if assigned(objpasunit) then
+              getsymonlyin(objpasunit,'TVARREC');
+             if not assigned(srsym) then
+              InternalError(1234124);
+             Parraydef(p)^.definition:=ptypesym(srsym)^.definition;
+             Parraydef(p)^.IsArrayOfConst:=true;
+             hs1:='array_of_const';
+           end
+          else
+           begin
+           { define field type }
+             Parraydef(p)^.definition:=single_type(hs1);
+             hs1:='array_of_'+hs1;
+           end;
+        end
+       { open string ? }
+       else if ((token=_STRING) or (idtoken=_SHORTSTRING)) and
+               (varspez=vs_var) and
+               (cs_openstring in aktmoduleswitches) and
+               not(cs_ansistrings in aktlocalswitches) then
+        begin
+          consume(token);
+          p:=openshortstringdef;
+          hs1:='openstring';
+        end
+       { everything else }
+       else
+        p:=single_type(hs1);
+     end
+    else
+     begin
+{$ifndef UseNiceNames}
+       hs1:='$$$';
+{$else UseNiceNames}
+       hs1:='var';
+{$endif UseNiceNames}
+       p:=new(Pformaldef,init);
+     end;
+    hs2:=aktprocsym^.definition^.mangledname;
+    while not sc^.empty do
+     begin
+       s:=sc^.get_with_tokeninfo(filepos);
+       aktprocsym^.definition^.concatdef(p,varspez);
+{$ifndef UseNiceNames}
+       hs2:=hs2+'$'+hs1;
+{$else UseNiceNames}
+       hs2:=hs2+tostr(length(hs1))+hs1;
+{$endif UseNiceNames}
+       vs:=new(Pvarsym,init(s,p));
+       vs^.fileinfo:=filepos;
+       vs^.varspez:=varspez;
+     { we have to add this to avoid var param to be in registers !!!}
+{$ifndef VALUEPARA}
+       if (varspez in [vs_var,vs_const]) and dont_copy_const_param(p) then
+         vs^.var_options := vs^.var_options or vo_regable;
+     { search for duplicate ids in object members/methods    }
+     { but only the current class, I don't know why ...      }
+     { at least TP and Delphi do it in that way         (FK) }
+       if assigned(procinfo._class) and (lexlevel=normal_function_level) and
+          (procinfo._class^.publicsyms^.search(vs^.name)<>nil) then
+      {   (search_class_member(procinfo._class,vs^.name)<>nil) then }
+         Message1(sym_e_duplicate_id,vs^.name);
+       aktprocsym^.definition^.parast^.insert(vs);
+{$else}
+       if (varspez in [vs_var,vs_const]) and push_addr_param(p) then
+         vs^.var_options := vs^.var_options or vo_regable;
+
+       { search for duplicate ids in object members/methods    }
+       { but only the current class, I don't know why ...      }
+       { at least TP and Delphi do it in that way         (FK) }
+       if assigned(procinfo._class) and (lexlevel=normal_function_level) and
+          (procinfo._class^.publicsyms^.search(vs^.name)<>nil) then
+      {   (search_class_member(procinfo._class,vs^.name)<>nil) then }
+         Message1(sym_e_duplicate_id,vs^.name);
+
+       { when it is a value para and it needs a local copy then rename
+         the parameter and insert a copy in the localst }
+       if (varspez=vs_value) and push_addr_param(p) then
+         begin
+           vs^.islocalcopy:=true;
+           aktprocsym^.definition^.localst^.insert(vs);
+           vs^.is_valid:=1;
+           l:=vs^.address; { save local address }
+           vs:=new(Pvarsym,init('val'+s,p));
+           vs^.fileinfo:=filepos;
+           vs^.varspez:=varspez;
+           vs^.localaddress:=l;
+           aktprocsym^.definition^.parast^.insert(vs);
+         end
+       else
+         aktprocsym^.definition^.parast^.insert(vs);
+{$endif}
+     end;
+    dispose(sc,done);
+    aktprocsym^.definition^.setmangledname(hs2);
+    if token=SEMICOLON then
+      consume(SEMICOLON)
+    else
+      break;
+  until false;
+  dec(testcurobject);
+  consume(RKLAMMER);
+end;
+
+
+
+procedure parse_proc_head(options : word);
+var sp:stringid;
+    pd:Pprocdef;
+    paramoffset:longint;
+    sym:Psym;
+    hs:string;
+    overloaded_level:word;
+    realfilepos : tfileposinfo;
+begin
+  if (options and pooperator) <> 0 then
+    begin
+      sp:=overloaded_names[optoken];
+      realname:=sp;
+    end
+  else
+    begin
+      sp:=pattern;
+      realname:=orgpattern;
+      realfilepos:=aktfilepos;
+      consume(ID);
+    end;
+
+{ method ? }
+  if (token=POINT) and not(parse_only) then
+   begin
+     consume(POINT);
+     getsym(sp,true);
+     sym:=srsym;
+     { qualifier is class name ? }
+     if (sym^.typ<>typesym) or
+        (ptypesym(sym)^.definition^.deftype<>objectdef) then
+       begin
+          Message(parser_e_class_id_expected);
+          aktprocsym:=nil;
+          consume(ID);
+       end
+     else
+       begin
+          { used to allow private syms to be seen }
+          aktobjectdef:=pobjectdef(ptypesym(sym)^.definition);
+          sp:=pattern;
+          realname:=orgpattern;
+          consume(ID);
+          procinfo._class:=pobjectdef(ptypesym(sym)^.definition);
+          aktprocsym:=pprocsym(procinfo._class^.publicsyms^.search(sp));
+          aktobjectdef:=nil;
+          { we solve this below }
+          if not(assigned(aktprocsym)) then
+            Message(parser_e_methode_id_expected);
+       end;
+   end
+  else
+   begin
+     { check for constructor/destructor which is not allowed here }
+     if (not parse_only) and
+        ((options and (poconstructor or podestructor))<>0) then
+        Message(parser_e_constructors_always_objects);
+
+     aktprocsym:=pprocsym(symtablestack^.search(sp));
+
+     if lexlevel=normal_function_level then
+{$ifdef UseNiceNames}
+       hs:=procprefix+'_'+tostr(length(sp))+sp
+{$else UseNiceNames}
+       hs:=procprefix+'_'+sp
+{$endif UseNiceNames}
+     else
+{$ifdef UseNiceNames}
+       hs:=lowercase(procprefix)+'_'+tostr(length(sp))+sp;
+{$else UseNiceNames}
+       hs:=procprefix+'_$'+sp;
+{$endif UseNiceNames}
+     if not(parse_only) then
+       begin
+         {The procedure we prepare for is in the implementation
+          part of the unit we compile. It is also possible that we
+          are compiling a program, which is also some kind of
+          implementaion part.
+
+          We need to find out if the procedure is global. If it is
+          global, it is in the global symtable.}
+         if not assigned(aktprocsym) then
+          begin
+            {Search the procedure in the global symtable.}
+            aktprocsym:=Pprocsym(search_a_symtable(sp,globalsymtable));
+            if assigned(aktprocsym) then
+             begin
+               {Check if it is a procedure.}
+               if aktprocsym^.typ<>procsym then
+                Message1(sym_e_duplicate_id,aktprocsym^.Name);
+               {The procedure has been found. So it is
+                a global one. Set the flags to mark this.}
+               procinfo.flags:=procinfo.flags or pi_is_global;
+             end;
+          end;
+       end;
+   end;
+  { problem with procedures inside methods }
+{$ifndef UseNiceNames}
+  if assigned(procinfo._class) then
+    if (pos('_$$_',procprefix)=0) then
+      hs:=procprefix+'_$$_'+procinfo._class^.name^+'_'+sp
+    else
+      hs:=procprefix+'_$'+sp;
+{$else UseNiceNames}
+  if assigned(procinfo._class) then
+    if (pos('_5Class_',procprefix)=0) then
+      hs:=procprefix+'_5Class_'+procinfo._class^.name^+'_'+tostr(length(sp))+sp
+    else
+      hs:=procprefix+'_'+tostr(length(sp))+sp;
+{$endif UseNiceNames}
+
+  if assigned(aktprocsym) then
+   begin
+     { Check if overloading is enabled }
+     if not(m_fpc in aktmodeswitches) then
+      begin
+        if aktprocsym^.typ<>procsym then
+         begin
+           Message1(sym_e_duplicate_id,aktprocsym^.name);
+           { try to recover by creating a new aktprocsym }
+           aktprocsym:=new(pprocsym,init(sp));
+         end
+        else
+         begin
+           if not(aktprocsym^.definition^.forwarddef) then
+            Message(parser_e_procedure_overloading_is_off);
+         end;
+      end
+     else
+      begin
+        { Check if the overloaded sym is realy a procsym }
+        if aktprocsym^.typ<>procsym then
+         begin
+           Message1(parser_e_overloaded_no_procedure,aktprocsym^.name);
+           { try to recover by creating a new aktprocsym }
+           aktprocsym:=new(pprocsym,init(sp));
+         end;
+      end;
+   end
+  else
+   begin
+     { create a new procsym and set the real filepos }
+     aktprocsym:=new(pprocsym,init(sp));
+     aktprocsym^.fileinfo:=realfilepos;
+     { for operator we have only one definition for each overloaded
+       operation }
+     if ((options and pooperator) <> 0) then
+       begin
+          { the only problem is that nextoverloaded might not be in a unit
+            known for the unit itself }
+          if assigned(overloaded_operators[optoken]) then
+            aktprocsym^.definition:=overloaded_operators[optoken]^.definition;
+       end;
+     symtablestack^.insert(aktprocsym);
+   end;
+
+{ create a new procdef }
+  pd:=new(pprocdef,init);
+  if assigned(procinfo._class) then
+    pd^._class := procinfo._class;
+
+  { set the options from the caller (podestructor or poconstructor) }
+  pd^.options:=pd^.options or options;
+
+  { calculate the offset of the parameters }
+  paramoffset:=8;
+
+  { calculate frame pointer offset }
+  if lexlevel>normal_function_level then
+    begin
+      procinfo.framepointer_offset:=paramoffset;
+      inc(paramoffset,target_os.size_of_pointer);
+    end;
+
+  if assigned (Procinfo._Class) and not(procinfo._class^.isclass) and
+     (((pd^.options and poconstructor)<>0) or ((pd^.options and podestructor)<>0)) then
+     inc(paramoffset,target_os.size_of_pointer);
+
+  { self pointer offset                              }
+  { self isn't pushed in nested procedure of methods }
+  if assigned(procinfo._class) and (lexlevel=normal_function_level) then
+    begin
+      procinfo.ESI_offset:=paramoffset;
+      inc(paramoffset,target_os.size_of_pointer);
+    end;
+
+  procinfo.call_offset:=paramoffset;
+
+  pd^.parast^.datasize:=0;
+
+  pd^.nextoverloaded:=aktprocsym^.definition;
+  aktprocsym^.definition:=pd;
+  aktprocsym^.definition^.setmangledname(hs);
+
+  overloaded_level:=1;
+  if assigned(pd^.nextoverloaded) and
+     (pd^.nextoverloaded^.owner^.symtabletype in [globalsymtable,staticsymtable]) then
+    begin
+       { we need another procprefix !!! }
+       { count, but only those in the same unit !!}
+       while assigned(pd^.nextoverloaded) and
+        (pd^.nextoverloaded^.owner^.symtabletype in [globalsymtable,staticsymtable]) do
+        begin
+          { only count already implemented functions }
+          if  not(pd^.forwarddef) then
+            inc(overloaded_level);
+          pd:=pd^.nextoverloaded;
+        end;
+     end;
+  if not parse_only then
+    procprefix:=hs+'$'+tostr(overloaded_level)+'$';
+
+  if token=LKLAMMER then
+    formal_parameter_list;
+  if ((options and pooperator)<>0) {and (overloaded_operators[optoken]=nil) } then
+    overloaded_operators[optoken]:=aktprocsym;
+end;
+
+
+procedure parse_proc_dec;
+var
+  hs : string;
+  isclassmethod : boolean;
+begin
+  inc(lexlevel);
+{ read class method }
+  if token=_CLASS then
+   begin
+     consume(_CLASS);
+     isclassmethod:=true;
+   end
+  else
+   isclassmethod:=false;
+  case token of
+     _FUNCTION : begin
+                   consume(_FUNCTION);
+                   parse_proc_head(0);
+                   if token<>COLON then
+                    begin
+                      if not(aktprocsym^.definition^.forwarddef) and
+                         not(m_repeat_forward in aktmodeswitches) then
+                       begin
+                         consume(COLON);
+                         consume_all_until(SEMICOLON);
+                       end;
+                    end
+                   else
+                    begin
+                      consume(COLON);
+                      aktprocsym^.definition^.retdef:=single_type(hs);
+                      aktprocsym^.definition^.test_if_fpu_result;
+                    end;
+                 end;
+    _PROCEDURE : begin
+                   consume(_PROCEDURE);
+                   parse_proc_head(0);
+                   aktprocsym^.definition^.retdef:=voiddef;
+                 end;
+  _CONSTRUCTOR : begin
+                   consume(_CONSTRUCTOR);
+                   parse_proc_head(poconstructor);
+                   if (procinfo._class^.options and oo_is_class)<>0 then
+                    begin
+                      { CLASS constructors return the created instance }
+                      aktprocsym^.definition^.retdef:=procinfo._class;
+                    end
+                   else
+                    begin
+                      { OBJECT constructors return a boolean }
+{$IfDef GDB}
+                      { GDB doesn't like unnamed types !}
+                      aktprocsym^.definition^.retdef:=globaldef('boolean');
+{$Else GDB}
+                      aktprocsym^.definition^.retdef:=new(porddef,init(bool8bit,0,1));
+{$Endif GDB}
+                    end;
+                 end;
+   _DESTRUCTOR : begin
+                   consume(_DESTRUCTOR);
+                   parse_proc_head(podestructor);
+                   aktprocsym^.definition^.retdef:=voiddef;
+                 end;
+     _OPERATOR : begin
+                   if lexlevel>normal_function_level then
+                     Message(parser_e_no_local_operator);
+                   consume(_OPERATOR);
+                   if not(token in [PLUS..last_overloaded]) then
+                     Message(parser_e_overload_operator_failed);
+                   optoken:=token;
+                   consume(Token);
+                   procinfo.flags:=procinfo.flags or pi_operator;
+                   parse_proc_head(pooperator);
+                   if token<>ID then
+                     consume(ID)
+                   else
+                     begin
+                       opsym:=new(pvarsym,init(pattern,voiddef));
+                       consume(ID);
+                     end;
+                   if token<>COLON then
+                     begin
+                       consume(COLON);
+                       aktprocsym^.definition^.retdef:=generrordef;
+                       consume_all_until(SEMICOLON);
+                     end
+                   else
+                    begin
+                      consume(COLON);
+                      aktprocsym^.definition^.retdef:=
+                       single_type(hs);
+                      aktprocsym^.definition^.test_if_fpu_result;
+                      if (optoken in [EQUAL,GT,LT,GTE,LTE]) and
+                         ((aktprocsym^.definition^.retdef^.deftype<>
+                         orddef) or (porddef(aktprocsym^.definition^.
+                         retdef)^.typ<>bool8bit)) then
+                        Message(parser_e_comparative_operator_return_boolean);
+                       opsym^.definition:=aktprocsym^.definition^.retdef;
+                     end;
+                 end;
+  end;
+  if isclassmethod and
+     assigned(aktprocsym) then
+    aktprocsym^.definition^.options:=aktprocsym^.definition^.options or poclassmethod;
+  consume(SEMICOLON);
+  dec(lexlevel);
+end;
+
+
+{****************************************************************************
+                        Procedure directive handlers
+****************************************************************************}
+
+{$ifdef tp}
+  {$F+}
+{$endif}
+
+procedure pd_far(const procnames:Tstringcontainer);
+begin
+  Message(parser_w_proc_far_ignored);
+end;
+
+procedure pd_near(const procnames:Tstringcontainer);
+begin
+  Message(parser_w_proc_near_ignored);
+end;
+
+procedure pd_export(const procnames:Tstringcontainer);
+begin
+  procnames.insert(realname);
+  procinfo.exported:=true;
+  if cs_link_deffile in aktglobalswitches then
+    deffile.AddExport(aktprocsym^.definition^.mangledname);
+  if assigned(procinfo._class) then
+    Message(parser_e_methods_dont_be_export);
+  if lexlevel<>normal_function_level then
+    Message(parser_e_dont_nest_export);
+end;
+
+procedure pd_inline(const procnames:Tstringcontainer);
+begin
+  if not(cs_support_inline in aktmoduleswitches) then
+   Message(parser_e_proc_inline_not_supported);
+end;
+
+procedure pd_forward(const procnames:Tstringcontainer);
+begin
+  aktprocsym^.definition^.forwarddef:=true;
+  aktprocsym^.properties:=aktprocsym^.properties or sp_forwarddef;
+end;
+
+procedure pd_stdcall(const procnames:Tstringcontainer);
+begin
+end;
+
+procedure pd_alias(const procnames:Tstringcontainer);
+begin
+  consume(COLON);
+  procnames.insert(get_stringconst);
+end;
+
+procedure pd_asmname(const procnames:Tstringcontainer);
+begin
+  aktprocsym^.definition^.setmangledname(target_os.Cprefix+pattern);
+  if token=CCHAR then
+    consume(CCHAR)
+  else
+    consume(CSTRING);
+  { we don't need anything else }
+  aktprocsym^.definition^.forwarddef:=false;
+end;
+
+procedure pd_intern(const procnames:Tstringcontainer);
+begin
+  consume(COLON);
+  aktprocsym^.definition^.extnumber:=get_intconst;
+end;
+
+procedure pd_system(const procnames:Tstringcontainer);
+begin
+  aktprocsym^.definition^.setmangledname(realname);
+end;
+
+
+procedure pd_cdecl(const procnames:Tstringcontainer);
+begin
+  if aktprocsym^.definition^.deftype<>procvardef then
+    aktprocsym^.definition^.setmangledname(target_os.Cprefix+realname);
+end;
+
+
+procedure pd_register(const procnames:Tstringcontainer);
+begin
+  Message(parser_w_proc_register_ignored);
+end;
+
+
+procedure pd_syscall(const procnames:Tstringcontainer);
+begin
+  aktprocsym^.definition^.options:=aktprocsym^.definition^.options or poclearstack;
+  aktprocsym^.definition^.forwarddef:=false;
+  aktprocsym^.definition^.extnumber:=get_intconst;
+end;
+
+
+procedure pd_external(const procnames:Tstringcontainer);
+{
+  If import_dll=nil the procedure is assumed to be in another
+  object file. In that object file it should have the name to
+  which import_name is pointing to. Otherwise, the procedure is
+  assumed to be in the DLL to which import_dll is pointing to. In
+  that case either import_nr<>0 or import_name<>nil is true, so
+  the procedure is either imported by number or by name. (DM)
+}
+var
+  import_dll,
+  import_name : string;
+  import_nr   : word;
+begin
+  aktprocsym^.definition^.forwarddef:=false;
+{ If the procedure should be imported from a DLL, a constant string follows.
+  This isn't really correct, an contant string expression follows
+  so we check if an semicolon follows, else a string constant have to
+  follow (FK) }
+  import_nr:=0;
+  import_name:='';
+  if not(token=SEMICOLON) and not(idtoken=_NAME) then
+    begin
+      import_dll:=get_stringconst;
+      if (idtoken=_NAME) then
+       begin
+         consume(_NAME);
+         import_name:=get_stringconst;
+       end;
+      if (idtoken=_INDEX) then
+       begin
+         {After the word index follows the index number in the DLL.}
+         consume(_INDEX);
+         import_nr:=get_intconst;
+       end;
+      if (import_nr=0) and (import_name='') then
+        Message(parser_w_empty_import_name);
+      if not(current_module^.uses_imports) then
+       begin
+         current_module^.uses_imports:=true;
+         importlib^.preparelib(current_module^.modulename^);
+       end;
+      importlib^.importprocedure(aktprocsym^.mangledname,import_dll,import_nr,import_name)
+    end
+  else
+    begin
+      if (idtoken=_NAME) then
+       begin
+         consume(_NAME);
+         aktprocsym^.definition^.setmangledname(get_stringconst);
+       end
+      else
+       begin
+         { external shouldn't override the cdecl/system name }
+         if (aktprocsym^.definition^.options and poclearstack)=0 then
+           aktprocsym^.definition^.setmangledname(aktprocsym^.name);
+         externals^.concat(new(pai_external,init(aktprocsym^.mangledname,EXT_NEAR)));
+       end;
+    end;
+end;
+
+{$ifdef TP}
+  {$F-}
+{$endif}
+
+function parse_proc_direc(const name:string;const proc_names:Tstringcontainer;var pdflags:word):boolean;
+{
+  Parse the procedure directive, returns true if a correct directive is found
+}
+const
+   namelength=15;
+type
+   pd_handler=procedure(const procnames:Tstringcontainer);
+   proc_dir_rec=record
+     name     : string[namelength]; {15 letters should be enough.}
+     handler  : pd_handler;         {Handler.}
+     flag     : longint;            {Procedure flag. May be zero}
+     pd_flags : longint;             {Parse options}
+     mut_excl : longint;             {List of mutually exclusive flags.}
+   end;
+const
+  {Should contain the number of procedure directives we support.}
+  num_proc_directives=21;
+  {Should contain the largest power of 2 lower than
+   num_proc_directives, the int value of the 2-log of it. Cannot be
+   calculated using an constant expression, as far as I know.}
+  num_proc_directives_2log=16;
+
+  proc_direcdata:array[1..num_proc_directives] of proc_dir_rec=
+   ((name:'ALIAS'     ;handler:{$ifdef FPC}@{$endif}pd_alias;
+      flag:0            ;pd_flags:pd_implemen+pd_body;
+      mut_excl:poinline+poexternal),
+    (name:'ASMNAME' ;handler:{$ifdef FPC}@{$endif}pd_asmname;
+      flag:pocdecl+poclearstack+poexternal;pd_flags:pd_interface+pd_implemen;
+      mut_excl:pointernproc+poexternal),
+    (name:'ASSEMBLER' ;handler:nil;
+      flag:poassembler  ;pd_flags:pd_implemen+pd_body;
+      mut_excl:pointernproc+poexternal),
+    (name:'CDECL'     ;handler:{$ifdef FPC}@{$endif}pd_cdecl;
+      flag:pocdecl+poclearstack;pd_flags:pd_interface+pd_implemen+pd_body+pd_procvar;
+      mut_excl:poleftright+poinline+poassembler+pointernproc+poexternal),
+    (name:'EXPORT'    ;handler:{$ifdef FPC}@{$endif}pd_export;
+      flag:poexports    ;pd_flags:pd_body+pd_global+pd_interface+pd_implemen{??};
+      mut_excl:poexternal+poinline+pointernproc+pointerrupt),
+    (name:'EXTERNAL'  ;handler:{$ifdef FPC}@{$endif}pd_external;
+      flag:poexternal   ;pd_flags:pd_implemen;
+      mut_excl:poexports+poinline+pointernproc+pointerrupt+poassembler+popalmossyscall),
+    (name:'FAR'       ;handler:{$ifdef FPC}@{$endif}pd_far;
+      flag:0            ;pd_flags:pd_implemen+pd_body+pd_interface+pd_procvar;
+      mut_excl:pointernproc),
+    (name:'FORWARD'   ;handler:{$ifdef FPC}@{$endif}pd_forward;
+      flag:0            ;pd_flags:pd_implemen;
+      mut_excl:pointernproc+poexternal),
+    (name:'INLINE'    ;handler:{$ifdef FPC}@{$endif}pd_inline;
+      flag:poinline     ;pd_flags:pd_implemen+pd_body;
+      mut_excl:poexports+poexternal+pointernproc+pointerrupt+poconstructor+podestructor),
+    (name:'INTERNCONST';handler:{$ifdef FPC}@{$endif}pd_intern;
+      flag:pointernconst;pd_flags:pd_implemen+pd_body;
+      mut_excl:pointernproc+pooperator),
+    (name:'INTERNPROC';handler:{$ifdef FPC}@{$endif}pd_intern;
+      flag:pointernproc ;pd_flags:pd_implemen;
+      mut_excl:poexports+poexternal+pointerrupt+poassembler+poclearstack+poleftright+poiocheck+
+               poconstructor+podestructor+pooperator),
+    (name:'INTERRUPT' ;handler:nil;
+      flag:pointerrupt  ;pd_flags:pd_implemen+pd_body;
+      mut_excl:pointernproc+poclearstack+poleftright+poinline+
+        poconstructor+podestructor+pooperator+poexternal),
+    (name:'IOCHECK'   ;handler:nil;
+      flag:poiocheck    ;pd_flags:pd_implemen+pd_body;
+      mut_excl:pointernproc+poexternal),
+    (name:'NEAR'      ;handler:{$ifdef FPC}@{$endif}pd_near;
+      flag:0            ;pd_flags:pd_implemen+pd_body+pd_procvar;
+      mut_excl:pointernproc),
+    (name:'PASCAL'    ;handler:nil;
+      flag:poleftright  ;pd_flags:pd_implemen+pd_body+pd_procvar;
+      mut_excl:pointernproc+poexternal),
+    (name:'POPSTACK'  ;handler:nil;
+      flag:poclearstack ;pd_flags:pd_interface+pd_implemen+pd_body+pd_procvar;
+      mut_excl:poinline+pointernproc+poassembler+poexternal),
+    (name:'PUBLIC'    ;handler:nil;
+      flag:0            ;pd_flags:pd_implemen+pd_body+pd_global;
+      mut_excl:pointernproc+poinline+poexternal),
+    (name:'REGISTER'    ;handler:{$ifdef FPC}@{$endif}pd_register;
+      flag:poregister   ;pd_flags:pd_interface+pd_implemen+pd_body+pd_procvar;
+      mut_excl:poleftright+pocdecl+pointernproc+poexternal),
+    (name:'STDCALL'    ;handler:{$ifdef FPC}@{$endif}pd_stdcall;
+      flag:postdcall    ;pd_flags:pd_interface+pd_implemen+pd_body+pd_procvar;
+      mut_excl:poleftright+pocdecl+pointernproc+poinline+poexternal),
+    (name:'SYSCALL'    ;handler:{$ifdef FPC}@{$endif}pd_syscall;
+      flag:popalmossyscall;pd_flags:pd_interface;
+      mut_excl:poexports+poinline+pointernproc+pointerrupt+poassembler+poexternal),
+    (name:'SYSTEM'     ;handler:{$ifdef FPC}@{$endif}pd_system;
+      flag:poclearstack ;pd_flags:pd_implemen;
+      mut_excl:poleftright+poinline+poassembler+pointernproc+poexternal));
+
+var
+  p,w : longint;
+begin
+  parse_proc_direc:=false;
+{ Search the procedure directive in the array. We shoot with a bazooka
+  on a bug, that is, we release a binary search }
+  p:=1;
+  if (length(name)<=namelength) then
+   begin
+     w:=num_proc_directives_2log;
+     while w<>0 do
+       begin
+         if proc_direcdata[p+w].name<=name then
+          inc(p,w);
+         w:=w shr 1;
+         while p+w>num_proc_directives do
+          w:=w shr 1;
+       end;
+   end;
+{ Check if the procedure directive is known }
+  if name<>proc_direcdata[p].name then
+   begin
+      { parsing a procvar type the name can be any
+        next variable !! }
+      if (pdflags and pd_procvar)=0 then
+        Message1(parser_w_unknown_proc_directive_ignored,name);
+      exit;
+   end;
+
+{ consume directive, and turn flag on }
+  consume(token);
+  parse_proc_direc:=true;
+
+{ Conflicts between directives ? }
+  if (aktprocsym^.definition^.options and proc_direcdata[p].mut_excl)<>0 then
+   begin
+     Message1(parser_e_proc_dir_conflict,name);
+     exit;
+   end;
+
+{ Check the pd_flags if the directive should be allowed }
+  if ((pdflags and pd_interface)<>0) and
+     ((proc_direcdata[p].pd_flags and pd_interface)=0) then
+    begin
+      Message1(parser_e_proc_dir_not_allowed_in_interface,name);
+      exit;
+    end;
+  if ((pdflags and pd_implemen)<>0) and
+     ((proc_direcdata[p].pd_flags and pd_implemen)=0) then
+    begin
+      Message1(parser_e_proc_dir_not_allowed_in_implementation,name);
+      exit;
+    end;
+  if ((pdflags and pd_procvar)<>0) and
+     ((proc_direcdata[p].pd_flags and pd_procvar)=0) then
+    begin
+      Message1(parser_e_proc_dir_not_allowed_in_procvar,name);
+      exit;
+    end;
+
+{ Return the new pd_flags }
+  if (proc_direcdata[p].pd_flags and pd_body)=0 then
+    pdflags:=pdflags and (not pd_body);
+  if (proc_direcdata[p].pd_flags and pd_global)<>0 then
+    pdflags:=pdflags or pd_global;
+
+{ Add the correct flag }
+  aktprocsym^.definition^.options:=aktprocsym^.definition^.options or proc_direcdata[p].flag;
+
+{ Call the handler }
+  if pointer({$ifndef FPC}@{$endif}proc_direcdata[p].handler)<>nil then
+    proc_direcdata[p].handler(proc_names);
+end;
+
+{***************************************************************************}
+
+function check_identical:boolean;
+{
+  Search for idendical definitions,
+  if there is a forward, then kill this.
+
+  Returns the result of the forward check.
+
+  Removed from unter_dec to keep the source readable
+}
+const
+{List of procedure options that affect the procedure type.}
+  po_type_params=poconstructor+podestructor+pooperator;
+
+  po_call_params=pocdecl+poclearstack+poleftright+poregister;
+
+var
+  hd,pd : Pprocdef;
+  storeparast : psymtable;
+  ad,fd : psym;
+begin
+  check_identical:=false;
+  pd:=aktprocsym^.definition;
+  if assigned(pd) then
+   begin
+   { Is there an overload/forward ? }
+     if assigned(pd^.nextoverloaded) then
+      begin
+      { walk the procdef list }
+        while (assigned(pd)) and (assigned(pd^.nextoverloaded)) do
+         begin
+           if not(m_repeat_forward in aktmodeswitches) or
+              equal_paras(aktprocsym^.definition^.para1,pd^.nextoverloaded^.para1,false) then
+             begin
+               if pd^.nextoverloaded^.forwarddef then
+               { remove the forward definition  but don't delete it,          }
+               { the symtable is the owner !!  }
+                 begin
+                   hd:=pd^.nextoverloaded;
+                 { Check if the procedure type and return type are correct }
+                   if ((hd^.options and po_type_params)<>(aktprocsym^.definition^.options and po_type_params)) or
+                      (not(is_equal(hd^.retdef,aktprocsym^.definition^.retdef)) and
+                      (m_repeat_forward in aktmodeswitches)) then
+                     begin
+                       Message1(parser_e_header_dont_match_forward,aktprocsym^.demangledName);
+                       exit;
+                     end;
+                 { Check calling convention }
+                   if ((hd^.options and po_call_params)<>(aktprocsym^.definition^.options and po_call_params)) then
+                    begin
+                    { only trigger a error, becuase it doesn't hurt }
+                      Message(parser_e_call_convention_dont_match_forward);
+                    end;
+                 { manglednames are equal? }
+                   if (m_repeat_forward in aktmodeswitches) or
+                      assigned(aktprocsym^.definition^.parast^.root) then
+                    if (hd^.mangledname<>aktprocsym^.definition^.mangledname) then
+                     begin
+                       if (aktprocsym^.definition^.options and poexternal)=0 then
+                         Message(parser_n_interface_name_diff_implementation_name);
+                     { reset the mangledname of the interface part to be sure }
+                     { this is wrong because the mangled name might have been used already !! }
+                     { hd^.setmangledname(aktprocsym^.definition^.mangledname);}
+                     { so we need to keep the name of interface !! }
+                       aktprocsym^.definition^.setmangledname(hd^.mangledname);
+                     end
+                   else
+                     begin
+                     { If mangled names are equal, therefore    }
+                     { they have the same number of parameters  }
+                     { Therefore we can check the name of these }
+                     { parameters...                            }
+                       if hd^.forwarddef and aktprocsym^.definition^.forwarddef then
+                         begin
+                           Message1(parser_e_function_already_declared_public_forward,aktprocsym^.demangledName);
+                           Check_identical:=true;
+                         { Remove other forward from the list to reduce errors }
+                           pd^.nextoverloaded:=pd^.nextoverloaded^.nextoverloaded;
+                           exit;
+                         end;
+
+                       ad:=hd^.parast^.root;
+                       fd:=aktprocsym^.definition^.parast^.root;
+                       if assigned(ad) and assigned(fd) then
+                         begin
+                           while assigned(ad) and assigned(fd) do
+                             begin
+                               if ad^.name<>fd^.name then
+                                 begin
+                                   Message3(parser_e_header_different_var_names,
+                                     aktprocsym^.name,ad^.name,fd^.name);
+                                   break;
+                                 end;
+                             { it is impossible to have a nil pointer }
+                             { for only one parameter - since they    }
+                             { have the same number of parameters.    }
+                             { Left = next parameter.                 }
+                               ad:=ad^.left;
+                               fd:=fd^.left;
+                             end;
+                         end;
+                     end;
+                 { also the call_offset }
+                   hd^.parast^.call_offset:=aktprocsym^.definition^.parast^.call_offset;
+
+                 { remove pd^.nextoverloaded from the list }
+                 { and add aktprocsym^.definition }
+                   pd^.nextoverloaded:=pd^.nextoverloaded^.nextoverloaded;
+                   hd^.nextoverloaded:=aktprocsym^.definition^.nextoverloaded;
+                 { Alert! All fields of aktprocsym^.definition that are modified
+                   by the procdir handlers must be copied here!.}
+                   hd^.forwarddef:=false;
+                   hd^.options:=hd^.options or aktprocsym^.definition^.options;
+                   if aktprocsym^.definition^.extnumber=-1 then
+                     aktprocsym^.definition^.extnumber:=hd^.extnumber
+                   else
+                     if hd^.extnumber=-1 then
+                       hd^.extnumber:=aktprocsym^.definition^.extnumber;
+                   { switch parast for warning in implementation  PM }
+                   if (m_repeat_forward in aktmodeswitches) or
+                      assigned(aktprocsym^.definition^.parast^.root) then
+                     begin
+                        storeparast:=hd^.parast;
+                        hd^.parast:=aktprocsym^.definition^.parast;
+                        aktprocsym^.definition^.parast:=storeparast;
+                     end;
+                   aktprocsym^.definition:=hd;
+                   check_identical:=true;
+                 end
+               else
+               { abstract methods aren't forward defined, but this }
+               { needs another error message                       }
+                 if (pd^.nextoverloaded^.options and poabstractmethod)=0 then
+                   Message(parser_e_overloaded_have_same_parameters)
+                 else
+                   Message(parser_e_abstract_no_definition);
+               break;
+             end;
+           pd:=pd^.nextoverloaded;
+         end;
+      end
+     else
+      begin
+      { there is no overloaded, so its always identical with itself }
+        check_identical:=true;
+      end;
+   end;
+{ insert opsym only in the right symtable }
+  if ((procinfo.flags and pi_operator)<>0) and not parse_only then
+    begin
+      if ret_in_param(aktprocsym^.definition^.retdef) then
+        begin
+          pprocdef(aktprocsym^.definition)^.parast^.insert(opsym);
+        { this increases the data size }
+        { correct this to get the right ret $value }
+          dec(pprocdef(aktprocsym^.definition)^.parast^.datasize,opsym^.getsize);
+          { this allows to read the funcretoffset }
+          opsym^.address:=-4;
+          opsym^.varspez:=vs_var;
+        end
+      else
+        pprocdef(aktprocsym^.definition)^.localst^.insert(opsym);
+    end;
+end;
+
+procedure compile_proc_body(const proc_names:Tstringcontainer;
+                            make_global,parent_has_class:boolean);
+{
+  Compile the body of a procedure
+}
+var
+   oldexitlabel,oldexit2label,oldquickexitlabel:Plabel;
+   _class,hp:Pobjectdef;
+   { switches can change inside the procedure }
+   entryswitches, exitswitches : tlocalswitches;
+   { code for the subroutine as tree }
+   code:ptree;
+   { size of the local strackframe }
+   stackframe:longint;
+   { true when no stackframe is required }
+   nostackframe:boolean;
+   { number of bytes which have to be cleared by RET }
+   parasize:longint;
+   { filepositions }
+   entrypos,
+   savepos,
+   exitpos   : tfileposinfo;
+begin
+   { calculate the lexical level }
+   inc(lexlevel);
+   if lexlevel>32 then
+    Message(parser_e_too_much_lexlevel);
+   { save old labels }
+   oldexitlabel:=aktexitlabel;
+   oldexit2label:=aktexit2label;
+   oldquickexitlabel:=quickexitlabel;
+   { get new labels }
+   getlabel(aktexitlabel);
+   getlabel(aktexit2label);
+   { exit for fail in constructors }
+   if (aktprocsym^.definition^.options and poconstructor)<>0 then
+     getlabel(quickexitlabel);
+   { reset break and continue labels }
+   in_except_block:=false;
+   aktbreaklabel:=nil;
+   aktcontinuelabel:=nil;
+
+   { insert symtables for the class, by only if it is no nested function }
+   if assigned(procinfo._class) and not(parent_has_class) then
+     begin
+       { insert them in the reverse order ! }
+       hp:=nil;
+       repeat
+         _class:=procinfo._class;
+         while _class^.childof<>hp do
+           _class:=_class^.childof;
+         hp:=_class;
+         _class^.publicsyms^.next:=symtablestack;
+         symtablestack:=_class^.publicsyms;
+       until hp=procinfo._class;
+     end;
+
+   { insert parasymtable in symtablestack}
+   { only if lexlevel > 1 !!! global symtable should be right after staticsymtazble
+     for checking of same names used in interface and implementation !! }
+   if lexlevel>=normal_function_level then
+     begin
+        aktprocsym^.definition^.parast^.next:=symtablestack;
+        symtablestack:=aktprocsym^.definition^.parast;
+        symtablestack^.symtablelevel:=lexlevel;
+     end;
+   { insert localsymtable in symtablestack}
+   aktprocsym^.definition^.localst^.next:=symtablestack;
+   symtablestack:=aktprocsym^.definition^.localst;
+   symtablestack^.symtablelevel:=lexlevel;
+   { constant symbols are inserted in this symboltable }
+   constsymtable:=symtablestack;
+
+   { reset the temporary memory }
+   cleartempgen;
+   { no registers are used }
+   usedinproc:=0;
+
+   { save entry info }
+   entrypos:=aktfilepos;
+   entryswitches:=aktlocalswitches;
+
+   { parse the code ... }
+   if (aktprocsym^.definition^.options and poassembler)<> 0 then
+     code:=assembler_block
+   else
+     code:=block(current_module^.islibrary);
+
+   { get a better entry point }
+   if assigned(code) then
+     entrypos:=code^.fileinfo;
+
+   { save exit info }
+   exitswitches:=aktlocalswitches;
+   exitpos:=last_endtoken_filepos;
+
+   { save current filepos }
+   savepos:=aktfilepos;
+
+   {When we are called to compile the body of a unit, aktprocsym should
+    point to the unit initialization. If the unit has no initialization,
+    aktprocsym=nil. But in that case code=nil. hus we should check for
+    code=nil, when we use aktprocsym.}
+
+   { set the framepointer to esp for assembler functions }
+   { but only if the are no local variables              }
+   { already done in assembler_block }
+   setfirsttemp(procinfo.firsttemp);
+
+   { ... and generate assembler }
+   { but set the right switches for entry !! }
+   aktlocalswitches:=entryswitches;
+   if assigned(code) then
+     generatecode(code);
+   { set switches to status at end of procedure }
+   aktlocalswitches:=exitswitches;
+
+   if assigned(code) then
+     begin
+        aktprocsym^.definition^.code:=code;
+
+        { the procedure is now defined }
+        aktprocsym^.definition^.forwarddef:=false;
+        aktprocsym^.definition^.usedregisters:=usedinproc;
+     end;
+
+   stackframe:=gettempsize;
+   { only now we can remove the temps }
+   resettempgen;
+
+   { first generate entry code with the correct position and switches }
+   aktfilepos:=entrypos;
+   aktlocalswitches:=entryswitches;
+   if assigned(code) then
+     genentrycode(procinfo.aktentrycode,proc_names,make_global,stackframe,parasize,nostackframe,false);
+
+   { now generate exit code with the correct position and switches }
+   aktfilepos:=exitpos;
+   aktlocalswitches:=exitswitches;
+   if assigned(code) then
+     begin
+       genexitcode(procinfo.aktexitcode,parasize,nostackframe,false);
+       procinfo.aktproccode^.insertlist(procinfo.aktentrycode);
+       procinfo.aktproccode^.concatlist(procinfo.aktexitcode);
+{$ifdef i386}
+ {$ifndef NoOpt}
+       if (cs_optimize in aktglobalswitches) and
+       { no asm block allowed }
+         ((procinfo.flags and pi_uses_asm)=0)  then
+           Optimize(procinfo.aktproccode);
+ {$endif NoOpt}
+{$endif}
+       { save local data (casetable) also in the same file }
+       if assigned(procinfo.aktlocaldata) and
+          (not procinfo.aktlocaldata^.empty) then
+         begin
+            procinfo.aktproccode^.concat(new(pai_section,init(sec_data)));
+            procinfo.aktproccode^.concatlist(procinfo.aktlocaldata);
+         end;
+       { now we can insert a cut }
+       if (cs_smartlink in aktmoduleswitches) then
+         codesegment^.concat(new(pai_cut,init));
+
+       { add the procedure to the codesegment }
+       codesegment^.concatlist(procinfo.aktproccode);
+     end;
+
+   { ... remove symbol tables, for the browser leave the static table }
+{    if (cs_browser in aktmoduleswitches) and (symtablestack^.symtabletype=staticsymtable) then
+    symtablestack^.next:=symtablestack^.next^.next
+   else }
+   if lexlevel>=normal_function_level then
+     symtablestack:=symtablestack^.next^.next
+   else
+     symtablestack:=symtablestack^.next;
+
+   { ... check for unused symbols      }
+   { but only if there is no asm block }
+   if assigned(code) then
+     begin
+       if (status.errorcount=0) then
+         begin
+           aktprocsym^.definition^.localst^.check_forwards;
+           aktprocsym^.definition^.localst^.checklabels;
+         end;
+       if (procinfo.flags and pi_uses_asm)=0 then
+         begin
+            { not for unit init, becuase the var can be used in finalize,
+              it will be done in proc_unit }
+            if (aktprocsym^.definition^.options and (pounitinit or pounitfinalize))=0 then
+              aktprocsym^.definition^.localst^.allsymbolsused;
+            aktprocsym^.definition^.parast^.allsymbolsused;
+         end;
+     end;
+
+   { the local symtables can be deleted, but the parast   }
+   { doesn't, (checking definitons when calling a         }
+   { function                                             }
+   { not for a inline procedure !!                 (PM)   }
+   { at lexlevel = 1 localst is the staticsymtable itself }
+   { so no dispose here !!                                }
+   if assigned(code) and
+      not(cs_browser in aktmoduleswitches) and
+      ((aktprocsym^.definition^.options and poinline)=0) then
+     begin
+       if lexlevel>=normal_function_level then
+         dispose(aktprocsym^.definition^.localst,done);
+       aktprocsym^.definition^.localst:=nil;
+     end;
+
+    { remove code tree, if not inline procedure }
+    if assigned(code) and ((aktprocsym^.definition^.options and poinline)=0) then
+      disposetree(code);
+
+   { remove class member symbol tables }
+   while symtablestack^.symtabletype=objectsymtable do
+     symtablestack:=symtablestack^.next;
+
+   { restore filepos, the switches are already set }
+   aktfilepos:=savepos;
+   { free labels }
+   freelabel(aktexitlabel);
+   freelabel(aktexit2label);
+   if (aktprocsym^.definition^.options and poconstructor)<>0 then
+    freelabel(quickexitlabel);
+   { restore labels }
+   aktexitlabel:=oldexitlabel;
+   aktexit2label:=oldexit2label;
+   quickexitlabel:=oldquickexitlabel;
+   { previous lexlevel }
+   dec(lexlevel);
+end;
+
+
+procedure parse_proc_directives(Anames:Pstringcontainer;var pdflags:word);
+{
+  Parse the procedure directives. It does not matter if procedure directives
+  are written using ;procdir; or ['procdir'] syntax.
+}
+var
+  name : string;
+  res  : boolean;
+begin
+  while token in [ID,LECKKLAMMER] do
+   begin
+     if token=LECKKLAMMER then
+      begin
+        consume(LECKKLAMMER);
+        repeat
+          name:=pattern;
+          { consume(ID);
+          now done in the function }
+          parse_proc_direc(name,Anames^,pdflags);
+          if token=COMMA then
+           consume(COMMA)
+          else
+           break;
+        until false;
+        consume(RECKKLAMMER);
+        { we always expect at least '[];' }
+        res:=true;
+      end
+     else
+      begin
+        name:=pattern;
+        res:=parse_proc_direc(name,Anames^,pdflags);
+      end;
+   { A procedure directive is always followed by a semicolon }
+     if res then
+      consume(SEMICOLON)
+     else
+      break;
+   end;
+end;
+
+procedure parse_var_proc_directives(var sym : ptypesym);
+var
+  anames : pstringcontainer;
+  pdflags : word;
+  oldsym : pprocsym;
+begin
+  oldsym:=aktprocsym;
+  anames:=new(pstringcontainer,init);
+  pdflags:=pd_procvar;
+  { we create a temporary aktprocsym to read the directives }
+  aktprocsym:=new(pprocsym,init(sym^.name));
+  aktprocsym^.definition:=pprocdef(sym^.definition);
+  { anmes should never be used anyway }
+  inc(lexlevel);
+  parse_proc_directives(anames,pdflags);
+  dec(lexlevel);
+  aktprocsym^.definition:=nil;
+  dispose(aktprocsym,done);
+  dispose(anames,done);
+  aktprocsym:=oldsym;
+end;
+
+
+procedure read_proc;
+{
+  Parses the procedure directives, then parses the procedure body, then
+  generates the code for it
+}
+var
+  oldprefix        : string;
+  oldprocsym       : Pprocsym;
+  oldprocinfo      : tprocinfo;
+  oldconstsymtable : Psymtable;
+  names            : Pstringcontainer;
+  pdflags          : word;
+begin
+{ save old state }
+   oldprocsym:=aktprocsym;
+   oldprefix:=procprefix;
+   oldconstsymtable:=constsymtable;
+   oldprocinfo:=procinfo;
+{ create a new procedure }
+   new(names,init);
+   codegen_newprocedure;
+   with procinfo do
+    begin
+      parent:=@oldprocinfo;
+    { clear flags }
+      flags:=0;
+    { standard frame pointer }
+      framepointer:=frame_pointer;
+      funcret_is_valid:=false;
+    { is this a nested function of a method ? }
+      _class:=oldprocinfo._class;
+    end;
+
+   parse_proc_dec;
+
+{ set the default function options }
+   if parse_only then
+    begin
+      aktprocsym^.properties:=aktprocsym^.properties or sp_forwarddef;
+      aktprocsym^.definition^.forwarddef:=true;
+      pdflags:=pd_interface;
+    end
+   else
+    begin
+      pdflags:=pd_body;
+      if current_module^.in_implementation then
+       pdflags:=pdflags or pd_implemen;
+      if (not current_module^.is_unit) or (cs_smartlink in aktmoduleswitches) then
+       pdflags:=pdflags or pd_global;
+      procinfo.exported:=false;
+      aktprocsym^.definition^.forwarddef:=false;
+    end;
+
+{ parse the directives that may follow }
+   inc(lexlevel);
+   parse_proc_directives(names,pdflags);
+   dec(lexlevel);
+
+{ search for forward declarations }
+   if (not check_identical) then
+     begin
+     { A method must be forward defined (in the object declaration) }
+       if assigned(procinfo._class) and (not assigned(oldprocinfo._class)) then
+         Message(parser_e_header_dont_match_any_member);
+     { check the global flag }
+       if (procinfo.flags and pi_is_global)<>0 then
+         Message(parser_e_overloaded_must_be_all_global);
+     end;
+
+{ set return type here, becuase the aktprocsym^.definition can be
+  changed by check_identical (PFV) }
+   procinfo.retdef:=aktprocsym^.definition^.retdef;
+
+   { pointer to the return value ? }
+   if ret_in_param(procinfo.retdef) then
+    begin
+      procinfo.retoffset:=procinfo.call_offset;
+      inc(procinfo.call_offset,target_os.size_of_pointer);
+    end;
+   { allows to access the parameters of main functions in nested functions }
+   aktprocsym^.definition^.parast^.call_offset:=procinfo.call_offset;
+
+{ compile procedure when a body is needed }
+   if (pdflags and pd_body)<>0 then
+     begin
+       Message1(parser_p_procedure_start,aktprocsym^.demangledname);
+       names^.insert(aktprocsym^.definition^.mangledname);
+      { set _FAIL as keyword if constructor }
+      if (aktprocsym^.definition^.options and poconstructor)<>0 then
+        tokeninfo[_FAIL].keyword:=m_all;
+      if assigned(aktprocsym^.definition^._class) then
+        tokeninfo[_SELF].keyword:=m_all;
+       compile_proc_body(names^,((pdflags and pd_global)<>0),assigned(oldprocinfo._class));
+      { reset _FAIL as normal }
+      if (aktprocsym^.definition^.options and poconstructor)<>0 then
+        tokeninfo[_FAIL].keyword:=m_none;
+      if assigned(aktprocsym^.definition^._class) and (lexlevel=main_program_level) then
+        tokeninfo[_SELF].keyword:=m_none;
+       consume(SEMICOLON);
+     end;
+{ close }
+   dispose(names,done);
+   codegen_doneprocedure;
+{ Restore old state }
+   constsymtable:=oldconstsymtable;
+   aktprocsym:=oldprocsym;
+   procprefix:=oldprefix;
+   procinfo:=oldprocinfo;
+   opsym:=nil;
+end;
+
+end.
+
+{
+  $Log$
+  Revision 1.1  1998-12-26 15:20:31  florian
+    + more changes for the new version
+
+}

+ 5 - 2
compiler/new/systems.pas

@@ -181,7 +181,7 @@ unit systems;
           heapsize,
           maxheapsize,
           stacksize   : longint;
-          flags       : ttargetflags;
+          flags       : set of ttargetflags;
        end;
 
        tasmmodeinfo=packed record
@@ -1227,7 +1227,10 @@ begin
 end.
 {
   $Log$
-  Revision 1.2  1998-12-15 22:18:58  florian
+  Revision 1.3  1998-12-26 15:20:31  florian
+    + more changes for the new version
+
+  Revision 1.2  1998/12/15 22:18:58  florian
     * some code added
 
   Revision 1.1  1998/12/15 16:32:59  florian

+ 273 - 94
compiler/new/tree.pas

@@ -191,23 +191,61 @@ unit tree;
           error : boolean;
           constructor init;
           destructor done;virtual;
+          { runs det_resulttype and det_temp }
+          procedure pass_1;
+          { dermines the resulttype of the node }
+          procedure det_resulttype;virtual;
+          { dermines the number of necessary temp. locations to evalute
+            the node }
+          procedure det_temp;virtual;
+          procedure secondpass;virtual;
        end;
 
-       ploadnode = object(tnode)
+       ploadnode = ^tloadnode;
+
+       tloadnode = object(tnode)
           symtableentry : psym;
           symtable : psymtable;
           is_absolute,is_first,is_methodpointer : boolean;
-          constructor init;
+          constructor init(v : pvarsym;st : psymtable);
           destructor done;virtual;
        end;
 
-          left,right : ptree;
-          { is true, if the right and left operand are swaped }
+{$ifndef nooldtree}
+       { allows to determine which elementes are to be replaced }
+       tdisposetyp = (dt_nothing,dt_leftright,dt_left,
+                      dt_mbleft,dt_typeconv,dt_inlinen,
+                      dt_mbleft_and_method,dt_loop,dt_case,dt_with,dt_onn);
+
+       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;
+          fileinfo : tfileposinfo;
+          localswitches : tlocalswitches;
+{$ifdef extdebug}
+          firstpasscount : longint;
+{$endif extdebug}
           case treetype : ttreetyp of
              addn : (use_strconcat : boolean;string_typ : tstringtype);
              callparan : (is_colon_para : boolean;exact_match_found : boolean);
              assignn : (assigntyp : tassigntyp;concat_string : boolean);
+             loadn : (symtableentry : psym;symtable : psymtable;
+                      is_absolute,is_first,is_methodpointer : boolean);
              calln : (symtableprocentry : psym;
                       symtableproc : psymtable;procdefinition : pprocdef;
                       methodpointer : ptree;
@@ -232,6 +270,54 @@ unit tree;
              withn : (withsymtable : psymtable;tablecount : longint);
              onn : (exceptsymtable : psymtable;excepttype : pobjectdef);
              arrayconstructn : (cargs,cargswap: boolean);
+           end;
+{$endif}
+          punarynode = ^tunarynode;
+          tunarynode = object(tnode)
+             left : pnode;
+          end;
+
+          pbinarynode = ^tbinarynode;
+          tbinarynode = object(tunarynode)
+             right : pnode;
+          end;
+
+          pbinopnode = ^tbinopnode;
+          tbinopnode = object(tbinarynode)
+             { is true, if the right and left operand are swaped }
+             { against the original order                        }
+             swaped : boolean;
+          end;
+
+{$ifdef dummy}
+          case treetype : ttreetyp of
+             addn : (use_strconcat : boolean;string_typ : tstringtype);
+             callparan : (is_colon_para : boolean;exact_match_found : boolean);
+             assignn : (assigntyp : tassigntyp;concat_string : boolean);
+             calln : (symtableprocentry : psym;
+                      symtableproc : psymtable;procdefinition : pprocdef;
+                      methodpointer : ptree;
+                      no_check,unit_specific,return_value_used : boolean);
+             ordconstn : (value : longint);
+             realconstn : (value_real : bestreal;lab_real : plabel;realtyp : tait);
+             fixconstn : (value_fix: longint);
+             funcretn : (funcretprocinfo : pointer;retdef : pdef);
+             subscriptn : (vs : pvarsym);
+             vecn : (memindex,memseg:boolean;callunique : boolean);
+             stringconstn : (value_str : pchar;length : longint; lab_str : plabel;stringtype : tstringtype);
+             typeconvn : (convtyp : tconverttype;explizit : boolean);
+             typen : (typenodetype : pdef);
+             inlinen : (inlinenumber : byte;inlineconst:boolean);
+             procinlinen : (inlineprocdef : pprocdef;
+                            retoffset,para_offset,para_size : longint);
+             setconstn : (value_set : pconstset;lab_set:plabel);
+             loopn : (t1,t2 : ptree;backward : boolean);
+             casen : (nodes : pcaserecord;elseblock : ptree);
+             labeln,goton : (labelnr : plabel);
+             withn : (withsymtable : psymtable;tablecount : longint);
+             onn : (exceptsymtable : psymtable;excepttype : pobjectdef);
+             arrayconstructn : (cargs,cargswap: boolean);
+{$endif dummy}
 
     function gennode(t : ttreetyp;l,r : ptree) : ptree;
     function genlabelnode(t : ttreetyp;nr : plabel) : ptree;
@@ -342,11 +428,36 @@ unit tree;
 {$endif extdebug}
       end;
 
+    procedure tnode.pass_1;
+
+      begin
+         det_resulttype;
+         det_temp;
+      end;
+
+    procedure tnode.det_resulttype;
+
+      begin
+         abstract;
+      end;
+
+    procedure tnode.det_temp;
+
+      begin
+         abstract;
+      end;
+
+    procedure tnode.secondpass;
+
+      begin
+         abstract;
+      end;
+
 {****************************************************************************
                                  TLOADNODE
  ****************************************************************************}
 
-    constructor tloadnode.init(v : pvarsym;st : psymtable) : ptree;
+    constructor tloadnode.init(v : pvarsym;st : psymtable);
 
       var
          p : ptree;
@@ -373,7 +484,6 @@ unit tree;
       end;
 
 {$ifdef dummy}
-
          { clean up the contents of a node }
          case p^.treetype of
           asmn : if assigned(p^.p_asm) then
@@ -386,7 +496,7 @@ unit tree;
                      dispose(p^.value_set);
                  end;
          end;
-
+{$endif dummy}
 
     procedure deletecaselabels(p : pcaserecord);
 
@@ -412,6 +522,27 @@ unit tree;
         p^.swaped:=not(p^.swaped);
     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;
 
     procedure disposetree(p : ptree);
 
@@ -511,6 +642,137 @@ unit tree;
         p^.fileinfo:=filepos;
      end;
 
+    function getnode : ptree;
+
+      var
+         hp : ptree;
+
+      begin
+         new(hp);
+         { makes error tracking easier }
+         fillchar(hp^,sizeof(ttree),0);
+         { reset }
+         hp^.location.loc:=LOC_INVALID;
+         { save local info }
+         hp^.fileinfo:=aktfilepos;
+         hp^.localswitches:=aktlocalswitches;
+         getnode:=hp;
+      end;
+
+
+    procedure putnode(p : ptree);
+      begin
+         { clean up the contents of a node }
+         case p^.treetype of
+          asmn : if assigned(p^.p_asm) then
+                  dispose(p^.p_asm,done);
+  stringconstn : begin
+                   ansistringdispose(p^.value_str,p^.length);
+                 end;
+     setconstn : begin
+                   if assigned(p^.value_set) then
+                     dispose(p^.value_set);
+                 end;
+         end;
+         { reference info }
+         if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
+            assigned(p^.location.reference.symbol) then
+           stringdispose(p^.location.reference.symbol);
+{$ifdef extdebug}
+         if p^.firstpasscount>maxfirstpasscount then
+            maxfirstpasscount:=p^.firstpasscount;
+{$endif extdebug}
+         dispose(p);
+      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_typeconv : hp^.left:=getcopy(p^.left);
+            dt_inlinen :
+              if assigned(p^.left) then
+                hp^.left:=getcopy(p^.left);
+            else internalerror(11);
+         end;
+       { now check treetype }
+         case p^.treetype of
+  stringconstn : begin
+                   hp^.value_str:=getpcharcopy(p);
+                   hp^.length:=p^.length;
+                 end;
+     setconstn : begin
+                   new(hp^.value_set);
+                   hp^.value_set:=p^.value_set;
+                 end;
+         end;
+         getcopy:=hp;
+      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^.is_methodpointer:=false;
+         { method pointer load nodes can use the left subtree }
+         p^.disposetyp:=dt_left;
+         p^.left:=nil;
+         genloadnode:=p;
+      end;
+
    function genwithnode(symtable : psymtable;l,r : ptree;count : longint) : ptree;
 
       var
@@ -582,28 +844,6 @@ unit tree;
          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
@@ -1532,74 +1772,13 @@ unit tree;
         is_emptyset:=(i=32);
       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_typeconv : hp^.left:=getcopy(p^.left);
-            dt_inlinen :
-              if assigned(p^.left) then
-                hp^.left:=getcopy(p^.left);
-            else internalerror(11);
-         end;
-       { now check treetype }
-         case p^.treetype of
-  stringconstn : begin
-                   hp^.value_str:=getpcharcopy(p);
-                   hp^.length:=p^.length;
-                 end;
-     setconstn : begin
-                   new(hp^.value_set);
-                   hp^.value_set:=p^.value_set;
-                 end;
-         end;
-         getcopy:=hp;
-      end;
-
-{$endif dummy}
-
 end.
 {
   $Log$
-  Revision 1.1  1998-12-15 22:21:53  florian
+  Revision 1.2  1998-12-26 15:20:32  florian
+    + more changes for the new version
+
+  Revision 1.1  1998/12/15 22:21:53  florian
     * first rough conversion
 
 }