mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-17 21:39:37 +02:00

starting with a previous 2.3.1 or compiler built from the objc branch + added basic objcprotocol support (only for external protocols currently) o use in type declaration: "type xp = objcprotocol ... end;" o when defining a root class that implements it: "type yc = objcclass(xp) ... end" (note: no support yet for something like "objcclass(id,xp)" or so) o when defining a non-root class that implements a protocol: "type zc = objcclass(nsobject,xp) ... end" o includes support for "required" and "optional" sections o no support yet for the objcprotocol(<protocol>) expression that enables getting a class instance representing the protocol (e.g., for use with "conformsToProtocol:") o message names have to specified in protocol declarations, but if an objcclass implements a protocol, the message names do not have to be repeated (but if they are, they have to match; the same goes when overriding inherited methods) + allow specifying the external name of Objective-C classes and protocols, since classes and protocols can have the same name (and you cannot use the same Pascal identifier in such caseq) + added NSObject protocol, and make the NSObject class use it + added missing NSObject class methods that have the same name as instance methods (added "class" name prefix to avoid clashes) * fixed several cases where the compiler did not treat Objective-C classes/protocols the same as Object Pascal classes/interfaces (a.o., forward declarations, alignment, regvars, several type conversions, ...) * allow "override" directive in objcclass declarations, and print a hint if it's forgotten in an external declaration (because it doesn't really matter there, and may make automated header conversion harder than necessary) and an error if will be used in a non-external declaration (because it is not possible to start a new vmt entry-tree in Objective-C, you can only override parent methods) * reject objcclasses/protocols as parameters to typeof() * don't try to test VMT validity of objcclasses/protocols git-svn-id: branches/objc@13375 -
418 lines
11 KiB
ObjectPascal
418 lines
11 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;
|
|
{ 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;
|
|
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);
|
|
procedure pop(st:TSymtable);
|
|
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.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.
|