mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-23 20:32:51 +00:00
- moved the compiler symbols into their own file.
- removed all pointer declarations to types from the symbols. All types must be placed into the type table which means that they can be considered static.
This commit is contained in:
parent
5a81a4ca16
commit
18c532c307
6 changed files with 728 additions and 564 deletions
|
@ -1194,6 +1194,7 @@ set (PCH_SOURCES
|
|||
r_data/voxels.cpp
|
||||
r_data/renderstyle.cpp
|
||||
r_data/r_interpolate.cpp
|
||||
scripting/symbols.cpp
|
||||
scripting/thingdef.cpp
|
||||
scripting/thingdef_data.cpp
|
||||
scripting/thingdef_properties.cpp
|
||||
|
|
|
@ -603,6 +603,7 @@ static inline void GC::WriteBarrier(DObject *pointed)
|
|||
}
|
||||
}
|
||||
|
||||
#include "symbols.h"
|
||||
#include "dobjtype.h"
|
||||
|
||||
inline bool DObject::IsKindOf (const PClass *base) const
|
||||
|
|
288
src/dobjtype.cpp
288
src/dobjtype.cpp
|
@ -66,7 +66,6 @@ EXTERN_CVAR(Bool, strictdecorate);
|
|||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy.
|
||||
FNamespaceManager Namespaces;
|
||||
|
||||
FTypeTable TypeTable;
|
||||
TArray<PClass *> PClass::AllClasses;
|
||||
|
@ -2683,68 +2682,6 @@ PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *>
|
|||
return static_cast<PPrototype *>(proto);
|
||||
}
|
||||
|
||||
/* PFunction **************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PFunction, false, false)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PFunction :: PropagataMark
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
size_t PFunction::PropagateMark()
|
||||
{
|
||||
for (unsigned i = 0; i < Variants.Size(); ++i)
|
||||
{
|
||||
GC::Mark(Variants[i].Proto);
|
||||
}
|
||||
return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PFunction :: AddVariant
|
||||
//
|
||||
// Adds a new variant for this function. Does not check if a matching
|
||||
// variant already exists.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags, int useflags)
|
||||
{
|
||||
Variant variant;
|
||||
|
||||
// I do not think we really want to deal with overloading here...
|
||||
assert(Variants.Size() == 0);
|
||||
|
||||
variant.Flags = flags;
|
||||
variant.UseFlags = useflags;
|
||||
variant.Proto = proto;
|
||||
variant.ArgFlags = std::move(argflags);
|
||||
variant.ArgNames = std::move(argnames);
|
||||
variant.Implementation = impl;
|
||||
if (impl != nullptr) impl->Proto = proto;
|
||||
|
||||
// SelfClass can differ from OwningClass, but this is variant-dependent.
|
||||
// Unlike the owner there can be cases where different variants can have different SelfClasses.
|
||||
// (Of course only if this ever gets enabled...)
|
||||
if (flags & VARF_Method)
|
||||
{
|
||||
assert(proto->ArgumentTypes.Size() > 0);
|
||||
auto selftypeptr = dyn_cast<PPointer>(proto->ArgumentTypes[0]);
|
||||
assert(selftypeptr != nullptr);
|
||||
variant.SelfClass = dyn_cast<PStruct>(selftypeptr->PointedType);
|
||||
assert(variant.SelfClass != nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
variant.SelfClass = nullptr;
|
||||
}
|
||||
|
||||
return Variants.Push(variant);
|
||||
}
|
||||
|
||||
/* PClass *****************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PClass, false, true)
|
||||
|
@ -3863,228 +3800,3 @@ CCMD(typetable)
|
|||
DumpTypeTable();
|
||||
}
|
||||
|
||||
// Symbol tables ------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS(PTypeBase, true, false);
|
||||
IMPLEMENT_CLASS(PSymbol, true, false);
|
||||
IMPLEMENT_CLASS(PSymbolConst, false, false);
|
||||
IMPLEMENT_CLASS(PSymbolConstNumeric, false, false);
|
||||
IMPLEMENT_CLASS(PSymbolConstString, false, false);
|
||||
IMPLEMENT_CLASS(PSymbolTreeNode, false, false)
|
||||
IMPLEMENT_CLASS(PSymbolType, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(PSymbolType)
|
||||
IMPLEMENT_POINTER(Type)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
IMPLEMENT_CLASS(PSymbolVMFunction, false, false)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PSymbol::~PSymbol()
|
||||
{
|
||||
}
|
||||
|
||||
PSymbolTable::PSymbolTable()
|
||||
: ParentSymbolTable(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
PSymbolTable::PSymbolTable(PSymbolTable *parent)
|
||||
: ParentSymbolTable(parent)
|
||||
{
|
||||
}
|
||||
|
||||
PSymbolTable::~PSymbolTable ()
|
||||
{
|
||||
ReleaseSymbols();
|
||||
}
|
||||
|
||||
size_t PSymbolTable::MarkSymbols()
|
||||
{
|
||||
size_t count = 0;
|
||||
MapType::Iterator it(Symbols);
|
||||
MapType::Pair *pair;
|
||||
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
GC::Mark(pair->Value);
|
||||
count++;
|
||||
}
|
||||
return count * sizeof(*pair);
|
||||
}
|
||||
|
||||
void PSymbolTable::ReleaseSymbols()
|
||||
{
|
||||
// The GC will take care of deleting the symbols. We just need to
|
||||
// clear our references to them.
|
||||
Symbols.Clear();
|
||||
}
|
||||
|
||||
void PSymbolTable::SetParentTable (PSymbolTable *parent)
|
||||
{
|
||||
ParentSymbolTable = parent;
|
||||
}
|
||||
|
||||
PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const
|
||||
{
|
||||
PSymbol * const *value = Symbols.CheckKey(symname);
|
||||
if (value == nullptr && searchparents && ParentSymbolTable != nullptr)
|
||||
{
|
||||
return ParentSymbolTable->FindSymbol(symname, searchparents);
|
||||
}
|
||||
return value != nullptr ? *value : nullptr;
|
||||
}
|
||||
|
||||
PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable)
|
||||
{
|
||||
PSymbol * const *value = Symbols.CheckKey(symname);
|
||||
if (value == nullptr)
|
||||
{
|
||||
if (ParentSymbolTable != nullptr)
|
||||
{
|
||||
return ParentSymbolTable->FindSymbolInTable(symname, symtable);
|
||||
}
|
||||
symtable = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
symtable = this;
|
||||
return *value;
|
||||
}
|
||||
|
||||
PSymbol *PSymbolTable::AddSymbol (PSymbol *sym)
|
||||
{
|
||||
// Symbols that already exist are not inserted.
|
||||
if (Symbols.CheckKey(sym->SymbolName) != nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
Symbols.Insert(sym->SymbolName, sym);
|
||||
return sym;
|
||||
}
|
||||
|
||||
void PSymbolTable::RemoveSymbol(PSymbol *sym)
|
||||
{
|
||||
auto mysym = Symbols.CheckKey(sym->SymbolName);
|
||||
if (mysym == nullptr || *mysym != sym) return;
|
||||
Symbols.Remove(sym->SymbolName);
|
||||
}
|
||||
|
||||
PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym)
|
||||
{
|
||||
// If a symbol with a matching name exists, take its place and return it.
|
||||
PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName);
|
||||
if (symslot != nullptr)
|
||||
{
|
||||
PSymbol *oldsym = *symslot;
|
||||
*symslot = newsym;
|
||||
return oldsym;
|
||||
}
|
||||
// Else, just insert normally and return nullptr since there was no
|
||||
// symbol to replace.
|
||||
Symbols.Insert(newsym->SymbolName, newsym);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(PNamespace, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(PNamespace)
|
||||
IMPLEMENT_POINTER(Parent)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
PNamespace::PNamespace(int filenum, PNamespace *parent)
|
||||
{
|
||||
Parent = parent;
|
||||
if (parent) Symbols.SetParentTable(&parent->Symbols);
|
||||
FileNum = filenum;
|
||||
}
|
||||
|
||||
size_t PNamespace::PropagateMark()
|
||||
{
|
||||
GC::Mark(Parent);
|
||||
return Symbols.MarkSymbols() + 1;
|
||||
}
|
||||
|
||||
FNamespaceManager::FNamespaceManager()
|
||||
{
|
||||
GlobalNamespace = nullptr;
|
||||
}
|
||||
|
||||
PNamespace *FNamespaceManager::NewNamespace(int filenum)
|
||||
{
|
||||
PNamespace *parent = nullptr;
|
||||
// The parent will be the last namespace with this or a lower filenum.
|
||||
// This ensures that DECORATE won't see the symbols of later files.
|
||||
for (int i = AllNamespaces.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (AllNamespaces[i]->FileNum <= filenum)
|
||||
{
|
||||
parent = AllNamespaces[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto newns = new PNamespace(filenum, parent);
|
||||
AllNamespaces.Push(newns);
|
||||
return newns;
|
||||
}
|
||||
|
||||
size_t FNamespaceManager::MarkSymbols()
|
||||
{
|
||||
for (auto ns : AllNamespaces)
|
||||
{
|
||||
GC::Mark(ns);
|
||||
}
|
||||
return AllNamespaces.Size();
|
||||
}
|
||||
|
||||
void FNamespaceManager::ReleaseSymbols()
|
||||
{
|
||||
GlobalNamespace = nullptr;
|
||||
AllNamespaces.Clear();
|
||||
}
|
||||
|
||||
// removes all symbols from the symbol tables.
|
||||
// After running the compiler these are not needed anymore.
|
||||
// Only the namespaces themselves are kept because the type table references them.
|
||||
int FNamespaceManager::RemoveSymbols()
|
||||
{
|
||||
int count = 0;
|
||||
for (auto ns : AllNamespaces)
|
||||
{
|
||||
count += ns->Symbols.Symbols.CountUsed();
|
||||
ns->Symbols.ReleaseSymbols();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void RemoveUnusedSymbols()
|
||||
{
|
||||
// Global symbols are not needed anymore after running the compiler.
|
||||
int count = Namespaces.RemoveSymbols();
|
||||
|
||||
// We do not need any non-field and non-function symbols in structs and classes anymore.
|
||||
for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i)
|
||||
{
|
||||
for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext)
|
||||
{
|
||||
if (ty->IsKindOf(RUNTIME_CLASS(PStruct)))
|
||||
{
|
||||
auto it = ty->Symbols.GetIterator();
|
||||
PSymbolTable::MapType::Pair *pair;
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction)))
|
||||
{
|
||||
ty->Symbols.RemoveSymbol(pair->Value);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DPrintf(DMSG_SPAMMY, "%d symbols removed after compilation\n", count);
|
||||
}
|
||||
|
|
276
src/dobjtype.h
276
src/dobjtype.h
|
@ -39,36 +39,6 @@ enum
|
|||
VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature
|
||||
};
|
||||
|
||||
// Symbol information -------------------------------------------------------
|
||||
|
||||
class PTypeBase : public DObject
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(PTypeBase, DObject)
|
||||
|
||||
public:
|
||||
virtual FString QualifiedName() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
class PSymbol : public PTypeBase
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase);
|
||||
public:
|
||||
virtual ~PSymbol();
|
||||
|
||||
virtual FString QualifiedName() const
|
||||
{
|
||||
return SymbolName.GetChars();
|
||||
}
|
||||
|
||||
FName SymbolName;
|
||||
|
||||
protected:
|
||||
PSymbol(FName name) { SymbolName = name; }
|
||||
};
|
||||
|
||||
// An action function -------------------------------------------------------
|
||||
|
||||
struct FState;
|
||||
|
@ -79,100 +49,6 @@ struct VMReturn;
|
|||
class VMFunction;
|
||||
struct FNamespaceManager;
|
||||
|
||||
// A VM function ------------------------------------------------------------
|
||||
|
||||
class PSymbolVMFunction : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PSymbolVMFunction, PSymbol);
|
||||
public:
|
||||
VMFunction *Function;
|
||||
|
||||
PSymbolVMFunction(FName name) : PSymbol(name) {}
|
||||
PSymbolVMFunction() : PSymbol(NAME_None) {}
|
||||
};
|
||||
|
||||
// A symbol for a type ------------------------------------------------------
|
||||
|
||||
class PSymbolType : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PSymbolType, PSymbol);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
class PType *Type;
|
||||
|
||||
PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {}
|
||||
PSymbolType() : PSymbol(NAME_None) {}
|
||||
};
|
||||
|
||||
// A symbol table -----------------------------------------------------------
|
||||
|
||||
struct PSymbolTable
|
||||
{
|
||||
PSymbolTable();
|
||||
PSymbolTable(PSymbolTable *parent);
|
||||
~PSymbolTable();
|
||||
|
||||
size_t MarkSymbols();
|
||||
|
||||
// Sets the table to use for searches if this one doesn't contain the
|
||||
// requested symbol.
|
||||
void SetParentTable (PSymbolTable *parent);
|
||||
PSymbolTable *GetParentTable() const
|
||||
{
|
||||
return ParentSymbolTable;
|
||||
}
|
||||
|
||||
// Finds a symbol in the table, optionally searching parent tables
|
||||
// as well.
|
||||
PSymbol *FindSymbol (FName symname, bool searchparents) const;
|
||||
|
||||
// Like FindSymbol with searchparents set true, but also returns the
|
||||
// specific symbol table the symbol was found in.
|
||||
PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable);
|
||||
|
||||
|
||||
// Places the symbol in the table and returns a pointer to it or NULL if
|
||||
// a symbol with the same name is already in the table. This symbol is
|
||||
// not copied and will be freed when the symbol table is destroyed.
|
||||
PSymbol *AddSymbol (PSymbol *sym);
|
||||
|
||||
// Similar to AddSymbol but always succeeds. Returns the symbol that used
|
||||
// to be in the table with this name, if any.
|
||||
PSymbol *ReplaceSymbol(PSymbol *sym);
|
||||
|
||||
void RemoveSymbol(PSymbol *sym);
|
||||
|
||||
// Frees all symbols from this table.
|
||||
void ReleaseSymbols();
|
||||
|
||||
typedef TMap<FName, PSymbol *> MapType;
|
||||
|
||||
MapType::Iterator GetIterator()
|
||||
{
|
||||
return MapType::Iterator(Symbols);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PSymbolTable *ParentSymbolTable;
|
||||
MapType Symbols;
|
||||
|
||||
friend class DObject;
|
||||
friend struct FNamespaceManager;
|
||||
};
|
||||
|
||||
// A symbol for a compiler tree node ----------------------------------------
|
||||
|
||||
class PSymbolTreeNode : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PSymbolTreeNode, PSymbol);
|
||||
public:
|
||||
struct ZCC_TreeNode *Node;
|
||||
|
||||
PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {}
|
||||
PSymbolTreeNode() : PSymbol(NAME_None) {}
|
||||
};
|
||||
|
||||
// Basic information shared by all types ------------------------------------
|
||||
|
||||
// Only one copy of a type is ever instantiated at one time.
|
||||
|
@ -536,52 +412,6 @@ public:
|
|||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
};
|
||||
|
||||
// Struct/class fields ------------------------------------------------------
|
||||
|
||||
// A PField describes a symbol that takes up physical space in the struct.
|
||||
class PField : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PField, PSymbol);
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = 0);
|
||||
|
||||
size_t Offset;
|
||||
PType *Type;
|
||||
DWORD Flags;
|
||||
int BitValue;
|
||||
protected:
|
||||
PField();
|
||||
};
|
||||
|
||||
// Struct/class fields ------------------------------------------------------
|
||||
|
||||
// A PField describes a symbol that takes up physical space in the struct.
|
||||
class PProperty : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PProperty, PSymbol);
|
||||
public:
|
||||
PProperty(FName name, TArray<PField *> &variables);
|
||||
|
||||
TArray<PField *> Variables;
|
||||
|
||||
protected:
|
||||
PProperty();
|
||||
};
|
||||
|
||||
class PPropFlag : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PPropFlag, PSymbol);
|
||||
public:
|
||||
PPropFlag(FName name, PField *offset, int bitval);
|
||||
|
||||
PField *Offset;
|
||||
int bitval;
|
||||
|
||||
protected:
|
||||
PPropFlag();
|
||||
};
|
||||
|
||||
// Compound types -----------------------------------------------------------
|
||||
|
||||
class PEnum : public PInt
|
||||
|
@ -729,36 +559,6 @@ protected:
|
|||
PPrototype();
|
||||
};
|
||||
|
||||
// TBD: Should we really support overloading?
|
||||
class PFunction : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PFunction, PSymbol);
|
||||
public:
|
||||
struct Variant
|
||||
{
|
||||
PPrototype *Proto;
|
||||
VMFunction *Implementation;
|
||||
TArray<DWORD> ArgFlags; // Should be the same length as Proto->ArgumentTypes
|
||||
TArray<FName> ArgNames; // we need the names to access them later when the function gets compiled.
|
||||
uint32_t Flags;
|
||||
int UseFlags;
|
||||
PStruct *SelfClass;
|
||||
};
|
||||
TArray<Variant> Variants;
|
||||
PStruct *OwningClass = nullptr;
|
||||
|
||||
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags, int useflags);
|
||||
int GetImplicitArgs()
|
||||
{
|
||||
if (Variants[0].Flags & VARF_Action) return 3;
|
||||
else if (Variants[0].Flags & VARF_Method) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t PropagateMark();
|
||||
|
||||
PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {}
|
||||
};
|
||||
|
||||
// Meta-info for every class derived from DObject ---------------------------
|
||||
|
||||
|
@ -914,82 +714,6 @@ extern PStateLabel *TypeStateLabel;
|
|||
extern PPointer *TypeNullPtr;
|
||||
extern PPointer *TypeVoidPtr;
|
||||
|
||||
// A constant value ---------------------------------------------------------
|
||||
|
||||
class PSymbolConst : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PSymbolConst, PSymbol);
|
||||
public:
|
||||
PType *ValueType;
|
||||
|
||||
PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {}
|
||||
PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {}
|
||||
};
|
||||
|
||||
// A constant numeric value -------------------------------------------------
|
||||
|
||||
class PSymbolConstNumeric : public PSymbolConst
|
||||
{
|
||||
DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst);
|
||||
public:
|
||||
union
|
||||
{
|
||||
int Value;
|
||||
double Float;
|
||||
void *Pad;
|
||||
};
|
||||
|
||||
PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {}
|
||||
PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {}
|
||||
PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {}
|
||||
PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {}
|
||||
PSymbolConstNumeric() {}
|
||||
};
|
||||
|
||||
// A constant string value --------------------------------------------------
|
||||
|
||||
class PSymbolConstString : public PSymbolConst
|
||||
{
|
||||
DECLARE_CLASS(PSymbolConstString, PSymbolConst);
|
||||
public:
|
||||
FString Str;
|
||||
|
||||
PSymbolConstString(FName name, const FString &str) : PSymbolConst(name, TypeString), Str(str) {}
|
||||
PSymbolConstString() {}
|
||||
};
|
||||
|
||||
// Namespaces --------------------------------------------------
|
||||
|
||||
class PNamespace : public PTypeBase
|
||||
{
|
||||
DECLARE_CLASS(PNamespace, PTypeBase)
|
||||
HAS_OBJECT_POINTERS;
|
||||
|
||||
public:
|
||||
PSymbolTable Symbols;
|
||||
PNamespace *Parent;
|
||||
int FileNum; // This is for blocking DECORATE access to later files.
|
||||
|
||||
PNamespace() {}
|
||||
PNamespace(int filenum, PNamespace *parent);
|
||||
size_t PropagateMark();
|
||||
};
|
||||
|
||||
struct FNamespaceManager
|
||||
{
|
||||
PNamespace *GlobalNamespace;
|
||||
TArray<PNamespace *> AllNamespaces;
|
||||
|
||||
FNamespaceManager();
|
||||
PNamespace *NewNamespace(int filenum);
|
||||
size_t MarkSymbols();
|
||||
void ReleaseSymbols();
|
||||
int RemoveSymbols();
|
||||
};
|
||||
|
||||
extern FNamespaceManager Namespaces;
|
||||
|
||||
|
||||
// Enumerations for serializing types in an archive -------------------------
|
||||
|
||||
inline bool &DObject::BoolVar(FName field)
|
||||
|
|
440
src/scripting/symbols.cpp
Normal file
440
src/scripting/symbols.cpp
Normal file
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
** symbols.cpp
|
||||
** Implements the symbol types and symbol table
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2016 Randy Heit
|
||||
** Copyright 2006-2017 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
#include "dobject.h"
|
||||
#include "i_system.h"
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
FNamespaceManager Namespaces;
|
||||
|
||||
// Symbol tables ------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS(PTypeBase, true, false);
|
||||
IMPLEMENT_CLASS(PSymbol, true, false);
|
||||
IMPLEMENT_CLASS(PSymbolConst, false, false);
|
||||
IMPLEMENT_CLASS(PSymbolConstNumeric, false, false);
|
||||
IMPLEMENT_CLASS(PSymbolConstString, false, false);
|
||||
IMPLEMENT_CLASS(PSymbolTreeNode, false, false)
|
||||
IMPLEMENT_CLASS(PSymbolType, false, false)
|
||||
IMPLEMENT_CLASS(PSymbolVMFunction, false, false)
|
||||
IMPLEMENT_CLASS(PFunction, false, false)
|
||||
IMPLEMENT_CLASS(PNamespace, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(PNamespace)
|
||||
IMPLEMENT_POINTER(Parent)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PSymbol::~PSymbol()
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PSymbolConstString::PSymbolConstString(FName name, const FString &str)
|
||||
: PSymbolConst(name, TypeString), Str(str)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PFunction :: AddVariant
|
||||
//
|
||||
// Adds a new variant for this function. Does not check if a matching
|
||||
// variant already exists.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags, int useflags)
|
||||
{
|
||||
Variant variant;
|
||||
|
||||
// I do not think we really want to deal with overloading here...
|
||||
assert(Variants.Size() == 0);
|
||||
|
||||
variant.Flags = flags;
|
||||
variant.UseFlags = useflags;
|
||||
variant.Proto = proto;
|
||||
variant.ArgFlags = std::move(argflags);
|
||||
variant.ArgNames = std::move(argnames);
|
||||
variant.Implementation = impl;
|
||||
if (impl != nullptr) impl->Proto = proto;
|
||||
|
||||
// SelfClass can differ from OwningClass, but this is variant-dependent.
|
||||
// Unlike the owner there can be cases where different variants can have different SelfClasses.
|
||||
// (Of course only if this ever gets enabled...)
|
||||
if (flags & VARF_Method)
|
||||
{
|
||||
assert(proto->ArgumentTypes.Size() > 0);
|
||||
auto selftypeptr = dyn_cast<PPointer>(proto->ArgumentTypes[0]);
|
||||
assert(selftypeptr != nullptr);
|
||||
variant.SelfClass = dyn_cast<PStruct>(selftypeptr->PointedType);
|
||||
assert(variant.SelfClass != nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
variant.SelfClass = nullptr;
|
||||
}
|
||||
|
||||
return Variants.Push(variant);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int PFunction::GetImplicitArgs()
|
||||
{
|
||||
if (Variants[0].Flags & VARF_Action) return 3;
|
||||
else if (Variants[0].Flags & VARF_Method) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PSymbolTable::PSymbolTable()
|
||||
: ParentSymbolTable(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
PSymbolTable::PSymbolTable(PSymbolTable *parent)
|
||||
: ParentSymbolTable(parent)
|
||||
{
|
||||
}
|
||||
|
||||
PSymbolTable::~PSymbolTable ()
|
||||
{
|
||||
ReleaseSymbols();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
size_t PSymbolTable::MarkSymbols()
|
||||
{
|
||||
size_t count = 0;
|
||||
MapType::Iterator it(Symbols);
|
||||
MapType::Pair *pair;
|
||||
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
GC::Mark(pair->Value);
|
||||
count++;
|
||||
}
|
||||
return count * sizeof(*pair);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PSymbolTable::ReleaseSymbols()
|
||||
{
|
||||
// The GC will take care of deleting the symbols. We just need to
|
||||
// clear our references to them.
|
||||
Symbols.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PSymbolTable::SetParentTable (PSymbolTable *parent)
|
||||
{
|
||||
ParentSymbolTable = parent;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const
|
||||
{
|
||||
PSymbol * const *value = Symbols.CheckKey(symname);
|
||||
if (value == nullptr && searchparents && ParentSymbolTable != nullptr)
|
||||
{
|
||||
return ParentSymbolTable->FindSymbol(symname, searchparents);
|
||||
}
|
||||
return value != nullptr ? *value : nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable)
|
||||
{
|
||||
PSymbol * const *value = Symbols.CheckKey(symname);
|
||||
if (value == nullptr)
|
||||
{
|
||||
if (ParentSymbolTable != nullptr)
|
||||
{
|
||||
return ParentSymbolTable->FindSymbolInTable(symname, symtable);
|
||||
}
|
||||
symtable = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
symtable = this;
|
||||
return *value;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PSymbol *PSymbolTable::AddSymbol (PSymbol *sym)
|
||||
{
|
||||
// Symbols that already exist are not inserted.
|
||||
if (Symbols.CheckKey(sym->SymbolName) != nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
Symbols.Insert(sym->SymbolName, sym);
|
||||
return sym;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PSymbolTable::RemoveSymbol(PSymbol *sym)
|
||||
{
|
||||
auto mysym = Symbols.CheckKey(sym->SymbolName);
|
||||
if (mysym == nullptr || *mysym != sym) return;
|
||||
Symbols.Remove(sym->SymbolName);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym)
|
||||
{
|
||||
// If a symbol with a matching name exists, take its place and return it.
|
||||
PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName);
|
||||
if (symslot != nullptr)
|
||||
{
|
||||
PSymbol *oldsym = *symslot;
|
||||
*symslot = newsym;
|
||||
return oldsym;
|
||||
}
|
||||
// Else, just insert normally and return nullptr since there was no
|
||||
// symbol to replace.
|
||||
Symbols.Insert(newsym->SymbolName, newsym);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PNamespace::PNamespace(int filenum, PNamespace *parent)
|
||||
{
|
||||
Parent = parent;
|
||||
if (parent) Symbols.SetParentTable(&parent->Symbols);
|
||||
FileNum = filenum;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
size_t PNamespace::PropagateMark()
|
||||
{
|
||||
GC::Mark(Parent);
|
||||
return Symbols.MarkSymbols() + 1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FNamespaceManager::FNamespaceManager()
|
||||
{
|
||||
GlobalNamespace = nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PNamespace *FNamespaceManager::NewNamespace(int filenum)
|
||||
{
|
||||
PNamespace *parent = nullptr;
|
||||
// The parent will be the last namespace with this or a lower filenum.
|
||||
// This ensures that DECORATE won't see the symbols of later files.
|
||||
for (int i = AllNamespaces.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (AllNamespaces[i]->FileNum <= filenum)
|
||||
{
|
||||
parent = AllNamespaces[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto newns = new PNamespace(filenum, parent);
|
||||
AllNamespaces.Push(newns);
|
||||
return newns;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
size_t FNamespaceManager::MarkSymbols()
|
||||
{
|
||||
for (auto ns : AllNamespaces)
|
||||
{
|
||||
GC::Mark(ns);
|
||||
}
|
||||
return AllNamespaces.Size();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FNamespaceManager::ReleaseSymbols()
|
||||
{
|
||||
GlobalNamespace = nullptr;
|
||||
AllNamespaces.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// removes all symbols from the symbol tables.
|
||||
// After running the compiler these are not needed anymore.
|
||||
// Only the namespaces themselves are kept because the type table references them.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FNamespaceManager::RemoveSymbols()
|
||||
{
|
||||
int count = 0;
|
||||
for (auto ns : AllNamespaces)
|
||||
{
|
||||
count += ns->Symbols.Symbols.CountUsed();
|
||||
ns->Symbols.ReleaseSymbols();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Clean out all compiler-only data from the symbol tables
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void RemoveUnusedSymbols()
|
||||
{
|
||||
// Global symbols are not needed anymore after running the compiler.
|
||||
int count = Namespaces.RemoveSymbols();
|
||||
|
||||
// We do not need any non-field and non-function symbols in structs and classes anymore.
|
||||
// struct/class fields and functions are still needed so that the game can access the script data,
|
||||
// but all the rest serves no purpose anymore and can be entirely removed.
|
||||
for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i)
|
||||
{
|
||||
for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext)
|
||||
{
|
||||
if (ty->IsKindOf(RUNTIME_CLASS(PStruct)))
|
||||
{
|
||||
auto it = ty->Symbols.GetIterator();
|
||||
PSymbolTable::MapType::Pair *pair;
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction)))
|
||||
{
|
||||
ty->Symbols.RemoveSymbol(pair->Value);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DPrintf(DMSG_SPAMMY, "%d symbols removed after compilation\n", count);
|
||||
}
|
286
src/scripting/symbols.h
Normal file
286
src/scripting/symbols.h
Normal file
|
@ -0,0 +1,286 @@
|
|||
// Note: This must not be included by anything but dobject.h!
|
||||
#pragma once
|
||||
|
||||
#ifndef __DOBJECT_H__
|
||||
#error You must #include "dobject.h" to get symbols.h
|
||||
#endif
|
||||
|
||||
|
||||
class VMFunction;
|
||||
class PType;
|
||||
class PPrototype;
|
||||
struct ZCC_TreeNode;
|
||||
class PStruct;
|
||||
|
||||
// Symbol information -------------------------------------------------------
|
||||
|
||||
class PTypeBase : public DObject
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(PTypeBase, DObject)
|
||||
|
||||
public:
|
||||
virtual FString QualifiedName() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
class PSymbol : public PTypeBase
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase);
|
||||
public:
|
||||
virtual ~PSymbol();
|
||||
|
||||
virtual FString QualifiedName() const
|
||||
{
|
||||
return SymbolName.GetChars();
|
||||
}
|
||||
|
||||
FName SymbolName;
|
||||
|
||||
protected:
|
||||
PSymbol(FName name) { SymbolName = name; }
|
||||
};
|
||||
|
||||
// A VM function ------------------------------------------------------------
|
||||
|
||||
class PSymbolVMFunction : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PSymbolVMFunction, PSymbol);
|
||||
public:
|
||||
VMFunction *Function;
|
||||
|
||||
PSymbolVMFunction(FName name) : PSymbol(name) {}
|
||||
PSymbolVMFunction() : PSymbol(NAME_None) {}
|
||||
};
|
||||
|
||||
// A symbol for a type ------------------------------------------------------
|
||||
|
||||
class PSymbolType : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PSymbolType, PSymbol);
|
||||
public:
|
||||
PType *Type;
|
||||
|
||||
PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {}
|
||||
PSymbolType() : PSymbol(NAME_None) {}
|
||||
};
|
||||
|
||||
// A symbol for a compiler tree node ----------------------------------------
|
||||
|
||||
class PSymbolTreeNode : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PSymbolTreeNode, PSymbol);
|
||||
public:
|
||||
struct ZCC_TreeNode *Node;
|
||||
|
||||
PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {}
|
||||
PSymbolTreeNode() : PSymbol(NAME_None) {}
|
||||
};
|
||||
|
||||
// Struct/class fields ------------------------------------------------------
|
||||
|
||||
// A PField describes a symbol that takes up physical space in the struct.
|
||||
class PField : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PField, PSymbol);
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
PField(FName name, PType *type, uint32_t flags = 0, size_t offset = 0, int bitvalue = 0);
|
||||
|
||||
size_t Offset;
|
||||
PType *Type;
|
||||
uint32_t Flags;
|
||||
int BitValue;
|
||||
protected:
|
||||
PField();
|
||||
};
|
||||
|
||||
// Properties ------------------------------------------------------
|
||||
|
||||
// For setting properties in class defaults.
|
||||
class PProperty : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PProperty, PSymbol);
|
||||
public:
|
||||
PProperty(FName name, TArray<PField *> &variables);
|
||||
|
||||
TArray<PField *> Variables;
|
||||
|
||||
protected:
|
||||
PProperty();
|
||||
};
|
||||
|
||||
class PPropFlag : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PPropFlag, PSymbol);
|
||||
public:
|
||||
PPropFlag(FName name, PField *offset, int bitval);
|
||||
|
||||
PField *Offset;
|
||||
int bitval;
|
||||
|
||||
protected:
|
||||
PPropFlag();
|
||||
};
|
||||
|
||||
// A constant value ---------------------------------------------------------
|
||||
|
||||
class PSymbolConst : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PSymbolConst, PSymbol);
|
||||
public:
|
||||
PType *ValueType;
|
||||
|
||||
PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {}
|
||||
PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {}
|
||||
};
|
||||
|
||||
// A constant numeric value -------------------------------------------------
|
||||
|
||||
class PSymbolConstNumeric : public PSymbolConst
|
||||
{
|
||||
DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst);
|
||||
public:
|
||||
union
|
||||
{
|
||||
int Value;
|
||||
double Float;
|
||||
void *Pad;
|
||||
};
|
||||
|
||||
PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {}
|
||||
PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {}
|
||||
PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {}
|
||||
PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {}
|
||||
PSymbolConstNumeric() {}
|
||||
};
|
||||
|
||||
// A constant string value --------------------------------------------------
|
||||
|
||||
class PSymbolConstString : public PSymbolConst
|
||||
{
|
||||
DECLARE_CLASS(PSymbolConstString, PSymbolConst);
|
||||
public:
|
||||
FString Str;
|
||||
|
||||
PSymbolConstString(FName name, const FString &str);
|
||||
PSymbolConstString() {}
|
||||
};
|
||||
|
||||
|
||||
// A function for the VM --------------------------------------------------
|
||||
|
||||
// TBD: Should we really support overloading?
|
||||
class PFunction : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PFunction, PSymbol);
|
||||
public:
|
||||
struct Variant
|
||||
{
|
||||
PPrototype *Proto;
|
||||
VMFunction *Implementation;
|
||||
TArray<uint32_t> ArgFlags; // Should be the same length as Proto->ArgumentTypes
|
||||
TArray<FName> ArgNames; // we need the names to access them later when the function gets compiled.
|
||||
uint32_t Flags;
|
||||
int UseFlags;
|
||||
PStruct *SelfClass;
|
||||
};
|
||||
TArray<Variant> Variants;
|
||||
PStruct *OwningClass = nullptr;
|
||||
|
||||
unsigned AddVariant(PPrototype *proto, TArray<uint32_t> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags, int useflags);
|
||||
int GetImplicitArgs();
|
||||
|
||||
PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {}
|
||||
};
|
||||
|
||||
// A symbol table -----------------------------------------------------------
|
||||
|
||||
struct PSymbolTable
|
||||
{
|
||||
PSymbolTable();
|
||||
PSymbolTable(PSymbolTable *parent);
|
||||
~PSymbolTable();
|
||||
|
||||
size_t MarkSymbols();
|
||||
|
||||
// Sets the table to use for searches if this one doesn't contain the
|
||||
// requested symbol.
|
||||
void SetParentTable (PSymbolTable *parent);
|
||||
PSymbolTable *GetParentTable() const
|
||||
{
|
||||
return ParentSymbolTable;
|
||||
}
|
||||
|
||||
// Finds a symbol in the table, optionally searching parent tables
|
||||
// as well.
|
||||
PSymbol *FindSymbol (FName symname, bool searchparents) const;
|
||||
|
||||
// Like FindSymbol with searchparents set true, but also returns the
|
||||
// specific symbol table the symbol was found in.
|
||||
PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable);
|
||||
|
||||
|
||||
// Places the symbol in the table and returns a pointer to it or NULL if
|
||||
// a symbol with the same name is already in the table. This symbol is
|
||||
// not copied and will be freed when the symbol table is destroyed.
|
||||
PSymbol *AddSymbol (PSymbol *sym);
|
||||
|
||||
// Similar to AddSymbol but always succeeds. Returns the symbol that used
|
||||
// to be in the table with this name, if any.
|
||||
PSymbol *ReplaceSymbol(PSymbol *sym);
|
||||
|
||||
void RemoveSymbol(PSymbol *sym);
|
||||
|
||||
// Frees all symbols from this table.
|
||||
void ReleaseSymbols();
|
||||
|
||||
typedef TMap<FName, PSymbol *> MapType;
|
||||
|
||||
MapType::Iterator GetIterator()
|
||||
{
|
||||
return MapType::Iterator(Symbols);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PSymbolTable *ParentSymbolTable;
|
||||
MapType Symbols;
|
||||
|
||||
friend class DObject;
|
||||
friend struct FNamespaceManager;
|
||||
};
|
||||
|
||||
// Namespaces --------------------------------------------------
|
||||
|
||||
class PNamespace : public PTypeBase
|
||||
{
|
||||
DECLARE_CLASS(PNamespace, PTypeBase)
|
||||
HAS_OBJECT_POINTERS;
|
||||
|
||||
public:
|
||||
PSymbolTable Symbols;
|
||||
PNamespace *Parent;
|
||||
int FileNum; // This is for blocking DECORATE access to later files.
|
||||
|
||||
PNamespace() {}
|
||||
PNamespace(int filenum, PNamespace *parent);
|
||||
size_t PropagateMark();
|
||||
};
|
||||
|
||||
struct FNamespaceManager
|
||||
{
|
||||
PNamespace *GlobalNamespace;
|
||||
TArray<PNamespace *> AllNamespaces;
|
||||
|
||||
FNamespaceManager();
|
||||
PNamespace *NewNamespace(int filenum);
|
||||
size_t MarkSymbols();
|
||||
void ReleaseSymbols();
|
||||
int RemoveSymbols();
|
||||
};
|
||||
|
||||
extern FNamespaceManager Namespaces;
|
||||
|
||||
|
Loading…
Reference in a new issue