mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 02:51:37 +01:00 
			
		
		
		
	 f7f357f18e
			
		
	
	
		f7f357f18e
		
	
	
	
	
		
			
			- 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.
 |