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

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

 ****************************************************************************}
{$I-}
unit symtable;

  interface

    uses
       objects,cobjects,systems,globals,asmgen,dos,strings;

    const
       { Symboltabellentypen }

       localsymtable = $8000;
       parasymtable = $4000;

       withsymtable = 1;
       staticsymtable = 2;
       globalsymtable = 3;
       unitsymtable = 4;
       objectsymtable = 5;
       recordsymtable = 6;
       macrosymtable = 7;

       { Konstanten für Unterprogrammoptionen }
       poexceptions = $1;
       povirtualmethod = $2;
       poclearstack = $4;
       poconstructor = $8;
       podestructor = $10;
       pointernproc = $20;
       poexports = $40;
       poiocheck = $80;

       hasharraysize = 97;

       { last operator which can overloaded }
       last_overloaded = PLUS;

    type
       { "forward" pointer }

       pformaldef = ^tformaldef;
       pfiledef = ^tfiledef;
       pclassdef = ^tclassdef;
       precdef = ^trecdef;
       parraydef = ^tarraydef;
       ppointerdef = ^tpointerdef;
       pstringdef = ^tstringdef;
       paufzaehldef = ^taufzaehldef;
       pgrunddef = ^tgrunddef;
       pprocdef = ^tprocdef;
       perrordef = ^terrordef;
       psetdef = ^tsetdef;
       psymtable = ^tsymtable;
       pdef = ^tdef;
       pprocvardef = ^tprocvardef;
       pabstractprocdef = ^tabstractprocdef;
       psym = ^tsym;
       plabelsym = ^tlabelsym;

       { Grundtypen }

       tgrundtyp = (uauto,u8bit,s32bit,s64real,uvoid,bool8bit,uchar,
                      s8bit,s16bit,u16bit);

       { Symboltabelleneinträge }

       tsymtyp = (abstractsym,varsym,typesym,procsym,unitsym,programsym,
                  constsym,aufzaehlsym,typedconstsym,errorsym,syssym,
                  labelsym);

       tsym = object
          typ : tsymtyp;
          _name : pchar;
          left : psym;
          right : psym;
          speedvalue : longint;
          forwarddef : boolean;
          constructor init(const n : string);
          constructor load;
          destructor done;virtual;
          procedure write;virtual;
          procedure deref;virtual;
          function name : string;
          procedure setname(const s : string);
       end;

       tlabelsym = object(tsym)
          number : longint;
          defined : boolean;
          constructor init(const n : string;l : longint);
          destructor done;virtual;
          procedure write;virtual;
       end;

       punitsym = ^tunitsym;

       tunitsym = object(tsym)
          unitsymtable : psymtable;
          constructor init(const n : string;ref : psymtable);
          procedure write;virtual;
       end;

       pmacrosym = ^tmacrosym;

       tmacrosym = object(tsym)
          defined : boolean;
       end;

       perrorsym = ^terrorsym;

       terrorsym = object(tsym)
          constructor init;
       end;

       pprocsym = ^tprocsym;

       tprocsym = object(tsym)
          definition : pprocdef;
          constructor init(const n : string);
          constructor load;
          destructor done;virtual;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       ptypesym = ^ttypesym;

       ttypesym = object(tsym)
          definition : pdef;
          constructor init(const n : string;d : pdef);
          constructor load;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       tvarspez = (vs_value,vs_const,vs_var);

       pvarsym = ^tvarsym;

       tvarsym = object(tsym)
          adresse : longint;
          definition : pdef;
          refs : longint;
          regable : boolean;
          { falls<>R_NO, dann befindet sich die Variable in einem Register }
          reg : tregister;
          { gibt die Art des Zugriffs an }
          varspez : tvarspez;
          constructor init(const n : string;p : pdef);
          constructor load;
          function getsize : longint;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       ptypedconstsym = ^ttypedconstsym;

       ttypedconstsym = object(tsym)
          prefix : pstring;
          definition : pdef;
          constructor init(const n : string;p : pdef);
          constructor load;
          destructor done;virtual;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       tconsttype = (constord,conststring,constreal,constbool,constint,
                     constchar);

       pconstsym = ^tconstsym;

       tconstsym = object(tsym)
          definition : pdef;
          consttype : tconsttype;
          value : longint;
          constructor init(const n : string;t : tconsttype;v : longint;def : pdef);
          constructor load;
          procedure deref;virtual;
          procedure write;virtual;
       end;

       paufzaehlsym = ^taufzaehlsym;

       taufzaehlsym = object(tsym)
          value : longint;
          definition : paufzaehldef;
          constructor init(const n : string;def : paufzaehldef;v : longint);
          constructor load;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       pprogramsym = ^tprogramsym;

       tprogramsym = object(tsym)
          constructor init(const n : string);
       end;

       psyssym = ^tsyssym;

       tsyssym = object(tsym)
          number : longint;
          constructor init(const n : string;l : longint);
          procedure write;virtual;
       end;

       tcallback = procedure(p : psym);

       tsymtablehasharray = array[0..hasharraysize-1] of psym;

       psymtablehasharray = ^tsymtablehasharray;

       tsymtable = object
          { Name wird bei parasymtables als call_offset-Speicher benutzt ! }
          { (dann longint)                                                 }
          name : pstring;
          datasize : longint;
          symtabletype : word;
          wurzel : psym;
	  hasharray : psymtablehasharray;
          next : psymtable;

          { gibt bei unitsymtables eine Nummer an, um später die }
          { Typen etc eindeutig einer Unit zuzuordnen können }
          unitid : word;

          wurzeldef : pdef; { Hier werden die internen Typenpointer eingesammelt }
          constructor init(t : word);
          constructor load;
          constructor loadasstruct(typ : word);
          destructor done;virtual;
          procedure insert(sym : psym);
          function search(const s : stringid) : psym;
          procedure clear;
          procedure registerdef(p : pdef);
          procedure foreach(proc2call : tcallback);
          procedure allsymbolsused;
          procedure write;
          procedure writeasunit;
          procedure writeasstruct;
          function getdefnr(l : word) : pdef;
       end;

       punitsymtable = ^tunitsymtable;

       tunitsymtable = object(tsymtable)
          checksum,maschstart : longint;
          constructor load(const n : string);
       end;

       { das braucht nun der Compiler }

       tdeftype = (abstractdef,arraydef,recorddef,pointerdef,grunddef,
                   stringdef,aufzaehldef,procdef,classdef,errordef,
                   filedef,formaldef,setdef,procvardef);

       tdef = object
          deftype : tdeftype;
          savesize : longint;
          number : word;
          owner : psymtable;
          next : pdef;
          function size : longint;virtual;
          constructor init;
          destructor done;virtual;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       tfiletyp = (ft_text,ft_typed,ft_untyped);

       tfiledef = object(tdef)
          public
             filetyp : tfiletyp;
             typed_as : pdef;
             constructor init(ft : tfiletyp;tas : pdef);
             constructor load;
             procedure write;virtual;
             procedure deref;virtual;
          private
             procedure setsize;
       end;

       tformaldef = object(tdef)
          constructor init;
          constructor load;
          procedure write;virtual;
       end;

       terrordef = object(tdef)
          constructor init;
       end;

       tpointerdef = object(tdef)
          definition : pdef;
          constructor init(def : pdef);
          constructor load;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       tarraydef = object(tdef)
          lowrange : longint;
          highrange : longint;
          rangenr : longint;
          definition : pdef;
          rangedef : pdef;
          function elesize : longint;
          constructor init(l,h : longint;rd : pdef);
          constructor load;
          procedure write;virtual;
          procedure deref;virtual;
          function size : longint;virtual;

          { erzeugt falls notwendig Grenzwerte für Range-Checking }
          procedure genrangecheck;
       end;

       trecdef = object(tdef)
          symtable : psymtable;
          constructor init(p : psymtable);
          constructor load;
          destructor done;virtual;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       tgrunddef = object(tdef)
          von : longint;
          bis : longint;

          rangenr : longint;
          typ : tgrundtyp;
          constructor init(t : tgrundtyp;v,b : longint);
          constructor load;
          procedure write;virtual;
          procedure setsize;

          { erzeugt falls notwendig Grenzwerte fuer Range-Checking }
          procedure genrangecheck;
       end;

       pdefcoll = ^tdefcoll;

       tdefcoll = record
          data : pdef;
          next : pdefcoll;
          paratyp : tvarspez;
       end;

       tabstractprocdef = object(tdef)
          retdef : pdef; { Definition des Returntypes }
          options : word;
          para1 : pdefcoll;
          constructor init;
          constructor load;
          destructor done;virtual;
          procedure concatdef(p : pdef;vsp : tvarspez);
          procedure deref;virtual;
          procedure write;virtual;
       end;

       tprocvardef = object(tabstractprocdef)
          constructor init;
          constructor load;
          procedure write;virtual;
       end;

       tprocdef = object(tabstractprocdef)
          usedregisters : byte;
          extnumber : longint;
          nextoverloaded : pprocdef;
          localst : psymtable; { Pointer auf die lokalen Symbole }
          parast : psymtable; { Pointer auf die Parameter }
          forwarddef : boolean; { true, wenn nur deklariert }
          _mangledname : pchar;
          constructor init;
          destructor done;virtual;
          constructor load;
          procedure write;virtual;
          procedure deref;virtual;
          function mangledname : string;
          procedure setmangledname(const s : string);
       end;

       tstringdef = object(tdef)
          len : byte;
          constructor init(l : byte);
          constructor load;
          procedure write;virtual;
       end;

       taufzaehldef = object(tdef)
          max : longint;
          constructor init;
          constructor load;
          procedure write;virtual;
       end;

       tclassdef = object(tdef)
          childof : pclassdef;
          name : pstring;
{          privatesyms : psymtable;
          protectedsyms : psymtable; }
          publicsyms : psymtable;
          constructor init(const n : string;c : pclassdef);
          destructor done;virtual;
          function isrelated(d : pclassdef) : boolean;
          function size : longint;virtual;
          constructor load;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       tsettyp = (normset);

       tsetdef = object(tdef)
          setof : pdef;
          settyp : tsettyp;
          constructor init(s : pdef;high : longint);
          constructor load;
          procedure write;virtual;
          procedure deref;virtual;
       end;

       punitnamerec = ^tunitnamerec;

       tunitnamerec = record
          unitname : pstring;
          next : punitnamerec;
       end;

    { initialisiert die Symboltabellenverwaltung }
    procedure init_symtable;
    procedure getsym(const s : stringid;notfounderror : boolean);
    procedure getsymonlyin(p : psymtable;const s : stringid);

    { schreibt eine Unit unter dem angegebenen Namen }
    { und gibt die Größe der erzeugten Datei zurück  }
    function writeunitas(const s : string;unitsymtable : psymtable) : longint;
    function readunit(from : string) : punitsymtable;

    { entfernt eine Symboltabelle vom Symboltabellenstack }
    procedure dellexlevel;

    { speichert eine "forward"-Pointerdefinition }
    procedure save_forward(ppd : ppointerdef;typesym : ptypesym);
    procedure resolve_forwards;

    var
       registerdef : boolean;      { true, wenn Definitionen           }
                                   { registriert werden sollen         }

       symtablestack : psymtable;  { Wurzel der verketteten Liste von  }
                                   { Symboltabellen                    }

       srsym : psym;               { enthält das Ergebnis der letzten  }
       srsymtable : psymtable;     { Suche nach einem Symbol           }

       forwardsallowed : boolean;  { true, wenn Pointertypen "forward" }
                                   { eingefügt werden dürfen           }

       constsymtable : psymtable;  { Symboltabelle in die die          }
                                   { Konstanten von z.B. Aufzählungs-  }
                                   { typen eingefügt werden            }

       voiddef : pgrunddef;        { Zeiger auf eine void-Definition   }
                                   { wird von quelltext initialisiert  }
                                   { (ist resulttype einer Procedure)  }
       voidpointerdef : ppointerdef;
                                   { Zeiger auf "void"-Pointerdef      }

       s32bitdef : pgrunddef;      { Zeiger für resulttype von         }
                                   { intconstn                         }

       u8bitdef : pgrunddef;       { Pointer auf 8-Bit unsigned        }
       u16bitdef : pgrunddef;      { Pointer auf 8-Bit unsigned        }

       cs64realdef : pgrunddef;    { Zeiger für resulttype von         }
                                   { realconstn                        }

       cstringdef : pstringdef;    { Zeiger für resulttype von         }
                                   { stringconstn                      }

       cchardef : pgrunddef;       { Zeiger für resulttype von         }
                                   { charconstn                        }

       booldef : pgrunddef;        { Zeiger auf boolschen Typ          }

       aktprocsym : pprocsym;      { Zeiger auf den Symboltablellen-   }
                                   { eintrag der momentan geparseten   }
                                   { procedure                         }

       procprefix : string;        { eindeutige Namen bei geschachtel- }
                                   { ten Unterprogrammen erzeugen      }

       lexlevel : word;            { Stufen von verschachtelten        }
                                   { Unterprogrammen                   }

       macros : psymtable;         { Zeiger auf die Symboltabelle mit  }
                                   { Makros                            }
       usedunits : tstringcontainer;
                                   { enthaelt die Namen aller zu       }
                                   { initialisierenden Units           }

       read_member : boolean;      { true, wenn Members aus einer PPU-  }
                                   { Datei gelesen werden, d.h. ein     }
                                   { varsym seine Adresse einlesen soll }

       generrorsym : psym;         { Jokersymbol, wenn das richtige    }
                                   { Symbol nicht gefunden wird        }

       generrordef : pdef;         { Jokersymbol für eine fehlerhafte  }
                                   { Typdefinition                     }

       {
         !!!! overloaded_operators : array[PLUS..last_overloaded] of pprocsym;
       }
       overloaded_operators : array[0..0] of pprocsym;

  implementation

    var
       aktrecordsymtable : psymtable; { zeigt auf die Symboltabelle des }
                                      { Records, das momentan aus einer }
                                      { PPU-Datei gelesen wird          }

    const
       ibloadunit = 1;
       ibgrunddef = 2;
       ibpointerdef = 3;
       ibtypesym = 4;
       ibarraydef = 5;
       ibprocdef = 6;
       ibprocsym = 7;
       iblinkofile = 8;
       ibstringdef = 9;
       ibvarsym = 10;
       ibconstsym = 11;
       ibinitunit = 12;
       ibaufzaehlsym = 13;
       ibtypedconstsym = 14;
       ibrecorddef = 15;
       ibfiledef = 16;
       ibformaldef = 17;
       ibclassdef = 18;
       ibaufzaehldef = 19;
       ibsetdef = 20;
       ibprocvardef = 21;
       ibend = 255;

                                           {                 Compilerversion }
                                           {             Format      |       }
                                           { Kennung      |          |       }
                                           {  |           |          |       }
                                           { /-------\   /-------\  /---\    }
       unitheader : array[0..19] of char = ('P','P','U','0','1','0',#0,#6,
                                            #0,#255,#0,#0,#0,#0,#255,#255,
                                           { |   |  \---------/ \-------/    }
                                           { |   |    |             |        }
                                           { |   |    Checksumme    |        }
                                           { |   \--momentan unbenutzt       }
                                           { Zielbetriebssystem              }
                                            #0,#0,#0,#0);
                                           {\---------/                      }
                                           {  |                              }
                                           {  Start der Maschinensprache     }

    const
{$ifdef tp}
       buffersize = 10000;
{$else}
       buffersize = 1024*1024;
{$endif}

    type
       tubuffer = array[0..buffersize-1] of byte;
       txbuffer = array[0..buffersize div 4] of longint;

       pxbuffer = ^txbuffer;

    var
       unitfile : file;
       buffer : ^tubuffer;
       bufferl,bufferp : word;
       checksum : longint;

    procedure writebuffer;

      var
         i : longint;

      begin
         for i:=0 to ((bufferp-1) div 4)-1 do
           checksum:=checksum xor pxbuffer(buffer)^[i];
         blockwrite(unitfile,buffer^,bufferp);
         bufferp:=0;
      end;

    procedure writebyte(b : byte);

      begin
         if bufferp>=buffersize then
           writebuffer;
         buffer^[bufferp]:=b;
         inc(bufferp);
      end;

    procedure writelong(l : longint);

      begin
         if bufferp>=buffersize-3 then
           writebuffer;
         move(l,buffer^[bufferp],4);
         inc(bufferp,4);
      end;

    procedure writedouble(d : double);

      begin
         if bufferp>=buffersize-7 then
           writebuffer;
         move(d,buffer^[bufferp],8);
         inc(bufferp,8);
      end;

    procedure writeword(w : word);

      begin
         if bufferp>=buffersize-1 then
           writebuffer;
         move(w,buffer^[bufferp],2);
         inc(bufferp,2);
      end;

    procedure writestring(const s : string);

      begin
         if bufferp>=buffersize-length(s) then
           writebuffer;
         move(s[0],buffer^[bufferp],length(s)+1);
         inc(bufferp,length(s)+1);
      end;

    procedure writedefref(p : pdef);

      begin
         if p=nil then
           writelong($ffffffff)
         else
           begin
              if (p^.owner^.symtabletype=recordsymtable) or
                 (p^.owner^.symtabletype=objectsymtable) then
                writeword($ffff)
              else writeword(p^.owner^.unitid);
              writeword(p^.number);
           end;
      end;

    function writeunitas(const s : string;unitsymtable : psymtable) : longint;

      var
         size : longint;
         maschstart : longint;

      begin
         assign(unitfile,s);
         rewrite(unitfile,1);
         if ioresult<>0 then
           fatalerror(cannot_write_unitfile);
         getmem(buffer,buffersize);
         { FPKPascal hat mit char(target) ein Problem }
         unitheader[8]:=char(byte(target_info.target));
         move(unitheader[0],buffer^,sizeof(unitheader));
         bufferp:=sizeof(unitheader);
         checksum:=0;
         unitsymtable^.writeasunit;

         { jetzt noch denn Rest im Buffer schreiben }
         writebuffer;

{$ifdef aout}
         maschstart:=bufferp;
{$endif}

         seek(unitfile,10);
         blockwrite(unitfile,checksum,4);

{$ifdef aout}
         seek(unitfile,16);
         blockwrite(unitfile,maschstart,4);
{$endif}

         size:=filesize(unitfile);
         close(unitfile);
         freemem(buffer,buffersize);
         writeunitas:=size;
      end;

    type
       ploaded_units = ^tloaded_units;

       tloaded_units = record
          name : pstring;
          unitpos : psymtable;
          next : ploaded_units;
       end;

    var
       loaded_units : ploaded_units;

    function searchsymtable(name : stringid) : psymtable;

      var
         hs : ploaded_units;

      begin
          hs:=loaded_units;
          while (assigned(hs)) do
            if (hs^.name^=name) then
              begin
                 searchsymtable:=hs^.unitpos;
                 exit;
              end
            else
              hs:=hs^.next;
          searchsymtable:=nil;
       end;

    const
{$ifdef tp}
       maxunitsize = 65000;
       maxsymtables = 255;
{$else}
       maxunitsize = 1024*1024*16;
       maxsymtables = 1024;
{$endif}

    type
       trbuffer = array[0..maxunitsize] of byte;
       prbuffer = ^trbuffer;

    var
       rbuffer : prbuffer;

    type
       tsymtablemap = array[0..maxsymtables] of psymtable;
       psymtablemap = ^tsymtablemap;

    var
       aktsymtablemap : psymtablemap;


    function readbyte : byte;

      begin
         if bufferp>bufferl-1 then
           fatalerror(error_reading_unit);
         inc(bufferp);
         readbyte:=rbuffer^[bufferp-1];
      end;

    function readword : word;

      var
         w : word;

      begin
         if bufferp>bufferl-2 then
           fatalerror(error_reading_unit);
         move(rbuffer^[bufferp],w,2);
         inc(bufferp,2);
         readword:=w;
      end;

    function readlong : longint;

      var
         l : longint;

      begin
         if bufferp>bufferl-4 then
           fatalerror(error_reading_unit);
         move(rbuffer^[bufferp],l,4);
         inc(bufferp,4);
         readlong:=l;
      end;

    function readdouble : double;

      var
         d : double;

      begin
         if bufferp>bufferl-8 then
           fatalerror(error_reading_unit);
         move(rbuffer^[bufferp],d,8);
         inc(bufferp,8);
         readdouble:=d;
      end;

    function readstring : string;

      var
         s : string;

      begin
         s[0]:=char(readbyte);
         if bufferp>bufferl-ord(s[0]) then
           fatalerror(error_reading_unit);
         move(rbuffer^[bufferp],s[1],ord(s[0]));
         inc(bufferp,ord(s[0]));
         readstring:=s;
      end;

    function readdefref : pdef;

      var
         hd : pdef;

      begin
         longint(hd):=readword;
         longint(hd):=longint(hd) or (longint(readword) shl 16);
         readdefref:=hd;
      end;

    procedure resolvedef(var d : pdef);

      begin
         if longint(d)=$ffffffff then
           d:=nil
         else
           begin
              if (longint(d) and $ffff)=$ffff then
                d:=aktrecordsymtable^.getdefnr(longint(d) shr 16)
              else
                d:=aktsymtablemap^[longint(d) and $ffff]^.getdefnr(longint(d) shr 16);
           end;
      end;

    var
       readunit_lastloaded : punitnamerec;

    function readunit(from : string) : punitsymtable;

      var
         p : punitsymtable;
         b : integer;
         l : longint;
         oldbuffer : prbuffer;
         oldbufferl,oldbufferp : word;
         dummy : boolean;
         hp : punitnamerec;
         hr : tunitnamerec;

      begin
         { suchen ob im selben "Stapel" schon einmal versucht wird die }
         { Unit from zu laden                                          }
         hp:=readunit_lastloaded;
         while hp<>nil do
           begin
              if hp^.unitname^=from then
                fatalerror(rec_unit_def);
              hp:=hp^.next;
           end;
         hr.next:=readunit_lastloaded;
         hr.unitname:=@from;
         readunit_lastloaded:=@hr;
         p:=punitsymtable(searchsymtable(from));

         { Ist die Unit schon geladen ? }
         if assigned(p) then
           begin
             readunit_lastloaded:=readunit_lastloaded^.next;
             readunit:=p;
             exit;
           end;

         oldbuffer:=rbuffer;
         oldbufferp:=bufferp;
         oldbufferl:=bufferl;

         { Pfad, in dem das Programm liegt ausprobieren }
         assign(unitfile,inputdir+from+'.PPU');
         reset(unitfile,1);
         if ioresult<>0 then
           begin
              { ansonsten Pfad in dem der Compiler liegt }
              assign(unitfile,unitpath+from+'.PPU');
              reset(unitfile,1);
              if ioresult<>0 then
                begin
                   { im schlimmsten Fall Umgebungsvariable auswerten }
                   assign(unitfile,search(from+'.PPU',getenv(target_info.unit_env),dummy)+from+'.PPU');
                   reset(unitfile,1);
                   if ioresult<>0 then
                     begin
                        exterror:=strpnew('Unit '+from);
                        fatalerror(unit_not_found);
                     end;
                end;
           end;
         l:=filesize(unitfile);
         if l>maxunitsize then
           fatalerror(error_reading_unit);
         if not quiet then
           writeln('Lade '+from+'.PPU');
         getmem(rbuffer,l);
         blockread(unitfile,rbuffer^,l,bufferl);
         close(unitfile);

         { auf Format prüfen }
         for b:=0 to 5 do
           if rbuffer^[b]<>byte(unitheader[b]) then
             fatalerror(malformed_unit);
         if (rbuffer^[8])<>byte(target_info.target) then
           fatalerror(not_same_target);
         bufferp:=sizeof(unitheader);
         p:=new(punitsymtable,load(from));
         p^.checksum:=plongint(@rbuffer^[10])^;
         p^.maschstart:=plongint(@rbuffer^[16])^;
         freemem(rbuffer,l);

         rbuffer:=oldbuffer;
         bufferp:=oldbufferp;
         bufferl:=oldbufferl;

         { Alle geladenen Units merken, erst am Ende einfügen da  }
         { alle Units die vorausgesetzt werden, davor geladen     }
         { werden sollten                                         }

         { im Unit-"Namenstack" eine Ebene entfernen }
         readunit_lastloaded:=readunit_lastloaded^.next;
         p^.next:=symtablestack;
         symtablestack:=p;;

         readunit:=p;
      end;
{$I+}
    procedure getsym(const s : stringid;notfounderror : boolean);

      begin
         srsymtable:=symtablestack;
         while assigned(srsymtable) do
           begin
              srsym:=srsymtable^.search(s);
              if assigned(srsym) then exit
               else srsymtable:=srsymtable^.next;
           end;
         if forwardsallowed then
           begin
              srsymtable:=symtablestack;
              srsym:=new(ptypesym,init(s,nil));
              srsym^.forwarddef:=true;
              srsymtable^.insert(srsym);
           end
         else if notfounderror then
           begin
              exterror:=strpnew(s);
              error(id_not_found);
              srsym:=generrorsym;
           end
         else srsym:=nil;
      end;

    procedure getsymonlyin(p : psymtable;const s : stringid);

      begin
         srsymtable:=p;
         srsym:=srsymtable^.search(s);
         if assigned(srsym) then exit
         else fatalerror(id_not_found);
      end;

    procedure dellexlevel;

      var
         p : psymtable;

      begin
         p:=symtablestack;
         symtablestack:=p^.next;
         dispose(p,done);
      end;

    constructor tprocsym.init(const n : string);

      begin
         tsym.init(n);
         typ:=procsym;
         definition:=nil;
      end;

    constructor tprocsym.load;

      begin
         tsym.load;
         typ:=procsym;

         definition:=pprocdef(readdefref);
      end;

    destructor tprocsym.done;

      var
         pd : pprocdef;

      begin
         pd:=definition;
         while assigned(pd) do
           begin
              if pd^.forwarddef then
                begin
                   exterror:=strpnew(name);
                   error(forward_not_resolved);
                end;
              pd:=pd^.nextoverloaded;
           end;
         tsym.done;
      end;

    procedure tprocsym.deref;

      begin
         resolvedef(pdef(definition));
      end;

    constructor tprogramsym.init(const n : string);

      begin
         tsym.init(n);
         typ:=programsym;
      end;

    constructor tsymtable.init(t : word);

      var
         w : word;

      begin
         symtabletype:=t;
         wurzel:=nil;
         next:=nil;
         name:=nil;
         if symtabletype=objectsymtable then
           datasize:=4
         else
           datasize:=0;
         wurzeldef:=nil;

         case symtabletype of
            globalsymtable,staticsymtable,unitsymtable :
              begin
                 new(hasharray);
                 for w:=0 to hasharraysize-1 do
                   hasharray^[w]:=nil;
              end;
            else hasharray:=nil;
         end;
      end;

    constructor tsymtable.load;

      var
         hp : pdef;
         b : byte;
         counter : word;
         hs : punitsymtable;
         map : psymtablemap;
         nextmapentry : word;
         sym : psym;
         unittoload : stringid;
         unitchecksum : longint;
         hr : tunitnamerec;

      begin
         new(map);
         map^[0]:=@self;
         nextmapentry:=1;

         symtabletype:=unitsymtable;

         { Hasharray setzten }
         new(hasharray);
         for counter:=0 to hasharraysize-1 do
            hasharray^[counter]:=nil;

         datasize:=0;
         wurzel:=nil;
         next:=nil;
         wurzeldef:=nil;

         { Definitionen einlesen }
         counter:=0;
         repeat
           b:=readbyte;
           case b of
              ibloadunit : begin
                              unittoload:=readstring;
                              unitchecksum:=readlong;
                              hs:=readunit(unittoload);

                              { stimmt die Checksumme in der geladenen Unit }
                              { mit der Checksumme in der momentan zu       }
                              { ladenden Unit überein ?                     }
                              if unitchecksum<>hs^.checksum then
                                begin
                                   { ja, dann eine Warnung ausgeben }
                                   exterror:=strpnew(name^);
                                   warning(ill_unit_version);
                                end;
                              map^[nextmapentry]:=hs;
                              inc(nextmapentry);
                              if nextmapentry>maxsymtables then
                                fatalerror(too_much_units);
                           end;
              ibpointerdef : hp:=new(ppointerdef,load);
              ibarraydef : hp:=new(parraydef,load);
              ibgrunddef : hp:=new(pgrunddef,load);
              ibprocdef : hp:=new(pprocdef,load);
              ibstringdef : hp:=new(pstringdef,load);
              ibrecorddef : hp:=new(precdef,load);
              ibclassdef : hp:=new(pclassdef,load);
              ibfiledef : hp:=new(pfiledef,load);
              ibformaldef : hp:=new(pformaldef,load);
              ibaufzaehldef : hp:=new(paufzaehldef,load);
              ibinitunit : usedunits.insert(readstring);
              iblinkofile : linkofiles.insert(readstring);
              ibsetdef : hp:=new(psetdef,load);
              ibprocvardef : hp:=new(pprocvardef,load);
              ibend : break;
              else fatalerror(malformed_unit);
           end;

           if (b<>ibloadunit) and (b<>ibinitunit) and (b<>iblinkofile) then
             begin
                { Numerieren }
                hp^.number:=counter;
                inc(counter);

                hp^.next:=wurzeldef;
                wurzeldef:=hp;
             end;
         until false;

         { nun die Definitionen Dereferenzieren }
         aktsymtablemap:=map;
         hp:=wurzeldef;
         while assigned(hp) do
           begin
              hp^.deref;

              {Besitzer setzen }
              hp^.owner:=@self;

              hp:=hp^.next;
           end;

         { nun Symbole einlesen }
         repeat
           b:=readbyte;
           case b of
              ibtypesym : sym:=new(ptypesym,load);
              ibprocsym : sym:=new(pprocsym,load);
              ibconstsym : sym:=new(pconstsym,load);
              ibvarsym : sym:=new(pvarsym,load);
              ibaufzaehlsym : sym:=new(paufzaehlsym,load);
              ibtypedconstsym : sym:=new(ptypedconstsym,load);
              ibend : break;
              else fatalerror(malformed_unit);
           end;
           sym^.deref;
           insert(sym);
         until false;
         dispose(map);
      end;

    constructor tunitsymtable.load(const n : string);

      var
         hp : ploaded_units;

      begin
         name:=stringdup(n);
         new(hp);
         hp^.name:=name;
         hp^.unitpos:=@self;
         hp^.next:=loaded_units;
         loaded_units:=hp;
         inherited load;
      end;

    constructor tsymtable.loadasstruct(typ : word);

      var
         hp : pdef;
         b : byte;
         counter : word;
         sym : psym;

      begin
         symtabletype:=typ;
         hasharray:=nil;
         aktrecordsymtable:=@self;
         name:=nil;
         if symtabletype=objectsymtable then
           datasize:=4
         else
           datasize:=0;
         wurzel:=nil;
         next:=nil;
         wurzeldef:=nil;

         { Definitionen einlesen }
         counter:=0;
         repeat
           b:=readbyte;
           case b of
              ibpointerdef : hp:=new(ppointerdef,load);
              ibarraydef : hp:=new(parraydef,load);
              ibgrunddef : hp:=new(pgrunddef,load);
              ibprocdef : hp:=new(pprocdef,load);
              ibstringdef : hp:=new(pstringdef,load);
              ibrecorddef : hp:=new(precdef,load);
              ibclassdef : hp:=new(pclassdef,load);
              ibaufzaehldef : hp:=new(paufzaehldef,load);
              ibsetdef : hp:=new(psetdef,load);
              ibprocvardef : hp:=new(pprocvardef,load);
              ibfiledef : hp:=new(pfiledef,load);
              ibformaldef : hp:=new(pformaldef,load);
              ibend : break;
              else fatalerror(malformed_unit);
           end;

           { Numerieren }
           hp^.number:=counter;
           inc(counter);
           hp^.next:=wurzeldef;
           wurzeldef:=hp;
         until false;
         { dereferenziert wird erst in trecdef^.deref }
         { nun Symbole einlesen }
         repeat
           b:=readbyte;
           case b of
              ibtypesym : sym:=new(ptypesym,load);
              ibprocsym : sym:=new(pprocsym,load);
              ibconstsym : sym:=new(pconstsym,load);
              ibvarsym : sym:=new(pvarsym,load);
              ibaufzaehlsym : sym:=new(paufzaehlsym,load);
              ibtypedconstsym : sym:=new(ptypedconstsym,load);
              ibend : break;
              else fatalerror(malformed_unit);
           end;
           insert(sym);
         until false;
      end;

    destructor tsymtable.done;

      var
         hp : pdef;

      begin
         { erst die Einträge loeschen, da procsym's noch ihre Definitionen }
         { auf unaufgelöste "forwards" ueberpruefen                        }
         clear;
         hp:=wurzeldef;
         while assigned(hp) do
           begin
              wurzeldef:=hp^.next;
              dispose(hp,done);
              hp:=wurzeldef;
           end;

      end;

    function tsymtable.getdefnr(l : word) : pdef;

      var
         hp : pdef;

      begin
         hp:=wurzeldef;
         while (assigned(hp)) and (hp^.number<>l) do
           hp:=hp^.next;
         getdefnr:=hp;
      end;

    procedure tsymtable.registerdef(p : pdef);

      begin
         p^.next:=wurzeldef;
         wurzeldef:=p;
         p^.owner:=@self;
      end;

    procedure tsymtable.clear;

      var
         w : integer;

      begin
         if assigned(wurzel) then
           dispose(wurzel,done);
         if assigned(hasharray) then
           begin
              for w:=0 to hasharraysize-1 do
                if assigned(hasharray^[w]) then
                  dispose(hasharray^[w],done);
              dispose(hasharray);
           end;
      end;

    function getspeedvalue(const s : string) : longint;

      var
         l : longint;
         w : word;

      begin
         l:=0;
         for w:=1 to length(s) do
           l:=l+ord(s[w]);
         getspeedvalue:=l;
      end;

    procedure tsymtable.insert(sym : psym);

      procedure _insert(var osym : psym);

        begin
           if osym=nil then osym:=sym
           else if osym^.speedvalue>sym^.speedvalue then _insert(osym^.right)
           else if osym^.speedvalue<sym^.speedvalue then _insert(osym^.left)
           else
             begin
                if osym^.name>sym^.name then _insert(osym^.right)
                else if osym^.name<sym^.name then _insert(osym^.left)
                else
                  begin
                     if (osym^.typ=typesym) and osym^.forwarddef then
                       begin
                          if (sym^.typ<>typesym) then fatalerror(id_already_type);
                          if (ptypesym(sym)^.definition^.deftype<>recorddef) and
                             (ptypesym(sym)^.definition^.deftype<>classdef) then
                             fatalerror(type_must_be_rec_or_class);
                          ptypesym(osym)^.definition:=ptypesym(sym)^.definition;
                          osym^.forwarddef:=false;
                          dispose(sym);
                       end
                     else
                       begin
                          exterror:=strpnew(sym^.name);
                          error(dupid);
                       end;
                  end;
             end;
      end;

      var
         l : longint;
         hp : psymtable;
         hsym : psym;

      begin
         { bei Symbolen für Variablen die Adresse eintragen, }
         { und Größe der Symboltabellendaten berechnen       }
         if (sym^.typ=varsym) and not(read_member) then
           begin
              { bei einer lokalen Symboltabelle erst! erhöhen, da der }
              { Wert in codegen.secondload dann mit minus verwendet   }
              { wird                                                  }
              l:=pvarsym(sym)^.getsize;
              if (symtabletype and $8000)=localsymtable then
                begin
                   inc(datasize,l);
                   if (l>=4) and ((datasize and 3)<>0) then
                     inc(datasize,4-(datasize and 3))
                   else if (l>=2) and ((datasize and 1)<>0) then
                     inc(datasize,2-(datasize and 1));

                   pvarsym(sym)^.adresse:=datasize;
                end
              else if (symtabletype and $3fff)=staticsymtable then
                begin
                   datasegment.concat(gennasmrec(
                     A_STATIC,S_NO,'_'+sym^.name+','+tostr(l)));
                   inc(datasize,l);

                   { Symbol kann nicht in Register geladen werden }
                   pvarsym(sym)^.regable:=false;
                end
              else if (symtabletype and $3fff)=globalsymtable then
                begin
                   datasegment.concat(gennasmrec(
                     A_GLOBAL,S_NO,'U_'+name^+'_'+sym^.name+','+tostr(l)));
                   inc(datasize,l);

                   { Symbol kann nicht in Register geladen werden }
                   pvarsym(sym)^.regable:=false;
                end
              else if ((symtabletype and $3fff)=recordsymtable) or
                      ((symtabletype and $3fff)=objectsymtable) then
                begin
                   if aktpackrecords=2 then
                     begin
                        { auf Wordgrenzen ausrichten }
                        if (l>=2) and ((datasize and 1)<>0) then
                          inc(datasize);
                     end;
                   pvarsym(sym)^.adresse:=datasize;
                   inc(datasize,l);

                   { Symbol kann nicht in Register geladen werden }
                   pvarsym(sym)^.regable:=false;
                end
              else if (symtabletype and $4000)=parasymtable then
                begin
                   {
                   if (l>=4) and ((datasize and 3)<>0) then
                     inc(datasize,4-(datasize and 3))
                   else if (l>=2) and ((datasize and 1)<>0) then
                     inc(datasize,2-(datasize and 1));
                   }
                   pvarsym(sym)^.adresse:=datasize;
                   { 1 Byte große Parameter werden als Word übergeben, }
                   { da z.B. PUSH AH nicht möglich ist                 }
                   if l=1 then l:=2;
                   inc(datasize,l);

                   { Symbol kann nicht in Register geladen werden }
                   pvarsym(sym)^.regable:=false;
                end
              else
                begin
                   if (l>=4) and ((datasize and 3)<>0) then
                     inc(datasize,4-(datasize and 3))
                   else if (l>=2) and ((datasize and 1)<>0) then
                     inc(datasize,2-(datasize and 1));
                   pvarsym(sym)^.adresse:=datasize;
                   inc(datasize,l);
                end;
           end
         else if sym^.typ=typedconstsym then
             begin
                if (symtabletype and $3fff)=globalsymtable then
                  begin
                     constsegment.concat(gennasmrec(DIRECT,S_NO,'.globl TC_'+
                       ptypedconstsym(sym)^.prefix^+'_'+sym^.name));
                  end;
                if not((symtabletype and $3fff)=unitsymtable) then
                  begin
                     constsegment.concat(gennasmrec(DIRECT,S_NO,'TC_'+
                       ptypedconstsym(sym)^.prefix^+'_'+sym^.name+':'));
                  end;
             end;
         if (symtabletype=staticsymtable) or
            (symtabletype=globalsymtable) then
           begin
              hp:=symtablestack;
              while assigned(hp) do
                begin
                   if (hp^.symtabletype and $3fff=staticsymtable) or
                      (hp^.symtabletype and $3fff=globalsymtable) then
                        begin
                           hsym:=hp^.search(sym^.name);
                           if (assigned(hsym)) and
                              not(hsym^.forwarddef) then
                              begin
                                 exterror:=strpnew(sym^.name);
                                 error(dupid);
                              end;
                        end;
                      hp:=hp^.next;
                end;
           end;
         sym^.speedvalue:=getspeedvalue(sym^.name);
         if assigned(hasharray) then
           _insert(hasharray^[sym^.speedvalue mod hasharraysize])
         else
           _insert(wurzel);
      end;

    procedure varsymbolused(p : psym);far;

      begin
         if p^.typ=varsym then
           { unbenutztes Symbol ist vielleicht Folgefehler }
           if (pvarsym(p)^.refs=0) and (errorcount=0) then
             begin
                exterror:=strpnew(p^.name);
                warning(symbol_not_used);
             end;
      end;

    procedure tsymtable.allsymbolsused;

      begin
{$ifdef tp}
         foreach(varsymbolused);
{$else}
         foreach(@varsymbolused);
{$endif}
      end;

    function tsymtable.search(const s : stringid) : psym;

      var
         hp : psym;
         w : word;
         speedvalue : longint;

      begin
         speedvalue:=getspeedvalue(s);
         if assigned(hasharray) then
           hp:=hasharray^[speedvalue mod hasharraysize]
         else
           hp:=wurzel;
         while assigned(hp) do
           begin
              if speedvalue>hp^.speedvalue then hp:=hp^.left
              else if speedvalue<hp^.speedvalue then hp:=hp^.right
              else
                begin
                   if hp^.name=s then
                     begin
                        search:=hp;
                        exit;
                     end
                  else if s>hp^.name then hp:=hp^.left
                  else hp:=hp^.right;
                end;
           end;
         search:=nil;
      end;

    procedure tsymtable.foreach(proc2call : tcallback);

      procedure a(p : psym);

        { sollte Preorder sein }
        { wegen Einlesen einer Unit }

        begin
           proc2call(p);
           if assigned(p^.left) then a(p^.left);
           if assigned(p^.right) then a(p^.right);
        end;

      var
         i : integer;

      begin
         if hasharray<>nil then
           begin
              for i:=0 to hasharraysize-1 do
                if assigned(hasharray^[i]) then
                  a(hasharray^[i]);
           end
         else
           if assigned(wurzel) then
             a(wurzel);
      end;

    { schreibt ein einzelnes Symbol (wird nur als "Callback" aufgerufen) }

    procedure writesym(p : psym);far;

      begin
         p^.write;
      end;

    procedure tsymtable.writeasunit;

      var
         counter : word;
         s : string;
         p : psymtable;

      begin
         unitid:=0;

         { zuerst alle im Interface-Abschnitt aufgeführten Units }
         { in die Datei schreiben und numerieren }
         p:=next;
         counter:=1;

         { im Implementationsteil aufgefuehrte Units ueberspringen }
         if symtabletype<>globalsymtable then
           begin
              while (p^.symtabletype<>globalsymtable) do
                p:=p^.next;
              p:=p^.next;
           end;
         while assigned(p) do
           begin
              if p^.symtabletype=unitsymtable then
                begin
                   p^.unitid:=counter;
                   inc(counter);
                   writebyte(ibloadunit);
                   writestring(p^.name^);
                   writelong(punitsymtable(p)^.checksum);
                end;
              p:=p^.next;
           end;

         { die Namen der benutzten Units schreiben }
         s:=usedunits.get;
         while s<>'' do
           begin
              writebyte(ibinitunit);
              writestring(s);
              s:=usedunits.get;
           end;
         s:=linkofiles.get;
         while s<>'' do
           begin
              writebyte(iblinkofile);
              writestring(s);
              s:=linkofiles.get;
           end;
         tsymtable.write;
      end;

    procedure tsymtable.writeasstruct;

      var
         counter : word;
         s : string;
         p : psymtable;

      begin
         tsymtable.write;
      end;

    procedure tsymtable.write;

      var
         pd : pdef;
         counter : longint;

      begin
         { nun alle Definitionen numerieren }
         counter:=0;
         pd:=wurzeldef;
         while assigned(pd) do
           begin
              pd^.number:=counter;
              inc(counter);
              pd:=pd^.next;
           end;
         { und jetzt schreiben }
         pd:=wurzeldef;
         while assigned(pd) do
           begin
              pd^.write;
              pd:=pd^.next;
           end;

         { Defintionsende }
         writebyte(ibend);

         { ...und per foreach alle Symbole schreiben }
{$ifdef tp}
         foreach(writesym);
{$else}
         foreach(@writesym);
{$endif}
         { Symbolende }
         writebyte(ibend);
      end;

{**************************************
              "forward"-Pointer
 **************************************}

    type
       presolvelist = ^tresolvelist;

       tresolvelist = record
          p : ppointerdef;
          typ : ptypesym;
          next : presolvelist;
       end;

    var
       swurzel : presolvelist;

    procedure save_forward(ppd : ppointerdef;typesym : ptypesym);

      var
         p : presolvelist;

      begin
         new(p);
         p^.next:=swurzel;
         p^.p:=ppd;
         p^.typ:=typesym;
         swurzel:=p;
      end;

    procedure resolve_forwards;

      var
         p : presolvelist;

      begin
         p:=swurzel;
         while p<>nil do
           begin
              swurzel:=swurzel^.next;
              p^.p^.definition:=p^.typ^.definition;
              dispose(p);
              p:=swurzel;
           end;
      end;

    constructor tsym.init(const n : string);

      begin
         left:=nil;
         right:=nil;
         setname(n);
         typ:=abstractsym;
         forwarddef:=false;
      end;

    constructor tsym.load;

      begin
         left:=nil;
         right:=nil;
         setname(readstring);
         typ:=abstractsym;
         forwarddef:=false;
      end;

    destructor tsym.done;

      begin
{$ifdef tp}
         if not(use_big) then
{$endif tp}
           strdispose(_name);
         if assigned(left) then dispose(left,done);
         if assigned(right) then dispose(right,done);
      end;

    procedure tsym.write;

      begin
         writestring(name);
      end;

    procedure tsym.deref;

      begin
      end;

    function tsym.name : string;

      var
         s : string;
         b : byte;

      begin
{$ifdef tp}
         if use_big then
           begin
              symbolstream.seek(longint(_name));
              symbolstream.read(b,1);
              symbolstream.read(s[1],b);
              s[0]:=chr(b);
              name:=s;
           end
         else
{$endif}
           begin
              name:=strpas(_name);
           end;
      end;

    procedure tsym.setname(const s : string);

      begin
         setstring(_name,s);
      end;

{**************************************
               TLABELSYM
 **************************************}

    constructor tlabelsym.init(const n : string;l : longint);

      begin
         inherited init(n);
         typ:=labelsym;
         number:=l;
         defined:=false;
      end;

    destructor tlabelsym.done;

      begin
         if not(defined) then
           begin
              exterror:=strpnew(name);
              error(label_not_defined);
           end;
         inherited done;
      end;

    procedure tlabelsym.write;

      begin
         error(ill_label_pos);
      end;

{**************************************
               TUNITSYM
 **************************************}

    constructor tunitsym.init(const n : string;ref : psymtable);

      begin
         tsym.init(n);
         typ:=unitsym;
         unitsymtable:=ref;
      end;

    procedure tunitsym.write;

      begin
      end;

{**************************************
               TTYPESYM
 **************************************}

    constructor terrorsym.init;

      begin
         tsym.init('');
         typ:=errorsym;
      end;

{**************************************
               TVARSYM
 **************************************}

    constructor tvarsym.init(const n : string;p : pdef);

      begin
         tsym.init(n);
         typ:=varsym;
         definition:=p;
         varspez:=vs_value;
         adresse:=0;
         refs:=0;

         { möglicher Kandidat für Register: }
         case p^.deftype of
            pointerdef,aufzaehldef,procvardef : regable:=true;
            grunddef : case pgrunddef(p)^.typ of
                          u8bit,s32bit,bool8bit,uchar,
                          s8bit,s16bit,u16bit : regable:=true;
                          else regable:=false;
                       end;
            else regable:=false;
         end;
         reg:=R_NO;
      end;

    constructor tvarsym.load;

      begin
         tsym.load;
         typ:=varsym;
         varspez:=tvarspez(readbyte);
         if read_member then
           adresse:=readlong
         else adresse:=0;
         definition:=readdefref;

         { nie in ein Register }
         regable:=false;
         reg:=R_NO;
      end;

    procedure tvarsym.deref;

      begin
         resolvedef(definition);
      end;

    procedure tvarsym.write;

      begin
         writebyte(ibvarsym);
         tsym.write;
         writebyte(byte(varspez));

         if read_member then
           writelong(adresse);

         writedefref(definition);
      end;

    function tvarsym.getsize : longint;

      begin
         { assigned(definition) ist ein Experiment }
         if assigned(definition) then
           begin
              case varspez of
                 vs_value : getsize:=definition^.size;
                 vs_var : getsize:=4;
                 vs_const : begin
                               if (definition^.deftype=stringdef) or
                                  (definition^.deftype=arraydef) or
                                  (definition^.deftype=recorddef) or
                                  (definition^.deftype=classdef) or
                                  (definition^.deftype=setdef) then
                                  getsize:=4
                                else
                                  getsize:=definition^.size;
                            end;
              end;
           end;
      end;

{**************************************
               TTYPEDCONSTSYM
 **************************************}

    constructor ttypedconstsym.init(const n : string;p : pdef);

      begin
         tsym.init(n);
         typ:=typedconstsym;
         definition:=p;
         prefix:=stringdup(procprefix);
      end;

    constructor ttypedconstsym.load;

      begin
         tsym.load;
         typ:=typedconstsym;
         definition:=readdefref;
         prefix:=stringdup(readstring);
      end;

    destructor ttypedconstsym.done;

      begin
         stringdispose(prefix);
         tsym.done;
      end;

    procedure ttypedconstsym.deref;

      begin
         resolvedef(definition);
      end;

    procedure ttypedconstsym.write;

      begin
         writebyte(ibtypedconstsym);
         tsym.write;
         writedefref(definition);
         writestring(prefix^);
      end;

{**************************************
               TCONSTSYM
 **************************************}

    constructor tconstsym.init(const n : string;t : tconsttype;v : longint;def : pdef);

      begin
         tsym.init(n);
         typ:=constsym;
         definition:=def;
         consttype:=t;
         value:=v;
      end;

    constructor tconstsym.load;

      var
         pd : pdouble;

      begin
         tsym.load;
         typ:=constsym;
         consttype:=tconsttype(readbyte);
         case consttype of
            constint,
            constbool,
            constchar : value:=readlong;
            constord : begin
                          definition:=readdefref;
                          value:=readlong;
                       end;
            conststring : value:=longint(stringdup(readstring));
            constreal : begin
                           new(pd);
                           pd^:=readdouble;
                           value:=longint(pd);
                        end;
         else fatalerror(malformed_unit);
         end;
      end;

    procedure tconstsym.deref;

      begin
         if consttype=constord then
           resolvedef(pdef(definition));
      end;

    procedure tconstsym.write;

      begin
         writebyte(ibconstsym);
         tsym.write;
         writebyte(byte(consttype));
         case consttype of
            constint,
            constbool,
            constchar : writelong(value);
            constord : begin
                          writedefref(definition);
                          writelong(value);
                       end;
            conststring : writestring(pstring(value)^);
            constreal : writedouble(pdouble(value)^);
            else internalerror(13);
         end;
      end;

{**************************************
               TAUFZAEHLSYM
 **************************************}

    constructor taufzaehlsym.init(const n : string;def : paufzaehldef;v : longint);

      begin
         tsym.init(n);
         typ:=aufzaehlsym;
         definition:=def;
         value:=v;
      end;

    constructor taufzaehlsym.load;

      begin
         tsym.load;
         typ:=aufzaehlsym;
         definition:=paufzaehldef(readdefref);
         value:=readlong;
      end;

    procedure taufzaehlsym.deref;

      begin
         resolvedef(pdef(definition));
      end;

    procedure taufzaehlsym.write;

      begin
         writebyte(ibaufzaehlsym);
         tsym.write;
         writedefref(definition);
         writelong(value);
      end;

{**************************************
               TTYPESYM
 **************************************}

    constructor ttypesym.init(const n : string;d : pdef);

      begin
         tsym.init(n);
         typ:=typesym;
         definition:=d;
      end;

    constructor ttypesym.load;

      begin
         tsym.load;
         typ:=typesym;
         definition:=readdefref;
      end;

    procedure ttypesym.deref;

      begin
         resolvedef(definition);
      end;

    procedure ttypesym.write;

      begin
         writebyte(ibtypesym);
         tsym.write;
         writedefref(definition);
      end;

    procedure tprocsym.write;

      begin
         writebyte(ibprocsym);
         tsym.write;
         writedefref(pdef(definition));
      end;

{**************************************
               TSYSSYM
 **************************************}

    constructor tsyssym.init(const n : string;l : longint);

      begin
         inherited init(n);
         typ:=syssym;
         number:=l;
      end;

    procedure tsyssym.write;

      begin
      end;

{**************************************
                  TDEF
 **************************************}


{ Das braucht der Compiler um die Typendefinitionen zu verwalten }

    constructor tdef.init;

      begin
         deftype:=abstractdef;
         if registerdef then symtablestack^.registerdef(@self);
      end;

    function tdef.size : longint;

      begin
         size:=savesize;
      end;

    procedure tdef.write;

      begin
      end;

    procedure tdef.deref;

      begin
      end;

    destructor tdef.done;

      begin
      end;

{**************************************
              TSTRINGDEF
 **************************************}

    constructor tstringdef.init(l : byte);

      begin
         tdef.init;
         deftype:=stringdef;
         len:=l;
         savesize:=len+1;
      end;

    constructor tstringdef.load;

      begin
         deftype:=stringdef;
         len:=readbyte;
         savesize:=len+1;
      end;

    procedure tstringdef.write;

      begin
         writebyte(ibstringdef);
         writebyte(len);
      end;

{**************************************
             TAUFZAEHLDEF
 **************************************}

    constructor taufzaehldef.init;

      begin
         tdef.init;
         deftype:=aufzaehldef;
         max:=0;
         savesize:=4;
      end;

    constructor taufzaehldef.load;

      begin
         deftype:=aufzaehldef;
         max:=readlong;
         savesize:=4;
      end;

    procedure taufzaehldef.write;

      begin
         writebyte(ibaufzaehldef);
         writelong(max);
      end;

{**************************************
               TGRUNDDEF
 **************************************}

    constructor tgrunddef.init(t : tgrundtyp;v,b : longint);

      begin
         tdef.init;
         deftype:=grunddef;
         von:=v;
         bis:=b;
         typ:=t;
         setsize;
      end;

    constructor tgrunddef.load;

      begin
         deftype:=grunddef;
         typ:=tgrundtyp(readbyte);
         von:=readlong;
         bis:=readlong;
         setsize;
         if (typ=uvoid) and not(cs_compilesystem in aktswitches) then
           voiddef:=@self;
      end;

    procedure tgrunddef.setsize;

      begin
         if typ=uauto then
           begin
              if (von>=0) and (bis<=255) then
                begin
                   savesize:=1;
                   typ:=u8bit;
                end
              else if (von>=-128) and (bis<=127) then
                begin
                   savesize:=1;
                   typ:=s8bit;
                end
              else if (von>=0) and (bis<=65536) then
                begin
                   savesize:=2;
                   typ:=u16bit;
                end
              else if (von>=-32768) and (bis<=32767) then
                begin
                   savesize:=2;
                   typ:=s16bit;
                end
              else
                begin
                   savesize:=4;
                   typ:=s32bit;
                end;
           end
         else
           case typ of
              uchar,u8bit,bool8bit,s8bit : savesize:=1;
              u16bit,s16bit : savesize:=2;
              s32bit  : savesize:=4;
              s64real : savesize:=8;
              else savesize:=0;
           end;

         { noch keine Rangecheck-Information erzeugt }
         rangenr:=0;
      end;

    procedure tgrunddef.genrangecheck;

      begin
         if rangenr=0 then
           begin
              { nun für das Rangechecking erforderliche Einträge erzeugen: }
              rangenr:=getunreglabel;
              constsegment.concat(gennasmrec(DIRECT,S_NO,'R_'+tostr(rangenr)+':'));
              constsegment.concat(gennasmrec(A_LONG,S_NO,tostr(von)));
              constsegment.concat(gennasmrec(A_LONG,S_NO,tostr(bis)));
           end;
      end;

    procedure tgrunddef.write;

      begin
         writebyte(ibgrunddef);
         writebyte(byte(typ));
         writelong(von);
         writelong(bis);
      end;

{**************************************
               TFILEDEF
 **************************************}

    constructor tfiledef.init(ft : tfiletyp;tas : pdef);

      begin
         inherited init;
         deftype:=filedef;
         filetyp:=ft;
         typed_as:=tas;
         setsize;
      end;

    constructor tfiledef.load;

      begin
         deftype:=filedef;
         { die Adressen werden später berechnet }
         filetyp:=tfiletyp(readbyte);
         if filetyp=ft_typed then
           typed_as:=readdefref;
         setsize;
      end;

    procedure tfiledef.deref;

      begin
         if filetyp=ft_typed then
           resolvedef(typed_as);
      end;

    procedure tfiledef.write;

      begin
         writebyte(ibfiledef);
         writebyte(byte(filetyp));
         if filetyp=ft_typed then
           writedefref(typed_as);
      end;

    procedure tfiledef.setsize;

      begin
         case filetyp of
            ft_text : savesize:=256;
            ft_untyped : savesize:=128;
            {!!!!!!}
            else internalerror(17);
         end;
      end;

{**************************************
               TPOINTERDEF
 **************************************}

    constructor tpointerdef.init(def : pdef);

      begin
         inherited init;
         deftype:=pointerdef;
         definition:=def;
         savesize:=4;
      end;

    constructor tpointerdef.load;

      begin
         deftype:=pointerdef;
         { die Adressen werden später berechnet }
         definition:=readdefref;
         savesize:=4;
      end;

    procedure tpointerdef.deref;

      begin
         resolvedef(definition);
      end;

    procedure tpointerdef.write;

      begin
         writebyte(ibpointerdef);
         writedefref(definition);
      end;

{**************************************
               TSETDEF
 **************************************}

    constructor tsetdef.init(s : pdef;high : longint);

      begin
         inherited init;
         deftype:=setdef;
         setof:=s;
         { nur normale Sets mit 32 Bytes Größe werden momentan unterstützt }
         if high<256 then
           begin
              settyp:=normset;
              savesize:=32;
           end
         else error(illsettype);
      end;

    constructor tsetdef.load;

      begin
         deftype:=setdef;
         setof:=readdefref;
         settyp:=tsettyp(readbyte);
         savesize:=32;
      end;

    procedure tsetdef.write;

      begin
         writebyte(ibsetdef);
         writedefref(setof);
         writebyte(byte(settyp));
      end;

    procedure tsetdef.deref;

      begin
         resolvedef(setof);
      end;

{**************************************
               TFORMALDEF
 **************************************}

    constructor tformaldef.init;

      begin
         inherited init;
         deftype:=formaldef;
         savesize:=4;
      end;

    constructor tformaldef.load;

      begin
         deftype:=formaldef;
         savesize:=4;
      end;

    procedure tformaldef.write;

      begin
         writebyte(ibformaldef);
      end;

{**************************************
               TARRAYDEF
 **************************************}

    constructor tarraydef.init(l,h : longint;rd : pdef);

      begin
         tdef.init;
         deftype:=arraydef;
         lowrange:=l;
         highrange:=h;
         rangedef:=rd;
         rangenr:=0;
      end;

    constructor tarraydef.load;

      begin
         deftype:=arraydef;
         rangenr:=0;

         { die Adressen werden später berechnet }
         definition:=readdefref;
         rangedef:=readdefref;
         lowrange:=readlong;
         highrange:=readlong;
      end;

    procedure tarraydef.genrangecheck;

      begin
         if rangenr=0 then
           begin
              { nun für das Rangechecking erforderliche Einträge erzeugen: }
              rangenr:=getunreglabel;
              constsegment.concat(gennasmrec(DIRECT,S_NO,'R_'+tostr(rangenr)+':'));
              constsegment.concat(gennasmrec(A_LONG,S_NO,tostr(lowrange)));
              constsegment.concat(gennasmrec(A_LONG,S_NO,tostr(highrange)));
           end;
      end;

    procedure tarraydef.deref;

      begin
         resolvedef(definition);
         resolvedef(rangedef);
      end;

    procedure tarraydef.write;

      begin
         writebyte(ibarraydef);
         writedefref(definition);
         writedefref(rangedef);
         writelong(lowrange);
         writelong(highrange);
      end;

    function tarraydef.elesize : longint;

      begin
         elesize:=definition^.size;
      end;

    function tarraydef.size : longint;

      begin
         size:=(highrange-lowrange+1)*elesize;
      end;

{**************************************
               TRECDEF
 **************************************}

    constructor trecdef.init(p : psymtable);

      begin
         tdef.init;
         deftype:=recorddef;
         symtable:=p;
         savesize:=symtable^.datasize;
      end;

    constructor trecdef.load;

      var
         oldread_member : boolean;

      begin
         deftype:=recorddef;
         savesize:=readlong;
         oldread_member:=read_member;
         read_member:=true;
         symtable:=new(psymtable,loadasstruct(recordsymtable));
         read_member:=oldread_member;
      end;

    destructor trecdef.done;

      begin
         dispose(symtable);
      end;

    procedure derefsym(p : psym);far;

      begin
         p^.deref;
      end;

    procedure trecdef.deref;

      var
         hp : pdef;
         oldrecsyms : psymtable;

      begin
         oldrecsyms:=aktrecordsymtable;
         aktrecordsymtable:=symtable;
         { nun die Definitionen Dereferenzieren }
         hp:=symtable^.wurzeldef;
         while assigned(hp) do
           begin
              hp^.deref;

              {Besitzer setzten }
              hp^.owner:=symtable;

              hp:=hp^.next;
           end;
{$ifdef tp}
         symtable^.foreach(derefsym);
{$else}
         symtable^.foreach(@derefsym);
{$endif}
         aktrecordsymtable:=oldrecsyms;
      end;

    procedure trecdef.write;

      var
         oldread_member : boolean;

      begin
         oldread_member:=read_member;
         read_member:=true;
         writebyte(ibrecorddef);
         writelong(savesize);
         self.symtable^.writeasstruct;
         read_member:=oldread_member;
      end;

{**************************************
               TABSTRACTPROCDEF
 **************************************}

    constructor tabstractprocdef.init;

      begin
         inherited init;
         para1:=nil;
         options:=0;
         retdef:=voiddef;
         savesize:=4;
      end;

    destructor tabstractprocdef.done;

      var
         hp : pdefcoll;

      begin
         hp:=para1;
         while assigned(hp) do
           begin
              para1:=hp^.next;
              dispose(hp);
              hp:=para1;
           end;
         inherited done;
      end;

    procedure tabstractprocdef.concatdef(p : pdef;vsp : tvarspez);

      var
         hp : pdefcoll;

      begin
         new(hp);
         hp^.paratyp:=vsp;
         hp^.data:=p;
         hp^.next:=para1;
         para1:=hp;
      end;

    procedure tabstractprocdef.deref;

      var
         hp : pdefcoll;

      begin
         inherited deref;
         resolvedef(retdef);
         hp:=para1;
         while assigned(hp) do
           begin
              resolvedef(hp^.data);
              hp:=hp^.next;
           end;
      end;

    constructor tabstractprocdef.load;

      var
         last,hp : pdefcoll;
         count,i : word;

      begin
         retdef:=readdefref;
         options:=readword;
         count:=readword;
         para1:=nil;
         savesize:=4;
         for i:=1 to count do
           begin
              new(hp);
              hp^.paratyp:=tvarspez(readbyte);
              hp^.data:=readdefref;
              hp^.next:=nil;
              if para1=nil then
                para1:=hp
              else
                last^.next:=hp;
              last:=hp;
           end;
      end;

    procedure tabstractprocdef.write;

      var
         count : word;
         hp : pdefcoll;

      begin
         writedefref(retdef);
         writeword(options);
         hp:=para1;
         count:=0;
         while assigned(hp) do
           begin
              inc(count);
              hp:=hp^.next;
           end;
         writeword(count);
         hp:=para1;
         while assigned(hp) do
           begin
              writebyte(byte(hp^.paratyp));
              writedefref(hp^.data);
              hp:=hp^.next;
           end;
      end;

{**************************************
               TPROCDEF
 **************************************}

    constructor tprocdef.init;

      begin
         inherited init;
         deftype:=procdef;
         _mangledname:=nil;
         nextoverloaded:=nil;
         extnumber:=-1;
         parast:=new(psymtable,init(parasymtable));
         localst:=new(psymtable,init(localsymtable));

         { grundsätzlich sind alle Register benutzt    }
         { erst wenn eine Implementation vorliegt wird }
         { dies vom Parser gegebenenfalls geändert     }
         usedregisters:=$ff;
         forwarddef:=true;
      end;

    constructor tprocdef.load;

      begin
         deftype:=procdef;
         inherited load;

         usedregisters:=readbyte;
         setstring(_mangledname,readstring);
         extnumber:=readlong;
         nextoverloaded:=pprocdef(readdefref);

         if gendeffile and ((options and poexports)<>0) then
           writeln(defdatei,#9+mangledname);

         parast:=nil;
         localst:=nil;
         forwarddef:=false;
      end;

    destructor tprocdef.done;

      var
         hp : pdefcoll;

      begin
         if assigned(parast) then
           dispose(parast,done);
         if assigned(localst) then
           dispose(localst,done);
         if
{$ifdef tp}
         not(use_big) and
{$endif}
         assigned(_mangledname) then
           strdispose(_mangledname);
         inherited done;
      end;

    procedure tprocdef.write;

      begin
         writebyte(ibprocdef);
         inherited write;

         writebyte(usedregisters);
         writestring(mangledname);
         writelong(extnumber);
         writedefref(nextoverloaded);
      end;

    procedure tprocdef.deref;

      begin
         inherited deref;
         resolvedef(pdef(nextoverloaded));
      end;

    function tprocdef.mangledname : string;

      var
         oldpos : longint;
         s : string;
         b : byte;

      begin
{ $ifdef tp
         if use_big then
           begin
              symbolstream.seek(longint(_mangledname));
              symbolstream.read(b,1);
              symbolstream.read(s[1],b);
              s[0]:=chr(b);
              mangledname:=s;
           end
         else
$endif}
           begin
              mangledname:=strpas(_mangledname);
           end;
      end;

    procedure tprocdef.setmangledname(const s : string);

      begin
         if
{$ifdef tp}
         not(use_big) and
{$endif}
         (assigned(_mangledname)) then
           strdispose(_mangledname);
         setstring(_mangledname,s);
      end;

{**************************************
               TPROCVARDEF
 **************************************}

    constructor tprocvardef.init;

      begin
         inherited init;
         deftype:=procvardef;
      end;

    constructor tprocvardef.load;

      begin
         deftype:=procvardef;
         inherited load;
      end;

    procedure tprocvardef.write;

      begin
         writebyte(ibprocvardef);
         inherited write;
      end;

{**************************************
               TCLASSDEF
 **************************************}

   constructor tclassdef.init(const n : string;c : pclassdef);

     begin
        tdef.init;
        deftype:=classdef;
        childof:=c;
        {privatesyms:=new(psymtable,init(objectsymtable));
        protectedsyms:=new(psymtable,init(objectsymtable)); }
        publicsyms:=new(psymtable,init(objectsymtable));

        { Daten der Vorfahren bei den Adressen beachten }
        if assigned(childof) then
          publicsyms^.datasize:=
            publicsyms^.datasize-4+childof^.publicsyms^.datasize;
        name:=stringdup(n);
     end;

    constructor tclassdef.load;

      var
         oldread_member : boolean;

      begin
         deftype:=classdef;
         savesize:=readlong;
         name:=stringdup(readstring);
         childof:=pclassdef(readdefref);
         oldread_member:=read_member;
         read_member:=true;
         publicsyms:=new(psymtable,loadasstruct(objectsymtable));
         publicsyms^.datasize:=savesize;
         read_member:=oldread_member;
      end;

   destructor tclassdef.done;

     begin
{!!!!
        if assigned(privatesyms) then
          dispose(privatesyms,done);
        if assigned(protectedsyms) then
          dispose(protectedsyms,done); }
        if assigned(publicsyms) then
          dispose(publicsyms,done);
        stringdispose(name);
        tdef.done;
     end;

   function tclassdef.isrelated(d : pclassdef) : boolean;

     var
        hp : pclassdef;

     begin
        isrelated:=false;
        hp:=@self;
        while assigned(hp) do
          begin
             if hp=d then
               begin
                  isrelated:=true;
                  exit;
               end;
             hp:=hp^.childof;
          end;
     end;

   function tclassdef.size : longint;

     begin
        size:=publicsyms^.datasize;
     end;

    procedure tclassdef.deref;

      var
         hp : pdef;
         oldrecsyms : psymtable;

      begin
         resolvedef(pdef(childof));
         oldrecsyms:=aktrecordsymtable;
         aktrecordsymtable:=publicsyms;
         { nun die Definitionen Dereferenzieren }
         hp:=publicsyms^.wurzeldef;
         while assigned(hp) do
           begin
              hp^.deref;

              {Besitzer setzten }
              hp^.owner:=publicsyms;

              hp:=hp^.next;
           end;
{$ifdef tp}
         publicsyms^.foreach(derefsym);
{$else}
         publicsyms^.foreach(@derefsym);
{$endif}
         aktrecordsymtable:=oldrecsyms;
      end;

    procedure tclassdef.write;

      var
         oldread_member : boolean;

      begin
         oldread_member:=read_member;
         read_member:=true;
         writebyte(ibclassdef);
         writelong(size);
         writestring(name^);
         writedefref(childof);
         publicsyms^.writeasstruct;
         read_member:=oldread_member;
      end;

{**************************************
               TERRORDEF
 **************************************}

   constructor terrordef.init;

     begin
        tdef.init;
        deftype:=errordef;
     end;

   procedure init_symtable;

     begin
        macros:=new(psymtable,init(macrosymtable));
        usedunits.init;
        usedunits.doubles:=false;
        read_member:=false;
        generrorsym:=new(perrorsym,init);
        swurzel:=nil;
        readunit_lastloaded:=nil;
        loaded_units:=nil;
     end;

end.
[ RETURN TO DIRECTORY ]