123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- {
- 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 : {$ifdef symansistr}TSymStr{$else}pshortstring{$endif};
- function GetEscapedRealName: TSymStr;
- function GetRealname: TSymStr;
- procedure SetRealname(const ANewName: TSymStr);
- public
- typ : tsymtyp;
- SymId : longint;
- Owner : TSymtable;
- destructor destroy;override;
- property RealName: TSymStr read GetRealName write SetRealName;
- property EscapedRealName: TSymStr read GetEscapedRealName;
- 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;
- { do not allow to add new definitions, can be extended to symbols probably }
- sealed : boolean;
- symtabletype : TSymtabletype;
- constructor Create(const s:string);
- { attention: only execute the a child's destructor if refcount is 1! }
- 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;
- function finditem(st:TSymtable):psymtablestackitem;
- procedure push(st:TSymtable); virtual;
- procedure pushafter(st,afterst:TSymtable); virtual;
- procedure pop(st:TSymtable); virtual;
- function top:TSymtable;
- function getcopyuntil(finalst: TSymtable): TSymtablestack;
- 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;
- {$ifdef symansistr}
- if length(FId)>maxidlen then
- SetLength(FId,maxidlen);
- {$endif}
- FHash:=FPHash(s);
- end;
- {****************************************************************************
- TSymEntry
- ****************************************************************************}
- destructor TSymEntry.destroy;
- begin
- {$ifdef MEMDEBUG}
- memrealnames.start;
- {$endif MEMDEBUG}
- {$ifndef symansistr}
- stringdispose(Frealname);
- {$endif}
- {$ifdef MEMDEBUG}
- memrealnames.stop;
- {$endif MEMDEBUG}
- inherited destroy;
- end;
- function TSymEntry.GetRealname:TSymStr;
- begin
- {$ifndef symansistr}
- if not assigned(FRealname) then
- internalerror(200611011);
- result:=FRealname^;
- {$else}
- if FRealName='' then
- internalerror(200611011);
- result:=FRealName;
- {$endif}
- end;
- function TSymEntry.GetEscapedRealName: TSymStr;
- begin
- result:=GetRealname;
- if result=Name then
- result:='$'+result;
- end;
- procedure TSymEntry.SetRealname(const ANewName:TSymStr);
- begin
- {$ifndef symansistr}
- stringdispose(FRealname);
- FRealname:=stringdup(ANewName);
- {$else}
- FRealname:=ANewName;
- {$endif}
- if Hash<>$ffffffff then
- begin
- if ANewName[1]='$' then
- Rename(Copy(ANewName,2,length(ANewName)))
- else
- Rename(Upper(ANewName));
- 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;
- { this can happen for specializations of routines that are not yet
- owned cause they might be thrown away again }
- if not assigned(st) then
- break;
- { 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;
- function TSymtablestack.finditem(st: TSymtable): psymtablestackitem;
- begin
- if not assigned(stack) then
- internalerror(200601233);
- result:=stack;
- while assigned(result)and(result^.symtable<>st) do
- result:=result^.next;
- end;
- procedure TSymtablestack.push(st:TSymtable);
- var
- hp : psymtablestackitem;
- begin
- new(hp);
- hp^.symtable:=st;
- hp^.next:=stack;
- stack:=hp;
- end;
- procedure TSymtablestack.pushafter(st,afterst:TSymtable);
- var
- hp,afteritem: psymtablestackitem;
- begin
- afteritem:=finditem(afterst);
- if assigned(afteritem) then
- begin
- new(hp);
- hp^.symtable:=st;
- hp^.next:=afteritem^.next;
- afteritem^.next:=hp;
- end
- else
- internalerror(201309171);
- 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(2006012304);
- result:=stack^.symtable;
- end;
- function addstitemreverse(st: TSymtablestack; finalst: tsymtable; curitem: psymtablestackitem): boolean;
- begin
- if not assigned(curitem) then
- begin
- result:=true;
- exit;
- end;
- if addstitemreverse(st,finalst,curitem^.next) then
- begin
- st.push(curitem^.symtable);
- result:=curitem^.symtable<>finalst
- end
- else
- result:=false
- end;
- function TSymtablestack.getcopyuntil(finalst: TSymtable): TSymtablestack;
- begin
- result:=TSymtablestack.create;
- addstitemreverse(result,finalst,stack);
- end;
- {$ifdef MEMDEBUG}
- initialization
- memrealnames:=TMemDebug.create('Realnames');
- memrealnames.stop;
- finalization
- memrealnames.free;
- {$endif MEMDEBUG}
- end.
|