- 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:
Randy Heit 2010-06-06 04:15:28 +00:00
parent 50d126e78b
commit c043627cc1
9 changed files with 1917 additions and 287 deletions

View File

@ -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;

View File

@ -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
View 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
View 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.
};

View File

@ -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

View File

@ -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
View File

@ -0,0 +1,373 @@
struct ZCCParseState
{
ZCCParseState(FScanner &scanner) : sc(scanner)
{
}
FScanner &sc;
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;
};

View File

@ -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>