fpc/compiler/symbase.pas
svenbarth f7f357f18e * symconst.pas:
- 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 -
2011-03-20 11:27:27 +00:00

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.