diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index d757aff7c..950e9bd7f 100644 --- a/src/dobjtype.cpp +++ b/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 *args = (const TArray *)id1; const TArray *rets = (const TArray *)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(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; diff --git a/src/dobjtype.h b/src/dobjtype.h index bdcff573d..a3b41e12d 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -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 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(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 diff --git a/src/memarena.cpp b/src/memarena.cpp new file mode 100644 index 000000000..569b9f8f9 --- /dev/null +++ b/src/memarena.cpp @@ -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 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)); +} diff --git a/src/memarena.h b/src/memarena.h new file mode 100644 index 000000000..e933fc072 --- /dev/null +++ b/src/memarena.h @@ -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. +}; diff --git a/src/tarray.h b/src/tarray.h index cced36e4b..cf8aa1dd0 100644 --- a/src/tarray.h +++ b/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 @@ -444,6 +452,15 @@ template struct TValueTraits } }; +// Must match layout of TMap +struct FMap +{ + void *Nodes; + void *LastFree; + hash_t Size; + hash_t NumUsed; +}; + template class TMapIterator; template class TMapConstIterator; diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index d699f37da..45ee171fa 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -1,8 +1,17 @@ +%include +{ +#define NEW_AST_NODE(type,name) \ + ZCC_##type *name = (ZCC_##type *)stat->SyntaxArena.Alloc(sizeof(ZCC_##type)); \ + name->SiblingNext = name; \ + name->SiblingPrev = name; \ + name->NodeType = AST_##type +} + %token_prefix ZCC_ %token_type { ZCCToken } %token_destructor {} // just to avoid a compiler warning %name ZCCParse -%extra_argument { FScanner *sc } +%extra_argument { ZCCParseState *stat } %syntax_error { FString unexpected, expecting; @@ -27,9 +36,9 @@ } } } - sc->ScriptMessage("%s\n%s\n", unexpected.GetChars(), expecting.GetChars()); + stat->sc.ScriptMessage("%s\n%s\n", unexpected.GetChars(), expecting.GetChars()); } -%parse_accept { sc->ScriptMessage("input accepted\n"); } +%parse_accept { stat->sc.ScriptMessage("input accepted\n"); } %parse_failure { /**failed = true;*/ } %nonassoc EQ MULEQ DIVEQ MODEQ ADDEQ SUBEQ LSHEQ RSHEQ ANDEQ OREQ XOREQ. @@ -51,7 +60,7 @@ %left SCOPE. -main ::= translation_unit. { sc->ScriptMessage("Parse complete\n"); } +main ::= translation_unit. { stat->sc.ScriptMessage("Parse complete\n"); } translation_unit ::= . translation_unit ::= translation_unit external_declaration. @@ -67,23 +76,33 @@ opt_semicolon ::= SEMICOLON. opt_comma ::= . opt_comma ::= COMMA. -opt_expr ::= . -opt_expr ::= expr. +%type opt_expr{ZCC_Expression *} +opt_expr(X) ::= . +{ + X = NULL; +} +opt_expr(X) ::= expr(A). +{ + X = A; +} /* A class definition. Can only occur at global scope. */ -class_definition ::= CLASS id_or_string class_ancestry class_flags class_body. +class_definition ::= class_start class_body. +{ +/* stat->CurrClass = NULL;*/ +} -id_or_string ::= IDENTIFIER. -id_or_string ::= string_constant. +class_start ::= CLASS IDENTIFIER class_ancestry class_flags. -class_ancestry ::= . -class_ancestry ::= COLON id_or_string. +%type class_ancestry {ENamedName} +class_ancestry(X) ::= . { X = NAME_Object; } +class_ancestry(X) ::= COLON IDENTIFIER(A). { X = ENamedName(A.Int); } class_flags ::= . class_flags ::= class_flags ABSTRACT. class_flags ::= class_flags NATIVE. -class_flags ::= class_flags REPLACES id_or_string. +class_flags ::= class_flags REPLACES IDENTIFIER. class_body ::= SEMICOLON class_innards EOF. @@ -131,16 +150,17 @@ states_def ::= STATES scanner_mode LBRACE states_body RBRACE. * set immediately after LBRACE is consumed, rather than immediately after * STATES is consumed. */ -scanner_mode ::= . { sc->SetStateMode(true); } +scanner_mode ::= . { stat->sc.SetStateMode(true); } states_body ::= . states_body ::= error. -states_body ::= states_body LABELID. +/*states_body ::= states_body LABELID.*/ states_body ::= states_body state_line. states_body ::= states_body state_label. states_body ::= states_body state_flow. -state_label ::= NWS COLON. +state_label ::= NWS(A) COLON. +{ Printf("Label %s\n", FName(ENamedName(A.Int)).GetChars()); } state_flow ::= state_flow_type scanner_mode SEMICOLON. state_flow_type ::= STOP. @@ -152,7 +172,8 @@ state_flow_type ::= GOTO dotted_identifier state_goto_offset. state_goto_offset ::= . state_goto_offset ::= PLUS expr. /* Must evaluate to an integer constant. */ -state_line ::= NWS NWS expr state_opts state_action. +state_line ::= NWS(A) NWS(B) expr state_opts state_action. +{ Printf("Sprite %s Frames %s\n", FName(ENamedName(A.Int)).GetChars(), FName(ENamedName(B.Int)).GetChars()); } state_opts ::= . state_opts ::= state_opts BRIGHT. @@ -180,24 +201,33 @@ dotted_identifier ::= dotted_identifier DOT IDENTIFIER. default_def ::= DEFAULT compound_statement. /* Type names */ -int_type ::= SBYTE. -int_type ::= BYTE. -int_type ::= SHORT. -int_type ::= USHORT. -int_type ::= INT. -int_type ::= UINT. +%type int_type {PType *} +%type type_name {PType *} -type_name ::= BOOL. -type_name ::= int_type. -type_name ::= FLOAT. -type_name ::= DOUBLE. -type_name ::= STRING. -type_name ::= VECTOR vector_size. -type_name ::= NAME. -type_name ::= IDENTIFIER. /* User-defined type (struct, enum, or class) */ +int_type(X) ::= SBYTE. { X = TypeSInt8; } +int_type(X) ::= BYTE. { X = TypeUInt8; } +int_type(X) ::= SHORT. { X = TypeSInt16; } +int_type(X) ::= USHORT. { X = TypeUInt16; } +int_type(X) ::= INT. { X = TypeSInt32; } +int_type(X) ::= UINT. { X = TypeUInt32; } + +type_name(X) ::= BOOL. { /*FIXME*/ X = TypeBool; } +type_name(X) ::= int_type(A). { X = A; } +type_name(X) ::= FLOAT. { X = TypeFloat32; } +type_name(X) ::= DOUBLE. { X = TypeFloat64; } +type_name(X) ::= STRING. { X = TypeString; } +type_name(X) ::= VECTOR vector_size(A). { X = NewVector(A); } +type_name(X) ::= NAME. { X = TypeName; } +type_name(X) ::= IDENTIFIER. /* User-defined type (struct, enum, or class) */ +{ + // FIXME + X = NULL; +} + +%type vector_size {unsigned int} vector_size ::= . -vector_size ::= LT INTCONST GT. +vector_size(X) ::= LT INTCONST(A) GT. { X = A.Int; } /* Type names can also be used as identifiers in contexts where type names * are not normally allowed. */ @@ -205,23 +235,56 @@ vector_size ::= LT INTCONST GT. SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR NAME. /* Aggregate types */ -aggregate_type ::= MAP LT type array_size COMMA type array_size GT. /* Hash table */ -aggregate_type ::= ARRAY LT type array_size GT. /* TArray */ -aggregate_type ::= CLASS class_restrictor. /* class */ +%type aggregate_type {PType *} +%type type {PType *} +%type type_or_array {PType *} +%type class_restrictor {PClass *} + +aggregate_type ::= MAP LT type_or_array COMMA type_or_array GT. /* Hash table */ +aggregate_type ::= ARRAY LT type_or_array GT. /* TArray */ +aggregate_type ::= CLASS class_restrictor. /* class */ + class_restrictor ::= . class_restrictor ::= LT IDENTIFIER GT. -type ::= type_name. -type ::= aggregate_type. +type(X) ::= type_name(A). { X = A; } +type(X) ::= aggregate_type(A). { X = A; } -type_list ::= type array_size. /* A comma-separated list of types */ -type_list ::= type_list COMMA type array_size. +type_or_array ::= type. +type_or_array ::= type array_size. + +type_list ::= type_or_array. /* A comma-separated list of types */ +type_list ::= type_list COMMA type_or_array. type_list_or_void ::= VOID. type_list_or_void ::= type_list. -array_size ::= . -array_size ::= array_size LBRACKET opt_expr RBRACKET. +%type array_size{ZCC_Expression *} +array_size(X) ::= LBRACKET opt_expr(A) RBRACKET. +{ + if (A == NULL) + { + NEW_AST_NODE(Expression,nil); + X = nil; + } + else + { + X = A; + } +} +array_size(X) ::= array_size(A) LBRACKET opt_expr(B) RBRACKET. +{ + if (B == NULL) + { + NEW_AST_NODE(Expression,nil); + A->AppendSibling(nil); + } + else + { + A->AppendSibling(B); + } + X = A; +} declarator ::= decl_flags type_list_or_void variables_or_function. /* Multiple type names are only valid for functions. */ declarator_no_fun ::= decl_flags type variable_list. @@ -230,8 +293,39 @@ variables_or_function ::= IDENTIFIER LPAREN func_params RPAREN func_const opt_fu variables_or_function ::= variable_list SEMICOLON. variables_or_function ::= error SEMICOLON. -variable_list ::= IDENTIFIER array_size. -variable_list ::= variable_list COMMA IDENTIFIER array_size. +/*----- Variable Names -----*/ +// They get the array size, because that makes it look more like C. +// I might still change my mind and stick array sizes with the rest +// of the type like C#. + +%type variable_name{ZCC_VarName *} +%type variable_list{ZCC_VarName *} + +variable_name(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(VarName,var); + var->Name = ENamedName(A.Int); + var->bIsArray = false; + var->ArraySize = 0; + X = var; +} +variable_name(X) ::= IDENTIFIER(A) array_size(B). +{ + NEW_AST_NODE(VarName,var); + var->Name = ENamedName(A.Int); + var->bIsArray = false; + var->ArraySize = B; + X = var; +} +variable_list(X) ::= variable_name(A). +{ + X = A; +} +variable_list(X) ::= variable_list(A) COMMA variable_name(B). +{ + A->AppendSibling(B); + X = A; +} decl_flags ::= . decl_flags ::= decl_flags NATIVE. @@ -257,7 +351,7 @@ func_params ::= func_param_list. func_param_list ::= func_param. func_param_list ::= func_param COMMA func_param_list. -func_param ::= func_param_flags type IDENTIFIER array_size. +func_param ::= func_param_flags type variable_name. func_param_flags ::= . func_param_flags ::= func_param_flags IN. @@ -270,141 +364,562 @@ struct_body ::= struct_member struct_body. /* Like UnrealScript, a constant's type is implied by its value's type. */ const_def ::= CONST IDENTIFIER EQ expr SEMICOLON. -/* Expressions */ +/************ Expressions ************/ /* We use default to access a class's default instance. */ %fallback IDENTIFIER DEFAULT. -primary ::= IDENTIFIER. -primary ::= SUPER. -primary ::= constant. -primary ::= SELF. -primary ::= LPAREN expr RPAREN. -primary ::= LPAREN error RPAREN. -primary ::= primary LPAREN func_expr_list RPAREN. [DOT] // Function call -primary ::= primary LBRACKET expr RBRACKET. [DOT] // Array access -primary ::= primary DOT IDENTIFIER. // Member access -primary ::= primary ADDADD. /* postfix++ */ -primary ::= primary SUBSUB. /* postfix-- */ -primary ::= SCOPE primary. +%type expr{ZCC_Expression *} +%type primary{ZCC_Expression *} +%type unary_expr{ZCC_Expression *} +%type constant{ZCC_Expression *} -unary_expr ::= primary. -unary_expr ::= SUB unary_expr. [UNARY] -unary_expr ::= ADD unary_expr. [UNARY] -unary_expr ::= SUBSUB unary_expr. [UNARY] -unary_expr ::= ADDADD unary_expr. [UNARY] -unary_expr ::= TILDE unary_expr. [UNARY] -unary_expr ::= BANG unary_expr. [UNARY] -unary_expr ::= SIZEOF unary_expr. [UNARY] -unary_expr ::= ALIGNOF unary_expr. [UNARY] +%include { +#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr); expr->Operation = T; expr->Operand = X +#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr); expr->Operation = T; expr->Left = X; expr->Right = Y +} + +/*----- Primary Expressions -----*/ + +primary(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(ExprID, expr); + expr->Operation = PEX_ID; + expr->Identifier = ENamedName(A.Int); + X = expr; +} +primary(X) ::= SUPER. +{ + NEW_AST_NODE(Expression, expr); + expr->Operation = PEX_Super; + X = expr; +} +primary(X) ::= constant(A). +{ + X = A; +} +primary(X) ::= SELF. +{ + NEW_AST_NODE(Expression, expr); + expr->Operation = PEX_Self; + X = expr; +} +primary(X) ::= LPAREN expr(A) RPAREN. +{ + X = A; +} +primary ::= LPAREN error RPAREN. +primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function call +{ + NEW_AST_NODE(ExprFuncCall, expr); + expr->Operation = PEX_FuncCall; + expr->Function = A; + expr->Parameters = B; + X = expr; +} +primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access +{ + NEW_AST_NODE(ExprBinary, expr); + expr->Operation = PEX_ArrayAccess; + expr->Left = A; + expr->Right = B; + X = expr; +} +primary(X) ::= primary(A) DOT IDENTIFIER(B). // Member access +{ + NEW_AST_NODE(ExprMemberAccess, expr); + expr->Operation = PEX_MemberAccess; + expr->Left = A; + expr->Right = ENamedName(B.Int); + X = expr; +} +primary(X) ::= primary(A) ADDADD. /* postfix++ */ +{ + UNARY_EXPR(A,PEX_PostInc); + X = expr; +} +primary(X) ::= primary(A) SUBSUB. /* postfix-- */ +{ + UNARY_EXPR(A,PEX_PostDec); + X = expr; +} +primary(X) ::= SCOPE primary(B). +{ + BINARY_EXPR(NULL,B,PEX_Scope); + X = expr; +} + +/*----- Unary Expressions -----*/ + +unary_expr(X) ::= primary(A). +{ + X = A; +} +unary_expr(X) ::= SUB unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_Negate); + X = expr; +} +unary_expr(X) ::= ADD unary_expr(A). [UNARY] +{ + // Even though this is really a no-op, we still need to make a node for + // it so we can type check that it is being applied to something numeric. + UNARY_EXPR(A,PEX_AntiNegate); + X = expr; +} +unary_expr(X) ::= SUBSUB unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_PreDec); + X = expr; +} +unary_expr(X) ::= ADDADD unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_PreInc); + X = expr; +} +unary_expr(X) ::= TILDE unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_BitNot); + X = expr; +} +unary_expr(X) ::= BANG unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_BoolNot); + X = expr; +} +unary_expr(X) ::= SIZEOF unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_SizeOf); + X = expr; +} +unary_expr(X) ::= ALIGNOF unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_AlignOf); + X = expr; +} /* Due to parsing conflicts, C-style casting is not supported. You * must use C++ function call-style casting instead. */ -expr ::= unary_expr. -expr ::= expr ADD expr. /* a + b */ -expr ::= expr SUB expr. /* a - b */ -expr ::= expr MUL expr. /* a * b */ -expr ::= expr DIV expr. /* a / b */ -expr ::= expr MOD expr. /* a % b */ -expr ::= expr POW expr. /* a ** b */ -expr ::= expr CROSSPROD expr. /* a cross b */ -expr ::= expr DOTPROD expr. /* a dot b */ -expr ::= expr LSH expr. /* a << b */ -expr ::= expr RSH expr. /* a >> b */ -expr ::= expr DOTDOT expr. /* a .. b */ +/*----- Binary Expressions -----*/ -expr ::= expr LT expr. /* a < b */ -expr ::= expr GT expr. /* a > b */ -expr ::= expr LTEQ expr. /* a <= b */ -expr ::= expr GTEQ expr. /* a >= b */ -expr ::= expr LTGTEQ expr. /* a <>= b */ -expr ::= expr IS expr. /* a is b */ +expr(X) ::= unary_expr(A). +{ + A = X; +} +expr(X) ::= expr(A) ADD expr(B). /* a + b */ +{ + BINARY_EXPR(A,B,PEX_Add); + X = expr; +} +expr(X) ::= expr(A) SUB expr(B). /* a - b */ +{ + BINARY_EXPR(A,B,PEX_Sub); + X = expr; +} +expr(X) ::= expr(A) MUL expr(B). /* a * b */ +{ + BINARY_EXPR(A,B,PEX_Mul); + X = expr; +} +expr(X) ::= expr(A) DIV expr(B). /* a / b */ +{ + BINARY_EXPR(A,B,PEX_Div); + X = expr; +} +expr(X) ::= expr(A) MOD expr(B). /* a % b */ +{ + BINARY_EXPR(A,B,PEX_Mod); + X = expr; +} +expr(X) ::= expr(A) POW expr(B). /* a ** b */ +{ + BINARY_EXPR(A,B,PEX_Pow); + X = expr; +} +expr(X) ::= expr(A) CROSSPROD expr(B). /* a cross b */ +{ + BINARY_EXPR(A,B,PEX_CrossProduct); + X = expr; +} +expr(X) ::= expr(A) DOTPROD expr(B). /* a dot b */ +{ + BINARY_EXPR(A,B,PEX_DotProduct); + X = expr; +} +expr(X) ::= expr(A) LSH expr(B). /* a << b */ +{ + BINARY_EXPR(A,B,PEX_LeftShift); + X = expr; +} +expr(X) ::= expr(A) RSH expr(B). /* a >> b */ +{ + BINARY_EXPR(A,B,PEX_RightShift); + X = expr; +} +expr(X) ::= expr(A) DOTDOT expr(B). /* a .. b */ +{ + BINARY_EXPR(A,B,PEX_Concat); + X = expr; +} -expr ::= expr EQEQ expr. /* a == b */ -expr ::= expr NEQ expr. /* a != b */ -expr ::= expr APPROXEQ expr. /* a ~== b */ +expr(X) ::= expr(A) LT expr(B). /* a < b */ +{ + BINARY_EXPR(A,B,PEX_LT); + X = expr; +} +expr(X) ::= expr(A) GT expr(B). /* a > b */ +{ + BINARY_EXPR(A,B,PEX_GT); + X = expr; +} +expr(X) ::= expr(A) LTEQ expr(B). /* a <= b */ +{ + BINARY_EXPR(A,B,PEX_LTEQ); + X = expr; +} +expr(X) ::= expr(A) GTEQ expr(B). /* a >= b */ +{ + BINARY_EXPR(A,B,PEX_GTEQ); + X = expr; +} +expr(X) ::= expr(A) LTGTEQ expr(B). /* a <>= b */ +{ + BINARY_EXPR(A,B,PEX_LTGTEQ); + X = expr; +} +expr(X) ::= expr(A) IS expr(B). /* a is b */ +{ + BINARY_EXPR(A,B,PEX_Is); + X = expr; +} -expr ::= expr AND expr. /* a & b */ -expr ::= expr XOR expr. /* a ^ b */ -expr ::= expr OR expr. /* a | b */ -expr ::= expr ANDAND expr. /* a && b */ -expr ::= expr OROR expr. /* a || b */ +expr(X) ::= expr(A) EQEQ expr(B). /* a == b */ +{ + BINARY_EXPR(A,B,PEX_EQEQ); + X = expr; +} +expr(X) ::= expr(A) NEQ expr(B). /* a != b */ +{ + BINARY_EXPR(A,B,PEX_NEQ); + X = expr; +} +expr(X) ::= expr(A) APPROXEQ expr(B). /* a ~== b */ +{ + BINARY_EXPR(A,B,PEX_APREQ); + X = expr; +} -expr ::= expr SCOPE expr. +expr(X) ::= expr(A) AND expr(B). /* a & b */ +{ + BINARY_EXPR(A,B,PEX_BitAnd); + X = expr; +} +expr(X) ::= expr(A) XOR expr(B). /* a ^ b */ +{ + BINARY_EXPR(A,B,PEX_BitXor); + X = expr; +} +expr(X) ::= expr(A) OR expr(B). /* a | b */ +{ + BINARY_EXPR(A,B,PEX_BitOr); + X = expr; +} +expr(X) ::= expr(A) ANDAND expr(B). /* a && b */ +{ + BINARY_EXPR(A,B,PEX_BoolAnd); + X = expr; +} +expr(X) ::= expr(A) OROR expr(B). /* a || b */ +{ + BINARY_EXPR(A,B,PEX_BoolOr); + X = expr; +} -expr ::= expr QUESTION expr COLON expr. +expr(X) ::= expr(A) SCOPE expr(B). +{ + BINARY_EXPR(A,B,PEX_Scope); + X = expr; +} -opt_expr_list ::= . -opt_expr_list ::= expr_list. +/*----- Trinary Expression -----*/ -expr_list ::= expr. -expr_list ::= expr_list COMMA expr. +expr(X) ::= expr(A) QUESTION expr(B) COLON expr(C). +{ + NEW_AST_NODE(ExprTrinary, expr); + expr->Operation = PEX_Trinary; + expr->Test = A; + expr->Left = B; + expr->Right = C; + X = expr; +} + +/************ Expression Lists ***********/ + +%type opt_expr_list{ZCC_Expression *} +%type expr_list{ZCC_Expression *} + +opt_expr_list(X) ::= . +{ + X = NULL; +} +opt_expr_list(X) ::= expr_list(A). +{ + X = A; +} + +expr_list(X) ::= expr(A). +{ + X = A; +} +expr_list(X) ::= expr_list(A) COMMA expr(B). +{ + X = A; + A->AppendSibling(B); +} + +/*----- Function argument lists -----*/ /* A function expression list can also specify a parameter's name, - * but once you do that, all remaining parameters must also be named. */ -func_expr_list ::= . -func_expr_list ::= expr_list. -func_expr_list ::= expr_list COMMA named_expr_list. -func_expr_list ::= named_expr_list. + * but once you do that, all remaining parameters must also be named. + * We let higher-level code handle this to keep this file simpler. */ +%type func_expr_list{ZCC_FuncParm *} +%type named_expr{ZCC_FuncParm *} -named_expr_list ::= named_expr. -named_expr_list ::= named_expr_list COMMA named_expr. +func_expr_list(X) ::= . +{ + X = NULL; +} +func_expr_list(X) ::= named_expr(A). +{ + X = A; +} +func_expr_list(X) ::= func_expr_list(A) COMMA named_expr(B). +{ + X = A; + A->AppendSibling(B); +} -named_expr ::= IDENTIFIER COLON expr. +named_expr(X) ::= IDENTIFIER(A) COLON expr(B). +{ + NEW_AST_NODE(FuncParm, parm); + parm->Value = B; + parm->Label = ENamedName(A.Int); + X = parm; +} +named_expr(X) ::= expr(B). +{ + NEW_AST_NODE(FuncParm, parm); + parm->Value = B; + parm->Label = NAME_None; + X = parm; +} + +/************ Constants ************/ /* Allow C-like concatenation of adjacent string constants. */ -string_constant ::= STRCONST. -string_constant ::= string_constant STRCONST. +%type string_constant{ZCC_ExprString *} -constant ::= string_constant. -constant ::= INTCONST. -constant ::= FLOATCONST. +string_constant(X) ::= STRCONST(A). +{ + NEW_AST_NODE(ExprString, strconst); + strconst->Operation = PEX_StringConst; + strconst->Value = A.String; + X = strconst; +} +string_constant(X) ::= string_constant(A) STRCONST(B). +{ + NEW_AST_NODE(ExprString, strconst); + strconst->Operation = PEX_StringConst; + strconst->Value = stat->Strings.Alloc(*(A->Value) + *(B.String)); + X = strconst; +} + +constant(X) ::= string_constant(A). +{ + X = A; +} +constant(X) ::= INTCONST(A). +{ + NEW_AST_NODE(ExprInt, intconst); + intconst->Operation = PEX_IntConst; + intconst->Value = A.Int; + X = intconst; +} +constant(X) ::= FLOATCONST(A). +{ + NEW_AST_NODE(ExprFloat, floatconst); + floatconst->Operation = PEX_FloatConst; + floatconst->Value = A.Float; + X = floatconst; +} + +/************ Statements ************/ function_body ::= compound_statement. +%type statement{ZCC_Statement *} +statement ::= SEMICOLON. statement ::= labeled_statement. statement ::= compound_statement. -statement ::= expression_statement. +statement ::= expression_statement SEMICOLON. statement ::= selection_statement. statement ::= iteration_statement. statement ::= jump_statement. -statement ::= assign_statement. -statement ::= local_var. +statement ::= assign_statement SEMICOLON. +statement ::= local_var SEMICOLON. statement ::= error SEMICOLON. -jump_statement ::= CONTINUE SEMICOLON. -jump_statement ::= BREAK SEMICOLON. -jump_statement ::= RETURN SEMICOLON. -jump_statement ::= RETURN expr_list SEMICOLON. +/*----- Jump Statements -----*/ -compound_statement ::= LBRACE RBRACE. -compound_statement ::= LBRACE statement_list RBRACE. -compound_statement ::= LBRACE error RBRACE. +%type jump_statement{ZCC_Statement *} -statement_list ::= statement. -statement_list ::= statement_list statement. +jump_statement(A) ::= CONTINUE SEMICOLON. +{ + NEW_AST_NODE(ContinueStmt, stmt); + A = stmt; +} +jump_statement(A) ::= BREAK SEMICOLON. +{ + NEW_AST_NODE(BreakStmt, stmt); + A = stmt; +} +jump_statement(A) ::= RETURN SEMICOLON. +{ + NEW_AST_NODE(ReturnStmt, stmt); + stmt->Values = NULL; + A = stmt; +} +jump_statement(A) ::= RETURN expr_list(X) SEMICOLON. +{ + NEW_AST_NODE(ReturnStmt, stmt); + stmt->Values = X; + A = stmt; +} -expression_statement ::= SEMICOLON. -expression_statement ::= expr SEMICOLON. +/*----- Compound Statements -----*/ -iteration_statement ::= while_or_until LPAREN expr RPAREN statement. -iteration_statement ::= DO statement while_or_until LPAREN expr RPAREN. -iteration_statement ::= FOR LPAREN for_init_expr SEMICOLON opt_expr SEMICOLON for_bump_expr RPAREN statement. +%type compound_statement{ZCC_CompoundStmt *} +%type statement_list{ZCC_Statement *} -while_or_until ::= WHILE. -while_or_until ::= UNTIL. +compound_statement(X) ::= LBRACE RBRACE. +{ + NEW_AST_NODE(CompoundStmt,stmt); + stmt->Content = NULL; + X = stmt; +} +compound_statement(X) ::= LBRACE statement_list(A) RBRACE. +{ + NEW_AST_NODE(CompoundStmt,stmt); + stmt->Content = A; + X = stmt; +} +compound_statement(X) ::= LBRACE error RBRACE. +{ + NEW_AST_NODE(CompoundStmt,stmt); + stmt->Content = NULL; + X = stmt; +} -for_init_expr ::= . -for_init_expr ::= expr. -for_init_expr ::= type variable_list EQ expr_list. -for_init_expr ::= assign_expr. +statement_list(X) ::= statement(A). +{ + X = A; +} +statement_list(X) ::= statement_list(A) statement(B). +{ + X = A; + A->AppendSibling(B); +} -for_bump_expr ::= . -for_bump_expr ::= expr. -for_bump_expr ::= assign_expr. +/*----- Expression Statements -----*/ + +%type expression_statement{ZCC_ExpressionStmt *} + +expression_statement(X) ::= expr(A). +{ + NEW_AST_NODE(ExpressionStmt, stmt); + stmt->Expression = A; + X = stmt; +} + +/*----- Iteration Statements -----*/ + +%type iteration_statement{ZCC_Statement *} + +// while/until (expr) statement +iteration_statement(X) ::= while_or_until(TY) LPAREN expr(EX) RPAREN statement(ST). +{ + NEW_AST_NODE(IterationStmt, iter); + if (TY.Int == ZCC_UNTIL) + { // Negate the loop condition + UNARY_EXPR(EX,PEX_BoolNot); + iter->LoopCondition = expr; + } + else + { + iter->LoopCondition = EX; + } + iter->LoopStatement = ST; + iter->LoopBumper = NULL; + iter->CheckAt = ZCC_IterationStmt::Start; + X = iter; +} +// do statement while/until (expr) +iteration_statement(X) ::= DO statement(ST) while_or_until(TY) LPAREN expr(EX) RPAREN. +{ + NEW_AST_NODE(IterationStmt, iter); + if (TY.Int == ZCC_UNTIL) + { // Negate the loop condition + UNARY_EXPR(EX,PEX_BoolNot); + iter->LoopCondition = expr; + } + else + { + iter->LoopCondition = EX; + } + iter->LoopStatement = ST; + iter->LoopBumper = NULL; + iter->CheckAt = ZCC_IterationStmt::End; + X = iter; +} +// for (init; cond; bump) statement +iteration_statement(X) ::= FOR LPAREN for_init(IN) SEMICOLON opt_expr(EX) SEMICOLON for_bump(DO) RPAREN statement(ST). +{ + NEW_AST_NODE(IterationStmt, iter); + iter->LoopCondition = EX; + iter->LoopStatement = ST; + iter->LoopBumper = DO; + iter->CheckAt = ZCC_IterationStmt::Start; + // The initialization expression appears outside the loop + IN->AppendSibling(iter); + // And the whole thing gets wrapped inside a compound statement in case the loop + // initializer defined any variables. + NEW_AST_NODE(CompoundStmt, wrap); + wrap->Content = IN; + X = wrap; +} + +while_or_until(X) ::= WHILE. +{ + X.Int = ZCC_WHILE; +} +while_or_until(X) ::= UNTIL. +{ + X.Int = ZCC_UNTIL; +} + +%type for_init{ZCC_Statement *} +for_init(X) ::= local_var(A). { X = A; } +for_init(X) ::= for_bump(A). { X = A; } + +%type for_bump{ZCC_Statement *} +for_bump(X) ::= . { X = NULL; } +for_bump(X) ::= expression_statement(A). { X = A; } +for_bump(X) ::= assign_statement(A). { X = A; } + +/*----- If Statements -----*/ /* Resolve the shift-reduce conflict here in favor of the shift. * This is the default behavior, but using precedence symbols @@ -412,19 +927,68 @@ for_bump_expr ::= assign_expr. */ %left IF. %left ELSE. -selection_statement ::= if_front. [IF] -selection_statement ::= if_front ELSE statement. [ELSE] +%type selection_statement{ZCC_Statement *} +%type if_front{ZCC_IfStmt *} -selection_statement ::= SWITCH LPAREN expr RPAREN statement. +selection_statement(X) ::= if_front(A). [IF] +{ + X = A; +} +selection_statement(X) ::= if_front(A) ELSE statement(B). [ELSE] +{ + A->FalsePath = B; + X = A; +} -if_front ::= IF LPAREN expr RPAREN statement. +if_front(X) ::= IF LPAREN expr(A) RPAREN statement(B). +{ + NEW_AST_NODE(IfStmt,stmt); + stmt->Condition = A; + stmt->TruePath = B; + stmt->FalsePath = NULL; + X = stmt; +} -labeled_statement ::= CASE expr COLON. -labeled_statement ::= DEFAULT COLON. +/*----- Switch Statements -----*/ -assign_statement ::= assign_expr SEMICOLON. [EQ] +selection_statement(X) ::= SWITCH LPAREN expr(A) RPAREN statement(B). +{ + NEW_AST_NODE(SwitchStmt,stmt); + stmt->Condition = A; + stmt->Content = B; + X = stmt; +} + +/*----- Case Label "Statements" -----*/ + +%type labeled_statement{ZCC_CaseStmt *} + +labeled_statement(X) ::= CASE expr(A) COLON. +{ + NEW_AST_NODE(CaseStmt,stmt); + stmt->Condition = A; + X = stmt; +} +labeled_statement(X) ::= DEFAULT COLON. +{ + NEW_AST_NODE(CaseStmt,stmt); + stmt->Condition = NULL; + X = stmt; +} + +/*----- Assignment Statements -----*/ + +%type assign_statement{ZCC_AssignStmt *} + +assign_statement(X) ::= expr_list(A) assign_op(OP) expr_list(B). [EQ] +{ + NEW_AST_NODE(AssignStmt,stmt); + stmt->AssignOp = OP.Int; + stmt->Dests = A; + stmt->Sources = B; + X = stmt; +} -assign_expr ::= expr_list assign_op expr_list. assign_op ::= EQ. assign_op ::= MULEQ. assign_op ::= DIVEQ. @@ -437,7 +1001,19 @@ assign_op ::= ANDEQ. assign_op ::= OREQ. assign_op ::= XOREQ. -local_var ::= type variable_list var_init SEMICOLON. +/*----- Local Variable Definition "Statements" -----*/ -var_init ::= . -var_init ::= EQ expr_list. +%type local_var{ZCC_LocalVarStmt *} + +local_var(X) ::= type(A) variable_list(B) var_init(C). +{ + NEW_AST_NODE(LocalVarStmt,vardef); + vardef->Type = A; + vardef->Vars = B; + vardef->Inits = C; + X = vardef; +} + +%type var_init{ZCC_Expression *} +var_init(X) ::= . { X = NULL; } +var_init(X) ::= EQ expr_list(A). { X = A; } diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index fc1a0b35e..eab49046a 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -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) diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h new file mode 100644 index 000000000..c1f3cc014 --- /dev/null +++ b/src/zscript/zcc_parser.h @@ -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; +}; diff --git a/zdoom.vcproj b/zdoom.vcproj index 689a1fe3d..91e381c58 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -712,6 +712,10 @@ RelativePath=".\src\md5.cpp" > + + @@ -1401,6 +1405,10 @@ RelativePath=".\src\md5.h" > + + @@ -6553,6 +6561,10 @@ RelativePath=".\src\zscript\zcc_parser.cpp" > + +