mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 06:53:58 +00:00
- Some abstract syntax tree creation stuff. (Plus some tentative type creation stuff that made
me realize I would be better off creating a type-agnostic AST for the entire input instead of trying to tentatively create types before they're seen.) SVN r2354 (scripting)
This commit is contained in:
parent
50d126e78b
commit
c043627cc1
9 changed files with 1917 additions and 287 deletions
306
src/dobjtype.cpp
306
src/dobjtype.cpp
|
@ -211,7 +211,7 @@ PType::~PType()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PType::IsMatch(const void *id1, const void *id2) const
|
||||
bool PType::IsMatch(intptr_t id1, intptr_t id2) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ bool PType::IsMatch(const void *id1, const void *id2) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PType::GetTypeIDs(const void *&id1, const void *&id2) const
|
||||
void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
||||
{
|
||||
id1 = NULL;
|
||||
id2 = NULL;
|
||||
|
@ -313,7 +313,7 @@ END_POINTERS
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PNamedType::IsMatch(const void *id1, const void *id2) const
|
||||
bool PNamedType::IsMatch(intptr_t id1, intptr_t id2) const
|
||||
{
|
||||
const DObject *outer = (const DObject *)id1;
|
||||
FName name = (ENamedName)(intptr_t)id2;
|
||||
|
@ -327,10 +327,10 @@ bool PNamedType::IsMatch(const void *id1, const void *id2) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PNamedType::GetTypeIDs(const void *&id1, const void *&id2) const
|
||||
void PNamedType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
||||
{
|
||||
id1 = Outer;
|
||||
id2 = (void *)(intptr_t)TypeName;
|
||||
id1 = (intptr_t)Outer;
|
||||
id2 = TypeName;
|
||||
}
|
||||
|
||||
/* PInt *******************************************************************/
|
||||
|
@ -454,13 +454,37 @@ IMPLEMENT_POINTY_CLASS(PPointer)
|
|||
DECLARE_POINTER(PointedType)
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PPointer - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PPointer::PPointer()
|
||||
: PInt(sizeof(void *), true), PointedType(NULL)
|
||||
{
|
||||
Align = __alignof(void *);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PPointer - Parameterized Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PPointer::PPointer(PType *pointsat)
|
||||
: PInt(sizeof(void *), true), PointedType(pointsat)
|
||||
{
|
||||
Align = __alignof(void *);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PPointer :: IsMatch
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PPointer::IsMatch(const void *id1, const void *id2) const
|
||||
bool PPointer::IsMatch(intptr_t id1, intptr_t id2) const
|
||||
{
|
||||
assert(id2 == NULL);
|
||||
PType *pointat = (PType *)id1;
|
||||
|
@ -474,10 +498,10 @@ bool PPointer::IsMatch(const void *id1, const void *id2) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PPointer::GetTypeIDs(const void *&id1, const void *&id2) const
|
||||
void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
||||
{
|
||||
id1 = PointedType;
|
||||
id2 = NULL;
|
||||
id1 = (intptr_t)PointedType;
|
||||
id2 = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -487,13 +511,35 @@ IMPLEMENT_POINTY_CLASS(PClassPointer)
|
|||
DECLARE_POINTER(ClassRestriction)
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClassPointer - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PClassPointer::PClassPointer()
|
||||
: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClassPointer - Parameterized Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PClassPointer::PClassPointer(PClass *restrict)
|
||||
: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(restrict)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClassPointer :: IsMatch
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PClassPointer::IsMatch(const void *id1, const void *id2) const
|
||||
bool PClassPointer::IsMatch(intptr_t id1, intptr_t id2) const
|
||||
{
|
||||
const PType *pointat = (const PType *)id1;
|
||||
const PClass *classat = (const PClass *)id2;
|
||||
|
@ -508,11 +554,11 @@ bool PClassPointer::IsMatch(const void *id1, const void *id2) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClassPointer::GetTypeIDs(const void *&id1, const void *&id2) const
|
||||
void PClassPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
||||
{
|
||||
assert(PointedType == RUNTIME_CLASS(PClass));
|
||||
id1 = PointedType;
|
||||
id2 = ClassRestriction;
|
||||
id1 = (intptr_t)PointedType;
|
||||
id2 = (intptr_t)ClassRestriction;
|
||||
}
|
||||
|
||||
|
||||
|
@ -528,13 +574,37 @@ IMPLEMENT_POINTY_CLASS(PArray)
|
|||
DECLARE_POINTER(ElementType)
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PArray - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PArray::PArray()
|
||||
: ElementType(NULL), ElementCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PArray - Parameterized Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PArray::PArray(PType *etype, unsigned int ecount)
|
||||
: ElementType(etype), ElementCount(ecount)
|
||||
{
|
||||
Align = etype->Align;
|
||||
Size = etype->Size * ecount;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PArray :: IsMatch
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PArray::IsMatch(const void *id1, const void *id2) const
|
||||
bool PArray::IsMatch(intptr_t id1, intptr_t id2) const
|
||||
{
|
||||
const PType *elemtype = (const PType *)id1;
|
||||
unsigned int count = (unsigned int)(intptr_t)id2;
|
||||
|
@ -548,29 +618,120 @@ bool PArray::IsMatch(const void *id1, const void *id2) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PArray::GetTypeIDs(const void *&id1, const void *&id2) const
|
||||
void PArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
||||
{
|
||||
id1 = ElementType;
|
||||
id2 = (void *)(intptr_t)ElementCount;
|
||||
id1 = (intptr_t)ElementType;
|
||||
id2 = ElementCount;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NewArray
|
||||
//
|
||||
// Returns a PArray for the given type and size, making sure not to create
|
||||
// duplicates.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PArray *NewArray(PType *type, unsigned int count)
|
||||
{
|
||||
size_t bucket;
|
||||
PType *atype = TypeTable.FindType(RUNTIME_CLASS(PArray), (intptr_t)type, count, &bucket);
|
||||
if (atype == NULL)
|
||||
{
|
||||
atype = new PArray(type, count);
|
||||
TypeTable.AddType(type, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket);
|
||||
}
|
||||
return (PArray *)type;
|
||||
}
|
||||
|
||||
/* PVector ****************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PVector)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PVector - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PVector::PVector()
|
||||
: PArray(TypeFloat32, 3)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PVector - Parameterized Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PVector::PVector(unsigned int size)
|
||||
: PArray(TypeFloat32, size)
|
||||
{
|
||||
assert(size >= 2 && size <= 4);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NewVector
|
||||
//
|
||||
// Returns a PVector with the given dimension, making sure not to create
|
||||
// duplicates.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PVector *NewVector(unsigned int size)
|
||||
{
|
||||
size_t bucket;
|
||||
PType *type = TypeTable.FindType(RUNTIME_CLASS(PVector), (intptr_t)TypeFloat32, size, &bucket);
|
||||
if (type == NULL)
|
||||
{
|
||||
type = new PVector(size);
|
||||
TypeTable.AddType(type, RUNTIME_CLASS(PVector), (intptr_t)TypeFloat32, size, bucket);
|
||||
}
|
||||
return (PVector *)type;
|
||||
}
|
||||
|
||||
/* PDynArray **************************************************************/
|
||||
|
||||
IMPLEMENT_POINTY_CLASS(PDynArray)
|
||||
DECLARE_POINTER(ElementType)
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PDynArray - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PDynArray::PDynArray()
|
||||
: ElementType(NULL)
|
||||
{
|
||||
Size = sizeof(FArray);
|
||||
Align = __alignof(FArray);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PDynArray - Parameterized Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PDynArray::PDynArray(PType *etype)
|
||||
: ElementType(etype)
|
||||
{
|
||||
Size = sizeof(FArray);
|
||||
Align = __alignof(FArray);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PDynArray :: IsMatch
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PDynArray::IsMatch(const void *id1, const void *id2) const
|
||||
bool PDynArray::IsMatch(intptr_t id1, intptr_t id2) const
|
||||
{
|
||||
assert(id2 == NULL);
|
||||
const PType *elemtype = (const PType *)id1;
|
||||
|
@ -584,12 +745,32 @@ bool PDynArray::IsMatch(const void *id1, const void *id2) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PDynArray::GetTypeIDs(const void *&id1, const void *&id2) const
|
||||
void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
||||
{
|
||||
id1 = ElementType;
|
||||
id2 = NULL;
|
||||
id1 = (intptr_t)ElementType;
|
||||
id2 = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NewDynArray
|
||||
//
|
||||
// Creates a new DynArray of the given type, making sure not to create a
|
||||
// duplicate.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PDynArray *NewDynArray(PType *type)
|
||||
{
|
||||
size_t bucket;
|
||||
PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket);
|
||||
if (atype == NULL)
|
||||
{
|
||||
atype = new PDynArray(type);
|
||||
TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket);
|
||||
}
|
||||
return (PDynArray *)atype;
|
||||
}
|
||||
|
||||
/* PMap *******************************************************************/
|
||||
|
||||
|
@ -598,13 +779,39 @@ IMPLEMENT_POINTY_CLASS(PMap)
|
|||
DECLARE_POINTER(ValueType)
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PMap - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PMap::PMap()
|
||||
: KeyType(NULL), ValueType(NULL)
|
||||
{
|
||||
Size = sizeof(FMap);
|
||||
Align = __alignof(FMap);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PMap - Parameterized Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PMap::PMap(PType *keytype, PType *valtype)
|
||||
: KeyType(keytype), ValueType(valtype)
|
||||
{
|
||||
Size = sizeof(FMap);
|
||||
Align = __alignof(FMap);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PMap :: IsMatch
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PMap::IsMatch(const void *id1, const void *id2) const
|
||||
bool PMap::IsMatch(intptr_t id1, intptr_t id2) const
|
||||
{
|
||||
const PType *keyty = (const PType *)id1;
|
||||
const PType *valty = (const PType *)id2;
|
||||
|
@ -618,10 +825,31 @@ bool PMap::IsMatch(const void *id1, const void *id2) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PMap::GetTypeIDs(const void *&id1, const void *&id2) const
|
||||
void PMap::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
||||
{
|
||||
id1 = KeyType;
|
||||
id2 = ValueType;
|
||||
id1 = (intptr_t)KeyType;
|
||||
id2 = (intptr_t)ValueType;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NewMap
|
||||
//
|
||||
// Returns a PMap for the given key and value types, ensuring not to create
|
||||
// duplicates.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PMap *NewMap(PType *keytype, PType *valuetype)
|
||||
{
|
||||
size_t bucket;
|
||||
PType *maptype = TypeTable.FindType(RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, &bucket);
|
||||
if (maptype == NULL)
|
||||
{
|
||||
maptype = new PMap(keytype, valuetype);
|
||||
TypeTable.AddType(maptype, RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, bucket);
|
||||
}
|
||||
return (PMap *)maptype;
|
||||
}
|
||||
|
||||
/* PStruct ****************************************************************/
|
||||
|
@ -650,7 +878,7 @@ IMPLEMENT_CLASS(PPrototype)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PPrototype::IsMatch(const void *id1, const void *id2) const
|
||||
bool PPrototype::IsMatch(intptr_t id1, intptr_t id2) const
|
||||
{
|
||||
const TArray<PType *> *args = (const TArray<PType *> *)id1;
|
||||
const TArray<PType *> *rets = (const TArray<PType *> *)id2;
|
||||
|
@ -664,10 +892,10 @@ bool PPrototype::IsMatch(const void *id1, const void *id2) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PPrototype::GetTypeIDs(const void *&id1, const void *&id2) const
|
||||
void PPrototype::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
||||
{
|
||||
id1 = &ArgumentTypes;
|
||||
id2 = &ReturnTypes;
|
||||
id1 = (intptr_t)&ArgumentTypes;
|
||||
id2 = (intptr_t)&ReturnTypes;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -947,7 +1175,7 @@ void PClass::InsertIntoHash ()
|
|||
size_t bucket;
|
||||
PType *found;
|
||||
|
||||
found = TypeTable.FindType(RUNTIME_CLASS(PClass), Outer, (void*)(intptr_t)(int)TypeName, &bucket);
|
||||
found = TypeTable.FindType(RUNTIME_CLASS(PClass), (intptr_t)Outer, TypeName, &bucket);
|
||||
if (found != NULL)
|
||||
{ // This type has already been inserted
|
||||
// ... but there is no need whatsoever to make it a fatal error!
|
||||
|
@ -955,7 +1183,7 @@ void PClass::InsertIntoHash ()
|
|||
}
|
||||
else
|
||||
{
|
||||
TypeTable.AddType(this, RUNTIME_CLASS(PClass), Outer, (void*)(intptr_t)(int)TypeName, bucket);
|
||||
TypeTable.AddType(this, RUNTIME_CLASS(PClass), (intptr_t)Outer, TypeName, bucket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -974,7 +1202,7 @@ PClass *PClass::FindClass (FName zaname)
|
|||
return NULL;
|
||||
}
|
||||
return static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass),
|
||||
/*FIXME:Outer*/NULL, (void*)(intptr_t)(int)zaname, NULL));
|
||||
/*FIXME:Outer*/0, zaname, NULL));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1109,7 +1337,7 @@ PClass *PClass::FindClassTentative(FName name)
|
|||
size_t bucket;
|
||||
|
||||
PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass),
|
||||
/*FIXME:Outer*/NULL, (void*)(intptr_t)(int)name, &bucket);
|
||||
/*FIXME:Outer*/0, name, &bucket);
|
||||
|
||||
if (found != NULL)
|
||||
{
|
||||
|
@ -1122,7 +1350,7 @@ PClass *PClass::FindClassTentative(FName name)
|
|||
type->ParentClass = this;
|
||||
type->Size = -1;
|
||||
type->bRuntimeClass = true;
|
||||
TypeTable.AddType(type, RUNTIME_CLASS(PClass), type->Outer, (void*)(intptr_t)(int)name, bucket);
|
||||
TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -1226,7 +1454,7 @@ size_t PClass::PropagateMark()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
PType *FTypeTable::FindType(PClass *metatype, const void *parm1, const void *parm2, size_t *bucketnum)
|
||||
PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum)
|
||||
{
|
||||
size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE;
|
||||
if (bucketnum != NULL)
|
||||
|
@ -1249,7 +1477,7 @@ PType *FTypeTable::FindType(PClass *metatype, const void *parm1, const void *par
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FTypeTable::AddType(PType *type, PClass *metatype, const void *parm1, const void *parm2, size_t bucket)
|
||||
void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
size_t bucketcheck;
|
||||
|
@ -1271,7 +1499,7 @@ void FTypeTable::AddType(PType *type, PClass *metatype, const void *parm1, const
|
|||
void FTypeTable::AddType(PType *type)
|
||||
{
|
||||
PClass *metatype;
|
||||
const void *parm1, *parm2;
|
||||
intptr_t parm1, parm2;
|
||||
size_t bucket;
|
||||
|
||||
metatype = type->GetClass()->TypeTableType;
|
||||
|
@ -1290,7 +1518,7 @@ void FTypeTable::AddType(PType *type)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
size_t FTypeTable::Hash(const void *p1, const void *p2, const void *p3)
|
||||
size_t FTypeTable::Hash(const void *p1, intptr_t p2, intptr_t p3)
|
||||
{
|
||||
size_t i1 = (size_t)p1;
|
||||
size_t i2 = (size_t)p2;
|
||||
|
|
|
@ -193,10 +193,10 @@ public:
|
|||
// It is up to the caller to make sure they are the correct types. There is
|
||||
// only one prototype for this function in order to simplify type table
|
||||
// management.
|
||||
virtual bool IsMatch(const void *id1, const void *id2) const;
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
|
||||
// Get the type IDs used by IsMatch
|
||||
virtual void GetTypeIDs(const void *&id1, const void *&id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
||||
static void StaticInit();
|
||||
};
|
||||
|
@ -226,8 +226,8 @@ public:
|
|||
|
||||
PNamedType() : Outer(NULL) {}
|
||||
|
||||
virtual bool IsMatch(const void *id1, const void *id2) const;
|
||||
virtual void GetTypeIDs(const void *&id1, const void *&id2) const;
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
};
|
||||
|
||||
// Basic types --------------------------------------------------------------
|
||||
|
@ -289,10 +289,14 @@ class PPointer : public PInt
|
|||
DECLARE_CLASS(PPointer, PInt);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
PPointer(PType *pointsat);
|
||||
|
||||
PType *PointedType;
|
||||
|
||||
virtual bool IsMatch(const void *id1, const void *id2) const;
|
||||
virtual void GetTypeIDs(const void *&id1, const void *&id2) const;
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
protected:
|
||||
PPointer();
|
||||
};
|
||||
|
||||
class PClass;
|
||||
|
@ -301,12 +305,16 @@ class PClassPointer : public PPointer
|
|||
DECLARE_CLASS(PClassPointer, PPointer);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
PClassPointer(PClass *restrict);
|
||||
|
||||
PClass *ClassRestriction;
|
||||
|
||||
typedef PClass *Type2;
|
||||
|
||||
virtual bool IsMatch(const void *id1, const void *id2) const;
|
||||
virtual void GetTypeIDs(const void *&id1, const void *&id2) const;
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
protected:
|
||||
PClassPointer();
|
||||
};
|
||||
|
||||
// Struct/class fields ------------------------------------------------------
|
||||
|
@ -343,11 +351,15 @@ class PArray : public PCompoundType
|
|||
DECLARE_CLASS(PArray, PCompoundType);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
PArray(PType *etype, unsigned int ecount);
|
||||
|
||||
PType *ElementType;
|
||||
unsigned int ElementCount;
|
||||
|
||||
virtual bool IsMatch(const void *id1, const void *id2) const;
|
||||
virtual void GetTypeIDs(const void *&id1, const void *&id2) const;
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
protected:
|
||||
PArray();
|
||||
};
|
||||
|
||||
// A vector is an array with extra operations.
|
||||
|
@ -355,6 +367,10 @@ class PVector : public PArray
|
|||
{
|
||||
DECLARE_CLASS(PVector, PArray);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
PVector(unsigned int size);
|
||||
protected:
|
||||
PVector();
|
||||
};
|
||||
|
||||
class PDynArray : public PCompoundType
|
||||
|
@ -362,10 +378,14 @@ class PDynArray : public PCompoundType
|
|||
DECLARE_CLASS(PDynArray, PCompoundType);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
PDynArray(PType *etype);
|
||||
|
||||
PType *ElementType;
|
||||
|
||||
virtual bool IsMatch(const void *id1, const void *id2) const;
|
||||
virtual void GetTypeIDs(const void *&id1, const void *&id2) const;
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
protected:
|
||||
PDynArray();
|
||||
};
|
||||
|
||||
class PMap : public PCompoundType
|
||||
|
@ -373,11 +393,15 @@ class PMap : public PCompoundType
|
|||
DECLARE_CLASS(PMap, PCompoundType);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
PMap(PType *keytype, PType *valtype);
|
||||
|
||||
PType *KeyType;
|
||||
PType *ValueType;
|
||||
|
||||
virtual bool IsMatch(const void *id1, const void *id2) const;
|
||||
virtual void GetTypeIDs(const void *&id1, const void *&id2) const;
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
protected:
|
||||
PMap();
|
||||
};
|
||||
|
||||
class PStruct : public PNamedType
|
||||
|
@ -397,8 +421,8 @@ public:
|
|||
TArray<PType *> ReturnTypes;
|
||||
|
||||
size_t PropagateMark();
|
||||
virtual bool IsMatch(const void *id1, const void *id2) const;
|
||||
virtual void GetTypeIDs(const void *&id1, const void *&id2) const;
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
};
|
||||
|
||||
// TBD: Should we really support overloading?
|
||||
|
@ -517,6 +541,17 @@ inline PClass::MetaClass *PClass::GetClass() const
|
|||
return static_cast<MetaClass *>(DObject::GetClass());
|
||||
}
|
||||
|
||||
// A class that hasn't had its parent class defined yet ---------------------
|
||||
|
||||
class PClassWaitingForParent : public PClass
|
||||
{
|
||||
DECLARE_CLASS(PClassWaitingForParent, PClass);
|
||||
public:
|
||||
PClassWaitingForParent(FName myname, FName parentname);
|
||||
|
||||
FName ParentName;
|
||||
};
|
||||
|
||||
// Type tables --------------------------------------------------------------
|
||||
|
||||
struct FTypeTable
|
||||
|
@ -525,16 +560,36 @@ struct FTypeTable
|
|||
|
||||
PType *TypeHash[HASH_SIZE];
|
||||
|
||||
PType *FindType(PClass *metatype, const void *parm1, const void *parm2, size_t *bucketnum);
|
||||
void AddType(PType *type, PClass *metatype, const void *parm1, const void *parm2, size_t bucket);
|
||||
PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum);
|
||||
void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket);
|
||||
void AddType(PType *type);
|
||||
void Mark();
|
||||
void Clear();
|
||||
|
||||
static size_t Hash(const void *p1, const void *p2, const void *p3);
|
||||
static size_t Hash(const void *p1, intptr_t p2, intptr_t p3);
|
||||
};
|
||||
|
||||
|
||||
extern FTypeTable TypeTable;
|
||||
|
||||
// Returns a type from the TypeTable. Will create one if it isn't present.
|
||||
PVector *NewVector(unsigned int size);
|
||||
PMap *NewMap(PType *keytype, PType *valuetype);
|
||||
PArray *NewArray(PType *type, unsigned int count);
|
||||
PDynArray *NewDynArray(PType *type);
|
||||
PPointer *NewPointer(PType *type);
|
||||
PClassPointer *NewClassPointer(PClass *restrict);
|
||||
PClassWaitingForParent *NewUnknownClass(FName myname, FName parentname);
|
||||
|
||||
// Built-in types -----------------------------------------------------------
|
||||
|
||||
extern PInt *TypeSInt8, *TypeUInt8;
|
||||
extern PInt *TypeSInt16, *TypeUInt16;
|
||||
extern PInt *TypeSInt32, *TypeUInt32;
|
||||
extern PFloat *TypeFloat32, *TypeFloat64;
|
||||
extern PString *TypeString;
|
||||
extern PName *TypeName;
|
||||
extern PSound *TypeSound;
|
||||
extern PColor *TypeColor;
|
||||
|
||||
#endif
|
||||
|
|
360
src/memarena.cpp
Normal file
360
src/memarena.cpp
Normal file
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
** memarena.cpp
|
||||
** Implements memory arenas.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Randy Heit
|
||||
** 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.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
** A memory arena is used for efficient allocation of many small objects that
|
||||
** will all be freed at once. Note that since individual destructors are not
|
||||
** called, you must not use an arena to allocate any objects that use a
|
||||
** destructor, either explicitly or implicitly (because they have members
|
||||
** with destructors).
|
||||
*/
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "m_alloc.h"
|
||||
#include "memarena.h"
|
||||
#include "zstring.h"
|
||||
|
||||
#define BLOCK_SIZE (10*1024)
|
||||
|
||||
struct FMemArena::Block
|
||||
{
|
||||
Block *NextBlock;
|
||||
void *Limit; // End of this block
|
||||
void *Avail; // Start of free space in this block
|
||||
|
||||
void Reset();
|
||||
void *Alloc(size_t size);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// RoundPointer
|
||||
//
|
||||
// Rounds a pointer up to a pointer-sized boundary.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static inline void *RoundPointer(void *ptr)
|
||||
{
|
||||
return (void *)(((size_t)ptr + sizeof(void*) - 1) & ~(sizeof(void*) - 1));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FMemArena::FMemArena()
|
||||
{
|
||||
TopBlock = NULL;
|
||||
FreeBlocks = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena Destructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FMemArena::~FMemArena()
|
||||
{
|
||||
FreeAllBlocks();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: Alloc
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void *FMemArena::Alloc(size_t size)
|
||||
{
|
||||
Block *block;
|
||||
|
||||
for (block = TopBlock; block != NULL; block = block->NextBlock)
|
||||
{
|
||||
void *res = block->Alloc(size);
|
||||
if (res != NULL)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
block = AddBlock(size);
|
||||
return block->Alloc(size);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: FreeAll
|
||||
//
|
||||
// Moves all blocks to the free list. No system-level deallocation occurs.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::FreeAll()
|
||||
{
|
||||
for (Block *next, *block = TopBlock; block != NULL; block = next)
|
||||
{
|
||||
next = block->NextBlock;
|
||||
block->Reset();
|
||||
block->NextBlock = FreeBlocks;
|
||||
FreeBlocks = block;
|
||||
}
|
||||
TopBlock = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: FreeAllBlocks
|
||||
//
|
||||
// Frees all blocks used by this arena.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::FreeAllBlocks()
|
||||
{
|
||||
FreeBlockChain(TopBlock);
|
||||
FreeBlockChain(FreeBlocks);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: FreeBlockChain
|
||||
//
|
||||
// Frees a chain of blocks.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::FreeBlockChain(Block *&top)
|
||||
{
|
||||
for (Block *next, *block = top; block != NULL; block = next)
|
||||
{
|
||||
next = block->NextBlock;
|
||||
M_Free(block);
|
||||
}
|
||||
top = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: AddBlock
|
||||
//
|
||||
// Allocates a block large enough to hold at least <size> bytes and adds it
|
||||
// to the TopBlock chain.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FMemArena::Block *FMemArena::AddBlock(size_t size)
|
||||
{
|
||||
size += sizeof(Block); // Account for header size
|
||||
if (size < BLOCK_SIZE)
|
||||
{
|
||||
size = BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
{ // Stick some free space at the end so we can use this block for
|
||||
// other things.
|
||||
size += BLOCK_SIZE/2;
|
||||
}
|
||||
Block *mem = (Block *)M_Malloc(size);
|
||||
mem->Limit = mem + size;
|
||||
mem->Reset();
|
||||
mem->NextBlock = TopBlock;
|
||||
TopBlock = mem;
|
||||
return mem;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: Block :: Reset
|
||||
//
|
||||
// Resets this block's Avail pointer.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMemArena::Block::Reset()
|
||||
{
|
||||
Avail = RoundPointer(this + sizeof(*this));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMemArena :: Block :: Alloc
|
||||
//
|
||||
// Allocates memory from the block if it has space. Returns NULL if not.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void *FMemArena::Block::Alloc(size_t size)
|
||||
{
|
||||
if ((char *)Avail + size > Limit)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void *res = Avail;
|
||||
Avail = RoundPointer((char *)Avail + size);
|
||||
return res;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSharedStringArena::FSharedStringArena()
|
||||
{
|
||||
memset(Buckets, 0, sizeof(Buckets));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena Destructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSharedStringArena::~FSharedStringArena()
|
||||
{
|
||||
FreeAll();
|
||||
// FMemArena destructor will free the blocks.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: Alloc
|
||||
//
|
||||
// Allocates a new string and initializes it with the passed string. This
|
||||
// version takes an FString as a parameter, so it won't need to allocate any
|
||||
// memory for the string text if it already exists in the arena.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString *FSharedStringArena::Alloc(const FString &source)
|
||||
{
|
||||
unsigned int hash;
|
||||
Node *strnode;
|
||||
|
||||
strnode = FindString(source, source.Len(), hash);
|
||||
if (strnode == NULL)
|
||||
{
|
||||
strnode = (Node *)FMemArena::Alloc(sizeof(Node));
|
||||
::new(&strnode->String) FString(source);
|
||||
strnode->Hash = hash;
|
||||
hash %= countof(Buckets);
|
||||
strnode->Next = Buckets[hash];
|
||||
Buckets[hash] = strnode;
|
||||
}
|
||||
return &strnode->String;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: Alloc
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString *FSharedStringArena::Alloc(const char *source)
|
||||
{
|
||||
return Alloc(source, strlen(source));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: Alloc
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString *FSharedStringArena::Alloc(const char *source, size_t strlen)
|
||||
{
|
||||
unsigned int hash;
|
||||
Node *strnode;
|
||||
|
||||
strnode = FindString(source, strlen, hash);
|
||||
if (strnode == NULL)
|
||||
{
|
||||
strnode = (Node *)FMemArena::Alloc(sizeof(Node));
|
||||
::new(&strnode->String) FString(source, strlen);
|
||||
strnode->Hash = hash;
|
||||
hash %= countof(Buckets);
|
||||
strnode->Next = Buckets[hash];
|
||||
Buckets[hash] = strnode;
|
||||
}
|
||||
return &strnode->String;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: FindString
|
||||
//
|
||||
// Finds the string if it's already in the arena. Returns NULL if not.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSharedStringArena::Node *FSharedStringArena::FindString(const char *str, size_t strlen, unsigned int &hash)
|
||||
{
|
||||
hash = SuperFastHash(str, strlen);
|
||||
|
||||
for (Node *node = Buckets[hash % countof(Buckets)]; node != NULL; node = node->Next)
|
||||
{
|
||||
if (node->Hash == hash && node->String.Len() == strlen && memcmp(&node->String[0], str, strlen) == 0)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FSharedStringArena :: FreeAll
|
||||
//
|
||||
// In addition to moving all used blocks onto the free list, all FStrings
|
||||
// they contain will have their destructors called.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FSharedStringArena::FreeAll()
|
||||
{
|
||||
for (Block *next, *block = TopBlock; block != NULL; block = next)
|
||||
{
|
||||
next = block->NextBlock;
|
||||
void *limit = block->Avail;
|
||||
block->Reset();
|
||||
for (Node *string = (Node *)block->Avail; string < limit; ++string)
|
||||
{
|
||||
string->~Node();
|
||||
}
|
||||
block->NextBlock = FreeBlocks;
|
||||
FreeBlocks = block;
|
||||
}
|
||||
memset(Buckets, 0, sizeof(Buckets));
|
||||
}
|
83
src/memarena.h
Normal file
83
src/memarena.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
** memarena.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Randy Heit
|
||||
** 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 "zstring.h"
|
||||
|
||||
// A general purpose arena.
|
||||
class FMemArena
|
||||
{
|
||||
public:
|
||||
FMemArena();
|
||||
~FMemArena();
|
||||
|
||||
void *Alloc(size_t size);
|
||||
void FreeAll();
|
||||
void FreeAllBlocks();
|
||||
|
||||
protected:
|
||||
struct Block;
|
||||
|
||||
Block *AddBlock(size_t size);
|
||||
void FreeBlockChain(Block *&top);
|
||||
|
||||
Block *TopBlock;
|
||||
Block *FreeBlocks;
|
||||
};
|
||||
|
||||
// An arena specializing in storage of FStrings. It knows how to free them,
|
||||
// but this means it also should never be used for allocating anything else.
|
||||
// Identical strings all return the same pointer.
|
||||
class FSharedStringArena : public FMemArena
|
||||
{
|
||||
public:
|
||||
FSharedStringArena();
|
||||
~FSharedStringArena();
|
||||
void FreeAll();
|
||||
|
||||
class FString *Alloc(const FString &source);
|
||||
class FString *Alloc(const char *source);
|
||||
class FString *Alloc(const char *source, size_t strlen);
|
||||
|
||||
protected:
|
||||
struct Node
|
||||
{
|
||||
Node *Next;
|
||||
FString String;
|
||||
unsigned int Hash;
|
||||
};
|
||||
Node *Buckets[256];
|
||||
|
||||
Node *FindString(const char *str, size_t strlen, unsigned int &hash);
|
||||
private:
|
||||
void *Alloc(size_t size) { return NULL; } // No access to FMemArena::Alloc for outsiders.
|
||||
};
|
17
src/tarray.h
17
src/tarray.h
|
@ -51,6 +51,14 @@ class FArchive;
|
|||
|
||||
// TArray -------------------------------------------------------------------
|
||||
|
||||
// Must match TArray's layout.
|
||||
struct FArray
|
||||
{
|
||||
void *Array;
|
||||
unsigned int Most;
|
||||
unsigned int Count;
|
||||
};
|
||||
|
||||
// T is the type stored in the array.
|
||||
// TT is the type returned by operator().
|
||||
template <class T, class TT=T>
|
||||
|
@ -444,6 +452,15 @@ template<class VT> struct TValueTraits
|
|||
}
|
||||
};
|
||||
|
||||
// Must match layout of TMap
|
||||
struct FMap
|
||||
{
|
||||
void *Nodes;
|
||||
void *LastFree;
|
||||
hash_t Size;
|
||||
hash_t NumUsed;
|
||||
};
|
||||
|
||||
template<class KT, class VT, class MapType> class TMapIterator;
|
||||
template<class KT, class VT, class MapType> class TMapConstIterator;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,83 +5,8 @@
|
|||
#include "w_wad.h"
|
||||
#include "cmdlib.h"
|
||||
#include "m_alloc.h"
|
||||
|
||||
class ZCCParser
|
||||
{
|
||||
public:
|
||||
void PrintError(const char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
VPrintf(PRINT_HIGH, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
};
|
||||
|
||||
union ZCCToken
|
||||
{
|
||||
int Int;
|
||||
double Float;
|
||||
const char *String;
|
||||
};
|
||||
|
||||
class StringTable
|
||||
{
|
||||
public:
|
||||
StringTable()
|
||||
{
|
||||
memset(Buckets, 0, sizeof(Buckets));
|
||||
}
|
||||
~StringTable()
|
||||
{
|
||||
for (size_t i = 0; i < countof(Buckets); ++i)
|
||||
{
|
||||
Node *node, *next;
|
||||
for (node = Buckets[i]; node != NULL; node = next)
|
||||
{
|
||||
if (node->String != NULL)
|
||||
{
|
||||
delete[] node->String;
|
||||
}
|
||||
next = node->Next;
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
}
|
||||
const char *Get(const char *str, int len)
|
||||
{
|
||||
unsigned int hash = SuperFastHash(str, len);
|
||||
Node *node, **nodep;
|
||||
|
||||
nodep = &Buckets[hash % countof(Buckets)];
|
||||
node = *nodep;
|
||||
// Search for string in the hash table.
|
||||
while (node != NULL)
|
||||
{
|
||||
if (node->Hash == hash && strcmp(str, node->String))
|
||||
{
|
||||
return node->String;
|
||||
}
|
||||
nodep = &node->Next;
|
||||
node = *nodep;
|
||||
}
|
||||
// String is not in the hash table; add it.
|
||||
node = new Node;
|
||||
*nodep = node;
|
||||
node->Hash = hash;
|
||||
node->String = copystring(str);
|
||||
node->Next = NULL;
|
||||
return node->String;
|
||||
}
|
||||
private:
|
||||
struct Node
|
||||
{
|
||||
Node *Next;
|
||||
const char *String;
|
||||
unsigned int Hash;
|
||||
};
|
||||
Node *Buckets[256];
|
||||
};
|
||||
#include "memarena.h"
|
||||
#include "zcc_parser.h"
|
||||
|
||||
static FString ZCCTokenName(int terminal);
|
||||
|
||||
|
@ -217,7 +142,6 @@ static void DoParse(const char *filename)
|
|||
}
|
||||
|
||||
FScanner sc;
|
||||
StringTable strings;
|
||||
void *parser;
|
||||
int tokentype;
|
||||
int lump;
|
||||
|
@ -245,11 +169,13 @@ static void DoParse(const char *filename)
|
|||
FILE *f = fopen("trace.txt", "w");
|
||||
ZCCParseTrace(f, "");
|
||||
#endif
|
||||
ZCCParseState state(sc);
|
||||
|
||||
while (sc.GetToken())
|
||||
{
|
||||
if (sc.TokenType == TK_StringConst)
|
||||
{
|
||||
value.String = strings.Get(sc.String, sc.StringLen);
|
||||
value.String = state.Strings.Alloc(sc.String, sc.StringLen);
|
||||
tokentype = ZCC_STRCONST;
|
||||
}
|
||||
else if (sc.TokenType == TK_IntConst)
|
||||
|
@ -285,7 +211,7 @@ static void DoParse(const char *filename)
|
|||
break;
|
||||
}
|
||||
}
|
||||
ZCCParse(parser, tokentype, value, &sc);
|
||||
ZCCParse(parser, tokentype, value, &state);
|
||||
if (failed)
|
||||
{
|
||||
sc.ScriptMessage("Parse failed\n");
|
||||
|
@ -293,8 +219,8 @@ static void DoParse(const char *filename)
|
|||
}
|
||||
}
|
||||
value.Int = -1;
|
||||
ZCCParse(parser, ZCC_EOF, value, &sc);
|
||||
ZCCParse(parser, 0, value, &sc);
|
||||
ZCCParse(parser, ZCC_EOF, value, &state);
|
||||
ZCCParse(parser, 0, value, &state);
|
||||
ZCCParseFree(parser, free);
|
||||
#ifdef _DEBUG
|
||||
if (f != NULL)
|
||||
|
|
373
src/zscript/zcc_parser.h
Normal file
373
src/zscript/zcc_parser.h
Normal file
|
@ -0,0 +1,373 @@
|
|||
struct ZCCParseState
|
||||
{
|
||||
ZCCParseState(FScanner &scanner) : sc(scanner)
|
||||
{
|
||||
}
|
||||
|
||||
FScanner ≻
|
||||
FSharedStringArena Strings;
|
||||
FMemArena SyntaxArena;
|
||||
};
|
||||
|
||||
union ZCCToken
|
||||
{
|
||||
int Int;
|
||||
double Float;
|
||||
FString *String;
|
||||
};
|
||||
|
||||
// Syntax tree structures.
|
||||
enum EZCCTreeNodeType
|
||||
{
|
||||
AST_Class,
|
||||
AST_Struct,
|
||||
AST_Enum,
|
||||
AST_EnumNode,
|
||||
AST_States,
|
||||
AST_StateLabel,
|
||||
AST_StateGoto,
|
||||
AST_StateLine,
|
||||
AST_VarName,
|
||||
AST_Type,
|
||||
AST_BasicType,
|
||||
AST_MapType,
|
||||
AST_DynArrayType,
|
||||
AST_ClassType,
|
||||
AST_Expression,
|
||||
AST_ExprID,
|
||||
AST_ExprString,
|
||||
AST_ExprInt,
|
||||
AST_ExprFloat,
|
||||
AST_ExprFuncCall,
|
||||
AST_ExprMemberAccess,
|
||||
AST_ExprUnary,
|
||||
AST_ExprBinary,
|
||||
AST_ExprTrinary,
|
||||
AST_FuncParm,
|
||||
AST_Statement,
|
||||
AST_CompoundStmt,
|
||||
AST_ContinueStmt,
|
||||
AST_BreakStmt,
|
||||
AST_ReturnStmt,
|
||||
AST_ExpressionStmt,
|
||||
AST_IterationStmt,
|
||||
AST_IfStmt,
|
||||
AST_SwitchStmt,
|
||||
AST_CaseStmt,
|
||||
AST_AssignStmt,
|
||||
AST_LocalVarStmt,
|
||||
};
|
||||
|
||||
|
||||
enum EZCCExprType
|
||||
{
|
||||
PEX_ID,
|
||||
PEX_Super,
|
||||
PEX_Self,
|
||||
PEX_StringConst,
|
||||
PEX_IntConst,
|
||||
PEX_UIntConst,
|
||||
PEX_FloatConst,
|
||||
PEX_FuncCall,
|
||||
PEX_ArrayAccess,
|
||||
PEX_MemberAccess,
|
||||
PEX_PostInc,
|
||||
PEX_PostDec,
|
||||
|
||||
PEX_PreInc,
|
||||
PEX_PreDec,
|
||||
PEX_Negate,
|
||||
PEX_AntiNegate,
|
||||
PEX_BitNot,
|
||||
PEX_BoolNot,
|
||||
PEX_SizeOf,
|
||||
PEX_AlignOf,
|
||||
|
||||
PEX_Add,
|
||||
PEX_Sub,
|
||||
PEX_Mul,
|
||||
PEX_Div,
|
||||
PEX_Mod,
|
||||
PEX_Pow,
|
||||
PEX_CrossProduct,
|
||||
PEX_DotProduct,
|
||||
PEX_LeftShift,
|
||||
PEX_RightShift,
|
||||
PEX_Concat,
|
||||
|
||||
PEX_LT,
|
||||
PEX_GT,
|
||||
PEX_LTEQ,
|
||||
PEX_GTEQ,
|
||||
PEX_LTGTEQ,
|
||||
PEX_Is,
|
||||
|
||||
PEX_EQEQ,
|
||||
PEX_NEQ,
|
||||
PEX_APREQ,
|
||||
|
||||
PEX_BitAnd,
|
||||
PEX_BitOr,
|
||||
PEX_BitXor,
|
||||
PEX_BoolAnd,
|
||||
PEX_BoolOr,
|
||||
|
||||
PEX_Scope,
|
||||
|
||||
PEX_Trinary
|
||||
};
|
||||
|
||||
struct ZCC_TreeNode
|
||||
{
|
||||
// This tree node's siblings are stored in a circular linked list.
|
||||
// When you get back to this node, you know you've been through
|
||||
// the whole list.
|
||||
ZCC_TreeNode *SiblingNext;
|
||||
ZCC_TreeNode *SiblingPrev;
|
||||
|
||||
// Node type is one of the node types above, which corresponds with
|
||||
// one of the structures below.
|
||||
EZCCTreeNodeType NodeType;
|
||||
|
||||
// Appends a sibling to this node's sibling list.
|
||||
void AppendSibling(ZCC_TreeNode *sibling)
|
||||
{
|
||||
if (sibling == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// The new sibling node should only be in a list with itself.
|
||||
assert(sibling->SiblingNext == sibling && sibling->SiblingNext == sibling);
|
||||
|
||||
// Check integrity of our sibling list.
|
||||
assert(SiblingPrev->SiblingNext == this);
|
||||
assert(SiblingNext->SiblingPrev == this);
|
||||
|
||||
SiblingPrev->SiblingNext = sibling;
|
||||
sibling->SiblingPrev = SiblingPrev;
|
||||
SiblingPrev = sibling;
|
||||
sibling->SiblingNext = this;
|
||||
}
|
||||
};
|
||||
|
||||
struct ZCC_Class : ZCC_TreeNode
|
||||
{
|
||||
FName ClassName;
|
||||
FName ParentName;
|
||||
VM_UWORD Flags;
|
||||
ZCC_TreeNode *Body;
|
||||
};
|
||||
|
||||
struct ZCC_Struct : ZCC_TreeNode
|
||||
{
|
||||
FName StructName;
|
||||
ZCC_TreeNode *Body;
|
||||
};
|
||||
|
||||
struct ZCC_Enum : ZCC_TreeNode
|
||||
{
|
||||
FName EnumName;
|
||||
struct ZCC_EnumNode *Elements;
|
||||
};
|
||||
|
||||
struct ZCC_EnumNode : ZCC_TreeNode
|
||||
{
|
||||
FName ElemName;
|
||||
ZCC_TreeNode *ElemValue;
|
||||
};
|
||||
|
||||
struct ZCC_States : ZCC_TreeNode
|
||||
{
|
||||
ZCC_TreeNode *Body;
|
||||
};
|
||||
|
||||
struct ZCC_StateLabel : ZCC_TreeNode
|
||||
{
|
||||
FName Label;
|
||||
};
|
||||
|
||||
struct ZCC_StateGoto : ZCC_TreeNode
|
||||
{
|
||||
ZCC_TreeNode *Label;
|
||||
ZCC_TreeNode *Offset;
|
||||
};
|
||||
|
||||
struct ZCC_StateLine : ZCC_TreeNode
|
||||
{
|
||||
char Sprite[4];
|
||||
FString *Frames;
|
||||
BITFIELD bBright:1;
|
||||
BITFIELD bHasOffset:1;
|
||||
int OffsetX;
|
||||
int OffsetY;
|
||||
ZCC_TreeNode *Action;
|
||||
};
|
||||
|
||||
struct ZCC_Expression : ZCC_TreeNode
|
||||
{
|
||||
EZCCExprType Operation;
|
||||
};
|
||||
|
||||
struct ZCC_VarName : ZCC_TreeNode
|
||||
{
|
||||
bool bIsArray;
|
||||
ZCC_Expression *ArraySize;
|
||||
ENamedName Name;
|
||||
};
|
||||
|
||||
struct ZCC_Type : ZCC_TreeNode
|
||||
{
|
||||
BITFIELD bIsArray:1;
|
||||
ZCC_Expression *ArraySize;
|
||||
};
|
||||
|
||||
struct ZCC_BasicType : ZCC_Type
|
||||
{
|
||||
PType *Type;
|
||||
FName TypeName;
|
||||
};
|
||||
|
||||
struct ZCC_MapType : ZCC_Type
|
||||
{
|
||||
ZCC_Type *KeyType;
|
||||
ZCC_Type *ValueType;
|
||||
};
|
||||
|
||||
struct ZCC_DynArrayType : ZCC_Type
|
||||
{
|
||||
ZCC_Type *ElementType;
|
||||
};
|
||||
|
||||
struct ZCC_ClassType : ZCC_Type
|
||||
{
|
||||
FName Restriction;
|
||||
};
|
||||
|
||||
struct ZCC_ExprID : ZCC_Expression
|
||||
{
|
||||
FName Identifier;
|
||||
};
|
||||
|
||||
struct ZCC_ExprString : ZCC_Expression
|
||||
{
|
||||
FString *Value;
|
||||
};
|
||||
|
||||
struct ZCC_ExprInt : ZCC_Expression
|
||||
{
|
||||
int Value;
|
||||
};
|
||||
|
||||
struct ZCC_ExprFloat : ZCC_Expression
|
||||
{
|
||||
double Value;
|
||||
};
|
||||
|
||||
struct ZCC_FuncParm : ZCC_TreeNode
|
||||
{
|
||||
ZCC_Expression *Value;
|
||||
FName Label;
|
||||
};
|
||||
|
||||
struct ZCC_ExprFuncCall : ZCC_Expression
|
||||
{
|
||||
ZCC_Expression *Function;
|
||||
ZCC_FuncParm *Parameters;
|
||||
};
|
||||
|
||||
struct ZCC_ExprMemberAccess : ZCC_Expression
|
||||
{
|
||||
ZCC_Expression *Left;
|
||||
FName Right;
|
||||
};
|
||||
|
||||
struct ZCC_ExprUnary : ZCC_Expression
|
||||
{
|
||||
ZCC_Expression *Operand;
|
||||
};
|
||||
|
||||
struct ZCC_ExprBinary : ZCC_Expression
|
||||
{
|
||||
ZCC_Expression *Left;
|
||||
ZCC_Expression *Right;
|
||||
};
|
||||
|
||||
struct ZCC_ExprTrinary : ZCC_Expression
|
||||
{
|
||||
ZCC_Expression *Test;
|
||||
ZCC_Expression *Left;
|
||||
ZCC_Expression *Right;
|
||||
};
|
||||
|
||||
struct ZCC_Statement : ZCC_TreeNode
|
||||
{
|
||||
};
|
||||
|
||||
struct ZCC_CompoundStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Statement *Content;
|
||||
};
|
||||
|
||||
struct ZCC_ContinueStmt : ZCC_Statement
|
||||
{
|
||||
};
|
||||
|
||||
struct ZCC_BreakStmt : ZCC_Statement
|
||||
{
|
||||
};
|
||||
|
||||
struct ZCC_ReturnStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Expression *Values;
|
||||
};
|
||||
|
||||
struct ZCC_ExpressionStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Expression *Expression;
|
||||
};
|
||||
|
||||
struct ZCC_IterationStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Expression *LoopCondition;
|
||||
ZCC_Statement *LoopStatement;
|
||||
ZCC_Statement *LoopBumper;
|
||||
|
||||
// Should the loop condition be checked at the
|
||||
// start of the loop (before the LoopStatement)
|
||||
// or at the end (after the LoopStatement)?
|
||||
enum { Start, End } CheckAt;
|
||||
};
|
||||
|
||||
struct ZCC_IfStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Expression *Condition;
|
||||
ZCC_Statement *TruePath;
|
||||
ZCC_Statement *FalsePath;
|
||||
};
|
||||
|
||||
struct ZCC_SwitchStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Expression *Condition;
|
||||
ZCC_Statement *Content;
|
||||
};
|
||||
|
||||
struct ZCC_CaseStmt : ZCC_Statement
|
||||
{
|
||||
// A NULL Condition represents the default branch
|
||||
ZCC_Expression *Condition;
|
||||
};
|
||||
|
||||
struct ZCC_AssignStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Expression *Dests;
|
||||
ZCC_Expression *Sources;
|
||||
int AssignOp;
|
||||
};
|
||||
|
||||
struct ZCC_LocalVarStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Type *Type;
|
||||
ZCC_VarName *Vars;
|
||||
ZCC_Expression *Inits;
|
||||
};
|
12
zdoom.vcproj
12
zdoom.vcproj
|
@ -712,6 +712,10 @@
|
|||
RelativePath=".\src\md5.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\memarena.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\mus2midi.cpp"
|
||||
>
|
||||
|
@ -1401,6 +1405,10 @@
|
|||
RelativePath=".\src\md5.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\memarena.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\mscinlines.h"
|
||||
>
|
||||
|
@ -6553,6 +6561,10 @@
|
|||
RelativePath=".\src\zscript\zcc_parser.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\zscript\zcc_parser.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
|
|
Loading…
Reference in a new issue