mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 11:59:41 +01:00 
			
		
		
		
	- remove thelpersearch again => adjustments to searchsym_in_class and calls to it - rename sto_has_classhelper to sto_has_helper * symbase.pas: make push and pop in tsymtablestack virtual * symdef.pas: - add a new class tdefawaresymtablestack which overrides push and pop of tsymtablestack and adjusts the new extendeddefs field of the current tmodule - tobjectdef.create: sto_has_classhelper => sto_has_helper * fmodule.pas: - add new hash object list to tmodule (key: mangled type name) which holds object list instances that contain all helpers currently active for a given type (= key of the hash list) - tmodule.create: the hash list owns the sublists (but those don't own the defs) - tmodule.destroy: free the hash list * pdecobjpas: - rename parse_extended_class to parse_extended_type - parsing of constructors: # for all helper types: no class constructors allowed # for record helpers: as long as constructors for records themselves are disabled they are for record helpers as well - object_dec: manually add the helper to the extendeddefs if the overall owner of the current def is a static symtable (implementation section or program/library main file), because the symtable won't be popped and pushed then * parser.pas: instantiate the new stack class * psub.pas: backup the extendeddefs in specialize_objectdefs as well * ptype.pas: - generate_specialization: backup the extendeddefs as well - record_dec: _RECORD is now consumed in read_named_type itself - read_named_type: parse "record helper" if advanced record syntax is enabled * symtable.pas: - correct searchsym_in_class declaration => adjustments in this unit as well - add the possibility to pass a context def to search_last_objectpascal_helper - rename search_objectpascal_class_helper to search_objectpascal_helper - rename search_class_helper to search_objc_helper - searchsym_in_class: # search for helpers in every level of the tree of the class # the contextclassh can also be a subclass of the extendeddef - searchsym_in_record: search for helper methods as well - searchsym_in_helper: # search for symbols in class and record helpers is the same except for the search in the class' ancestors # search the extendeddef directly and rely on searchsym_in_class only for the class' ancestors as we need to find the helpers there as well - search_last_objectpascal_helper: use the extendeddefs list of current_module instead of scanning the symbol stack itself * pexpr.pas: adjustments because of renaming of sto_has_classhelper * pinline.pas: adjustment because of removing of thelpersearch * nflw.pas: - renamed classhelper to helperdef - adjusted search_last_objectpascal_helper call * msg*: - adjusted error message for constructors in records (this currently applies to record helpers as well) - renamed parser_e_not_allowed_in_classhelper to parser_e_not_allowed_in_helper => adjustments in code - added parser_e_no_class_constructors_in_helpers * pdecsub.pas: adjusted renamed error message * htypechk.pas: check for helpers in every step of the hierarchy * nobj.pas: search_class_helper => search_objc_helper * utils/ppudump.pas: adjust, because of renames Note: the define "useoldsearch" will be only used for performance comparison on my (faster) Linux machine; that (and its associated code) will be removed afterwards git-svn-id: branches/svenbarth/classhelpers@17151 -
		
			
				
	
	
		
			442 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			442 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 1998-2002 by Florian Klaempfl, Pierre Muller
 | 
						|
 | 
						|
    This unit handles the symbol tables
 | 
						|
 | 
						|
    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 symbase;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
    uses
 | 
						|
       { common }
 | 
						|
       cutils,cclasses,
 | 
						|
       { global }
 | 
						|
       globtype,globals,
 | 
						|
       { symtable }
 | 
						|
       symconst
 | 
						|
       ;
 | 
						|
 | 
						|
{************************************************
 | 
						|
            Needed forward pointers
 | 
						|
************************************************}
 | 
						|
 | 
						|
    type
 | 
						|
       TSymtable = class;
 | 
						|
 | 
						|
       { THashedIDString }
 | 
						|
 | 
						|
       THashedIDString=object
 | 
						|
       private
 | 
						|
         FId   : TIDString;
 | 
						|
         FHash : Longword;
 | 
						|
         procedure SetId(const s:TIDString);
 | 
						|
       public
 | 
						|
         property Id:TIDString read FId write SetId;
 | 
						|
         property Hash:longword read FHash;
 | 
						|
       end;
 | 
						|
 | 
						|
 | 
						|
{************************************************
 | 
						|
                 TDefEntry
 | 
						|
************************************************}
 | 
						|
 | 
						|
      TDefEntry = class
 | 
						|
         typ   : tdeftyp;
 | 
						|
         defid : longint;
 | 
						|
         owner : TSymtable;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{************************************************
 | 
						|
                   TSymEntry
 | 
						|
************************************************}
 | 
						|
 | 
						|
      { this object is the base for all symbol objects }
 | 
						|
      TSymEntry = class(TFPHashObject)
 | 
						|
      private
 | 
						|
         FRealName : pshortstring;
 | 
						|
         function  GetRealname:shortstring;
 | 
						|
         procedure SetRealname(const ANewName:shortstring);
 | 
						|
      public
 | 
						|
         typ   : tsymtyp;
 | 
						|
         SymId : longint;
 | 
						|
         Owner : TSymtable;
 | 
						|
         destructor destroy;override;
 | 
						|
         property RealName:shortstring read GetRealName write SetRealName;
 | 
						|
      end;
 | 
						|
 | 
						|
{************************************************
 | 
						|
                 TSymtable
 | 
						|
************************************************}
 | 
						|
 | 
						|
       TSymtable = class
 | 
						|
       public
 | 
						|
          name      : pshortstring;
 | 
						|
          realname  : pshortstring;
 | 
						|
          DefList   : TFPObjectList;
 | 
						|
          SymList   : TFPHashObjectList;
 | 
						|
          defowner  : TDefEntry; { for records and objects }
 | 
						|
          moduleid  : longint;
 | 
						|
          refcount  : smallint;
 | 
						|
          currentvisibility : tvisibility;
 | 
						|
          currentlyoptional : boolean;
 | 
						|
          tableoptions : tsymtableoptions;
 | 
						|
          { level of symtable, used for nested procedures }
 | 
						|
          symtablelevel : byte;
 | 
						|
          symtabletype  : TSymtabletype;
 | 
						|
          constructor Create(const s:string);
 | 
						|
          destructor  destroy;override;
 | 
						|
          procedure freeinstance;override;
 | 
						|
          function  getcopy:TSymtable;
 | 
						|
          procedure clear;virtual;
 | 
						|
          function  checkduplicate(var s:THashedIDString;sym:TSymEntry):boolean;virtual;
 | 
						|
          procedure insert(sym:TSymEntry;checkdup:boolean=true);virtual;
 | 
						|
          procedure Delete(sym:TSymEntry);virtual;
 | 
						|
          function  Find(const s:TIDString) : TSymEntry;
 | 
						|
          function  FindWithHash(const s:THashedIDString) : TSymEntry;virtual;
 | 
						|
          procedure insertdef(def:TDefEntry);virtual;
 | 
						|
          procedure deletedef(def:TDefEntry);
 | 
						|
          function  iscurrentunit:boolean;virtual;
 | 
						|
          { includes the flag in this symtable and all parent symtables; if
 | 
						|
            it's already set the flag is not set again }
 | 
						|
          procedure includeoption(option:tsymtableoption);
 | 
						|
       end;
 | 
						|
 | 
						|
       psymtablestackitem = ^TSymtablestackitem;
 | 
						|
       TSymtablestackitem = record
 | 
						|
         symtable : TSymtable;
 | 
						|
         next     : psymtablestackitem;
 | 
						|
       end;
 | 
						|
 | 
						|
       TSymtablestack = class
 | 
						|
         stack : psymtablestackitem;
 | 
						|
         constructor create;
 | 
						|
         destructor destroy;override;
 | 
						|
         procedure clear;
 | 
						|
         procedure push(st:TSymtable); virtual;
 | 
						|
         procedure pop(st:TSymtable); virtual;
 | 
						|
         function  top:TSymtable;
 | 
						|
       end;
 | 
						|
 | 
						|
 | 
						|
    var
 | 
						|
       initialmacrosymtable: TSymtable;   { macros initially defined by the compiler or
 | 
						|
                                            given on the command line. Is common
 | 
						|
                                            for all files compiled and do not change. }
 | 
						|
       macrosymtablestack,
 | 
						|
       symtablestack        : TSymtablestack;
 | 
						|
 | 
						|
{$ifdef MEMDEBUG}
 | 
						|
    var
 | 
						|
      memrealnames : tmemdebug;
 | 
						|
{$endif MEMDEBUG}
 | 
						|
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
    uses
 | 
						|
       verbose;
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                              THashedIDString
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    procedure THashedIDString.SetId(const s:TIDString);
 | 
						|
      begin
 | 
						|
        FId:=s;
 | 
						|
        FHash:=FPHash(s);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                                TSymEntry
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    destructor TSymEntry.destroy;
 | 
						|
      begin
 | 
						|
{$ifdef MEMDEBUG}
 | 
						|
        memrealnames.start;
 | 
						|
{$endif MEMDEBUG}
 | 
						|
        stringdispose(Frealname);
 | 
						|
{$ifdef MEMDEBUG}
 | 
						|
        memrealnames.stop;
 | 
						|
{$endif MEMDEBUG}
 | 
						|
        inherited destroy;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TSymEntry.GetRealname:shortstring;
 | 
						|
      begin
 | 
						|
        if not assigned(FRealname) then
 | 
						|
          internalerror(200611011);
 | 
						|
        result:=FRealname^;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymEntry.SetRealname(const ANewName:shortstring);
 | 
						|
      begin
 | 
						|
        stringdispose(FRealname);
 | 
						|
        FRealname:=stringdup(ANewName);
 | 
						|
        if Hash<>$ffffffff then
 | 
						|
          begin
 | 
						|
            if FRealname^[1]='$' then
 | 
						|
              Rename(Copy(FRealname^,2,255))
 | 
						|
            else
 | 
						|
              Rename(Upper(FRealname^));
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                                TSymtable
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    constructor TSymtable.Create(const s:string);
 | 
						|
      begin
 | 
						|
         if s<>'' then
 | 
						|
           begin
 | 
						|
             name:=stringdup(upper(s));
 | 
						|
             realname:=stringdup(s);
 | 
						|
           end
 | 
						|
         else
 | 
						|
           begin
 | 
						|
             name:=nil;
 | 
						|
             realname:=nil;
 | 
						|
           end;
 | 
						|
         symtabletype:=abstractsymtable;
 | 
						|
         symtablelevel:=0;
 | 
						|
         defowner:=nil;
 | 
						|
         DefList:=TFPObjectList.Create(true);
 | 
						|
         SymList:=TFPHashObjectList.Create(true);
 | 
						|
         refcount:=1;
 | 
						|
         currentvisibility:=vis_public;
 | 
						|
         currentlyoptional:=false;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    destructor TSymtable.destroy;
 | 
						|
      begin
 | 
						|
        { freeinstance decreases refcount }
 | 
						|
        if refcount>1 then
 | 
						|
          exit;
 | 
						|
        Clear;
 | 
						|
        DefList.Free;
 | 
						|
        { SymList can already be disposed or set to nil for withsymtable, }
 | 
						|
        { but in that case Free does nothing                              }
 | 
						|
        SymList.Free;
 | 
						|
        stringdispose(name);
 | 
						|
        stringdispose(realname);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymtable.freeinstance;
 | 
						|
      begin
 | 
						|
        dec(refcount);
 | 
						|
        if refcount=0 then
 | 
						|
          inherited freeinstance;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TSymtable.getcopy:TSymtable;
 | 
						|
      begin
 | 
						|
        inc(refcount);
 | 
						|
        result:=self;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TSymtable.iscurrentunit:boolean;
 | 
						|
      begin
 | 
						|
        result:=false;
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure TSymtable.includeoption(option: tsymtableoption);
 | 
						|
      var
 | 
						|
        st: tsymtable;
 | 
						|
      begin
 | 
						|
        if option in tableoptions then
 | 
						|
          exit;
 | 
						|
        include(tableoptions,option);
 | 
						|
        { iterative approach should be faster than recursion based on calls }
 | 
						|
        st:=self;
 | 
						|
        while assigned(st.defowner) do
 | 
						|
          begin
 | 
						|
            st:=st.defowner.owner;
 | 
						|
            { the flag is already set, so by definition it is set in the
 | 
						|
              owning symtables as well }
 | 
						|
            if option in st.tableoptions then
 | 
						|
              break;
 | 
						|
            include(st.tableoptions,option);
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymtable.clear;
 | 
						|
      var
 | 
						|
        i : integer;
 | 
						|
      begin
 | 
						|
         SymList.Clear;
 | 
						|
         { Prevent recursive calls between TDef.destroy and TSymtable.Remove }
 | 
						|
         if DefList.OwnsObjects then
 | 
						|
           begin
 | 
						|
             for i := 0 to DefList.Count-1 do
 | 
						|
               TDefEntry(DefList[i]).Owner:=nil;
 | 
						|
           end;
 | 
						|
         DefList.Clear;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TSymtable.checkduplicate(var s:THashedIDString;sym:TSymEntry):boolean;
 | 
						|
      begin
 | 
						|
        result:=(FindWithHash(s)<>nil);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymtable.insert(sym:TSymEntry;checkdup:boolean=true);
 | 
						|
      var
 | 
						|
        hashedid : THashedIDString;
 | 
						|
      begin
 | 
						|
         if checkdup then
 | 
						|
           begin
 | 
						|
             if sym.realname[1]='$' then
 | 
						|
               hashedid.id:=Copy(sym.realname,2,255)
 | 
						|
             else
 | 
						|
               hashedid.id:=Upper(sym.realname);
 | 
						|
             { First check for duplicates, this can change the symbol name
 | 
						|
               in case of a duplicate entry }
 | 
						|
             checkduplicate(hashedid,sym);
 | 
						|
           end;
 | 
						|
         { Now we can insert the symbol, any duplicate entries
 | 
						|
           are renamed to an unique (and for users unaccessible) name }
 | 
						|
         if sym.realname[1]='$' then
 | 
						|
           sym.ChangeOwnerAndName(SymList,Copy(sym.realname,2,255))
 | 
						|
         else
 | 
						|
           sym.ChangeOwnerAndName(SymList,Upper(sym.realname));
 | 
						|
         sym.Owner:=self;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymtable.Delete(sym:TSymEntry);
 | 
						|
      begin
 | 
						|
        if sym.Owner<>self then
 | 
						|
          internalerror(200611121);
 | 
						|
        SymList.Remove(sym);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymtable.insertdef(def:TDefEntry);
 | 
						|
      begin
 | 
						|
         DefList.Add(def);
 | 
						|
         def.owner:=self;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymtable.deletedef(def:TDefEntry);
 | 
						|
      begin
 | 
						|
        if def.Owner<>self then
 | 
						|
          internalerror(200611122);
 | 
						|
        def.Owner:=nil;
 | 
						|
        DefList.Remove(def);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TSymtable.Find(const s : TIDString) : TSymEntry;
 | 
						|
      begin
 | 
						|
        result:=TSymEntry(SymList.Find(s));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TSymtable.FindWithHash(const s:THashedIDString) : TSymEntry;
 | 
						|
      begin
 | 
						|
        result:=TSymEntry(SymList.FindWithHash(s.id,s.hash));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                            Symtable Stack
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    constructor TSymtablestack.create;
 | 
						|
      begin
 | 
						|
        stack:=nil;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    destructor TSymtablestack.destroy;
 | 
						|
      begin
 | 
						|
        clear;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymtablestack.clear;
 | 
						|
      var
 | 
						|
        hp : psymtablestackitem;
 | 
						|
      begin
 | 
						|
        while assigned(stack) do
 | 
						|
          begin
 | 
						|
            hp:=stack;
 | 
						|
            stack:=hp^.next;
 | 
						|
            dispose(hp);
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymtablestack.push(st:TSymtable);
 | 
						|
      var
 | 
						|
        hp : psymtablestackitem;
 | 
						|
      begin
 | 
						|
        new(hp);
 | 
						|
        hp^.symtable:=st;
 | 
						|
        hp^.next:=stack;
 | 
						|
        stack:=hp;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TSymtablestack.pop(st:TSymtable);
 | 
						|
      var
 | 
						|
        hp : psymtablestackitem;
 | 
						|
      begin
 | 
						|
        if not assigned(stack) then
 | 
						|
          internalerror(200601231);
 | 
						|
        if stack^.symtable<>st then
 | 
						|
          internalerror(200601232);
 | 
						|
        hp:=stack;
 | 
						|
        stack:=hp^.next;
 | 
						|
        dispose(hp);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TSymtablestack.top:TSymtable;
 | 
						|
      begin
 | 
						|
        if not assigned(stack) then
 | 
						|
          internalerror(200601233);
 | 
						|
        result:=stack^.symtable;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{$ifdef MEMDEBUG}
 | 
						|
initialization
 | 
						|
  memrealnames:=TMemDebug.create('Realnames');
 | 
						|
  memrealnames.stop;
 | 
						|
 | 
						|
finalization
 | 
						|
  memrealnames.free;
 | 
						|
{$endif MEMDEBUG}
 | 
						|
end.
 |